@shipfox/client-integrations 0.2.0

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.
Files changed (243) hide show
  1. package/.storybook/main.ts +1 -0
  2. package/.storybook/preview.css +4 -0
  3. package/.storybook/preview.tsx +56 -0
  4. package/.turbo/turbo-build.log +2 -0
  5. package/.turbo/turbo-type$colon$emit.log +1 -0
  6. package/.turbo/turbo-type.log +1 -0
  7. package/CHANGELOG.md +207 -0
  8. package/LICENSE +21 -0
  9. package/dist/components/connection-picker.d.ts +7 -0
  10. package/dist/components/connection-picker.d.ts.map +1 -0
  11. package/dist/components/connection-picker.js +98 -0
  12. package/dist/components/connection-picker.js.map +1 -0
  13. package/dist/components/installed-integrations-section.d.ts +14 -0
  14. package/dist/components/installed-integrations-section.d.ts.map +1 -0
  15. package/dist/components/installed-integrations-section.js +203 -0
  16. package/dist/components/installed-integrations-section.js.map +1 -0
  17. package/dist/components/integration-delete-confirm-modal.d.ts +10 -0
  18. package/dist/components/integration-delete-confirm-modal.d.ts.map +1 -0
  19. package/dist/components/integration-delete-confirm-modal.js +61 -0
  20. package/dist/components/integration-delete-confirm-modal.js.map +1 -0
  21. package/dist/components/integration-gallery-for-workspace.d.ts +9 -0
  22. package/dist/components/integration-gallery-for-workspace.d.ts.map +1 -0
  23. package/dist/components/integration-gallery-for-workspace.js +169 -0
  24. package/dist/components/integration-gallery-for-workspace.js.map +1 -0
  25. package/dist/components/integration-gallery.d.ts +8 -0
  26. package/dist/components/integration-gallery.d.ts.map +1 -0
  27. package/dist/components/integration-gallery.js +26 -0
  28. package/dist/components/integration-gallery.js.map +1 -0
  29. package/dist/components/integration-gallery.stories.d.ts +26 -0
  30. package/dist/components/integration-gallery.stories.d.ts.map +1 -0
  31. package/dist/components/integration-gallery.stories.js +335 -0
  32. package/dist/components/integration-gallery.stories.js.map +1 -0
  33. package/dist/components/integration-usage-events.d.ts +4 -0
  34. package/dist/components/integration-usage-events.d.ts.map +1 -0
  35. package/dist/components/integration-usage-events.js +127 -0
  36. package/dist/components/integration-usage-events.js.map +1 -0
  37. package/dist/components/integration-usage-modal.d.ts +16 -0
  38. package/dist/components/integration-usage-modal.d.ts.map +1 -0
  39. package/dist/components/integration-usage-modal.js +184 -0
  40. package/dist/components/integration-usage-modal.js.map +1 -0
  41. package/dist/components/provider-grid.d.ts +14 -0
  42. package/dist/components/provider-grid.d.ts.map +1 -0
  43. package/dist/components/provider-grid.js +152 -0
  44. package/dist/components/provider-grid.js.map +1 -0
  45. package/dist/components/redirect-install-page.d.ts +19 -0
  46. package/dist/components/redirect-install-page.d.ts.map +1 -0
  47. package/dist/components/redirect-install-page.js +68 -0
  48. package/dist/components/redirect-install-page.js.map +1 -0
  49. package/dist/components/repository-picker.d.ts +15 -0
  50. package/dist/components/repository-picker.d.ts.map +1 -0
  51. package/dist/components/repository-picker.js +78 -0
  52. package/dist/components/repository-picker.js.map +1 -0
  53. package/dist/components/webhook/copyable-value.d.ts +10 -0
  54. package/dist/components/webhook/copyable-value.d.ts.map +1 -0
  55. package/dist/components/webhook/copyable-value.js +65 -0
  56. package/dist/components/webhook/copyable-value.js.map +1 -0
  57. package/dist/components/webhook/webhook-create-modal.d.ts +10 -0
  58. package/dist/components/webhook/webhook-create-modal.d.ts.map +1 -0
  59. package/dist/components/webhook/webhook-create-modal.js +233 -0
  60. package/dist/components/webhook/webhook-create-modal.js.map +1 -0
  61. package/dist/components/webhook/webhook-form-errors.d.ts +11 -0
  62. package/dist/components/webhook/webhook-form-errors.d.ts.map +1 -0
  63. package/dist/components/webhook/webhook-form-errors.js +27 -0
  64. package/dist/components/webhook/webhook-form-errors.js.map +1 -0
  65. package/dist/components/webhook/webhook-modals.stories.d.ts +25 -0
  66. package/dist/components/webhook/webhook-modals.stories.d.ts.map +1 -0
  67. package/dist/components/webhook/webhook-modals.stories.js +222 -0
  68. package/dist/components/webhook/webhook-modals.stories.js.map +1 -0
  69. package/dist/components/webhook/webhook-public-endpoint-alert.d.ts +2 -0
  70. package/dist/components/webhook/webhook-public-endpoint-alert.d.ts.map +1 -0
  71. package/dist/components/webhook/webhook-public-endpoint-alert.js +20 -0
  72. package/dist/components/webhook/webhook-public-endpoint-alert.js.map +1 -0
  73. package/dist/components/webhook/webhook-usage-details.d.ts +7 -0
  74. package/dist/components/webhook/webhook-usage-details.d.ts.map +1 -0
  75. package/dist/components/webhook/webhook-usage-details.js +49 -0
  76. package/dist/components/webhook/webhook-usage-details.js.map +1 -0
  77. package/dist/connection-status-badge.d.ts +12 -0
  78. package/dist/connection-status-badge.d.ts.map +1 -0
  79. package/dist/connection-status-badge.js +34 -0
  80. package/dist/connection-status-badge.js.map +1 -0
  81. package/dist/feature.d.ts +37 -0
  82. package/dist/feature.d.ts.map +1 -0
  83. package/dist/feature.js +48 -0
  84. package/dist/feature.js.map +1 -0
  85. package/dist/hooks/api/integrations.d.ts +265 -0
  86. package/dist/hooks/api/integrations.d.ts.map +1 -0
  87. package/dist/hooks/api/integrations.js +229 -0
  88. package/dist/hooks/api/integrations.js.map +1 -0
  89. package/dist/hooks/api/webhook-connections.d.ts +91 -0
  90. package/dist/hooks/api/webhook-connections.d.ts.map +1 -0
  91. package/dist/hooks/api/webhook-connections.js +97 -0
  92. package/dist/hooks/api/webhook-connections.js.map +1 -0
  93. package/dist/index.d.ts +17 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +18 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/integration-icon.d.ts +17 -0
  98. package/dist/integration-icon.d.ts.map +1 -0
  99. package/dist/integration-icon.js +22 -0
  100. package/dist/integration-icon.js.map +1 -0
  101. package/dist/linear-callback.d.ts +17 -0
  102. package/dist/linear-callback.d.ts.map +1 -0
  103. package/dist/linear-callback.js +113 -0
  104. package/dist/linear-callback.js.map +1 -0
  105. package/dist/pages/gitea-form-errors.d.ts +11 -0
  106. package/dist/pages/gitea-form-errors.d.ts.map +1 -0
  107. package/dist/pages/gitea-form-errors.js +35 -0
  108. package/dist/pages/gitea-form-errors.js.map +1 -0
  109. package/dist/pages/gitea-install-page.d.ts +2 -0
  110. package/dist/pages/gitea-install-page.d.ts.map +1 -0
  111. package/dist/pages/gitea-install-page.js +139 -0
  112. package/dist/pages/gitea-install-page.js.map +1 -0
  113. package/dist/pages/github-install-page.d.ts +2 -0
  114. package/dist/pages/github-install-page.d.ts.map +1 -0
  115. package/dist/pages/github-install-page.js +11 -0
  116. package/dist/pages/github-install-page.js.map +1 -0
  117. package/dist/pages/linear-callback-page.d.ts +2 -0
  118. package/dist/pages/linear-callback-page.d.ts.map +1 -0
  119. package/dist/pages/linear-callback-page.js +192 -0
  120. package/dist/pages/linear-callback-page.js.map +1 -0
  121. package/dist/pages/linear-install-page.d.ts +2 -0
  122. package/dist/pages/linear-install-page.d.ts.map +1 -0
  123. package/dist/pages/linear-install-page.js +24 -0
  124. package/dist/pages/linear-install-page.js.map +1 -0
  125. package/dist/pages/sentry-callback-page.d.ts +2 -0
  126. package/dist/pages/sentry-callback-page.d.ts.map +1 -0
  127. package/dist/pages/sentry-callback-page.js +256 -0
  128. package/dist/pages/sentry-callback-page.js.map +1 -0
  129. package/dist/pages/sentry-install-page.d.ts +2 -0
  130. package/dist/pages/sentry-install-page.d.ts.map +1 -0
  131. package/dist/pages/sentry-install-page.js +17 -0
  132. package/dist/pages/sentry-install-page.js.map +1 -0
  133. package/dist/pages/source-control-onboarding-page.d.ts +2 -0
  134. package/dist/pages/source-control-onboarding-page.d.ts.map +1 -0
  135. package/dist/pages/source-control-onboarding-page.js +37 -0
  136. package/dist/pages/source-control-onboarding-page.js.map +1 -0
  137. package/dist/provider-catalog.d.ts +15 -0
  138. package/dist/provider-catalog.d.ts.map +1 -0
  139. package/dist/provider-catalog.js +28 -0
  140. package/dist/provider-catalog.js.map +1 -0
  141. package/dist/routes/gitea.d.ts +6 -0
  142. package/dist/routes/gitea.d.ts.map +1 -0
  143. package/dist/routes/gitea.js +7 -0
  144. package/dist/routes/gitea.js.map +1 -0
  145. package/dist/routes/github-callback.d.ts +6 -0
  146. package/dist/routes/github-callback.d.ts.map +1 -0
  147. package/dist/routes/github-callback.js +129 -0
  148. package/dist/routes/github-callback.js.map +1 -0
  149. package/dist/routes/github.d.ts +6 -0
  150. package/dist/routes/github.d.ts.map +1 -0
  151. package/dist/routes/github.js +7 -0
  152. package/dist/routes/github.js.map +1 -0
  153. package/dist/routes/integrations.d.ts +6 -0
  154. package/dist/routes/integrations.d.ts.map +1 -0
  155. package/dist/routes/integrations.js +7 -0
  156. package/dist/routes/integrations.js.map +1 -0
  157. package/dist/routes/linear-callback.d.ts +6 -0
  158. package/dist/routes/linear-callback.d.ts.map +1 -0
  159. package/dist/routes/linear-callback.js +7 -0
  160. package/dist/routes/linear-callback.js.map +1 -0
  161. package/dist/routes/linear.d.ts +6 -0
  162. package/dist/routes/linear.d.ts.map +1 -0
  163. package/dist/routes/linear.js +7 -0
  164. package/dist/routes/linear.js.map +1 -0
  165. package/dist/routes/sentry-callback.d.ts +6 -0
  166. package/dist/routes/sentry-callback.d.ts.map +1 -0
  167. package/dist/routes/sentry-callback.js +7 -0
  168. package/dist/routes/sentry-callback.js.map +1 -0
  169. package/dist/routes/sentry.d.ts +6 -0
  170. package/dist/routes/sentry.d.ts.map +1 -0
  171. package/dist/routes/sentry.js +7 -0
  172. package/dist/routes/sentry.js.map +1 -0
  173. package/dist/sentry-callback.d.ts +35 -0
  174. package/dist/sentry-callback.d.ts.map +1 -0
  175. package/dist/sentry-callback.js +132 -0
  176. package/dist/sentry-callback.js.map +1 -0
  177. package/dist/tsconfig.test.tsbuildinfo +1 -0
  178. package/package.json +120 -0
  179. package/src/components/connection-picker.tsx +89 -0
  180. package/src/components/installed-integrations-section.tsx +198 -0
  181. package/src/components/integration-delete-confirm-modal.tsx +62 -0
  182. package/src/components/integration-gallery-for-workspace.tsx +193 -0
  183. package/src/components/integration-gallery.stories.tsx +302 -0
  184. package/src/components/integration-gallery.test.tsx +692 -0
  185. package/src/components/integration-gallery.tsx +49 -0
  186. package/src/components/integration-usage-events.test.ts +80 -0
  187. package/src/components/integration-usage-events.ts +116 -0
  188. package/src/components/integration-usage-modal.tsx +178 -0
  189. package/src/components/provider-grid.tsx +163 -0
  190. package/src/components/redirect-install-page.test.tsx +98 -0
  191. package/src/components/redirect-install-page.tsx +68 -0
  192. package/src/components/repository-picker.tsx +102 -0
  193. package/src/components/webhook/copyable-value.test.tsx +41 -0
  194. package/src/components/webhook/copyable-value.tsx +72 -0
  195. package/src/components/webhook/webhook-create-modal.tsx +247 -0
  196. package/src/components/webhook/webhook-form-errors.test.ts +45 -0
  197. package/src/components/webhook/webhook-form-errors.ts +32 -0
  198. package/src/components/webhook/webhook-modals.stories.tsx +225 -0
  199. package/src/components/webhook/webhook-public-endpoint-alert.tsx +15 -0
  200. package/src/components/webhook/webhook-usage-details.tsx +44 -0
  201. package/src/connection-status-badge.tsx +38 -0
  202. package/src/feature.ts +47 -0
  203. package/src/hooks/api/integrations.test.ts +105 -0
  204. package/src/hooks/api/integrations.ts +287 -0
  205. package/src/hooks/api/webhook-connections.ts +115 -0
  206. package/src/index.ts +16 -0
  207. package/src/integration-icon.react.test.tsx +40 -0
  208. package/src/integration-icon.test.ts +19 -0
  209. package/src/integration-icon.tsx +26 -0
  210. package/src/linear-callback.test.ts +227 -0
  211. package/src/linear-callback.ts +136 -0
  212. package/src/pages/gitea-form-errors.test.ts +55 -0
  213. package/src/pages/gitea-form-errors.ts +36 -0
  214. package/src/pages/gitea-install-page.tsx +108 -0
  215. package/src/pages/github-install-page.tsx +11 -0
  216. package/src/pages/linear-callback-page.test.tsx +157 -0
  217. package/src/pages/linear-callback-page.tsx +175 -0
  218. package/src/pages/linear-install-page.tsx +26 -0
  219. package/src/pages/sentry-callback-page.test.tsx +205 -0
  220. package/src/pages/sentry-callback-page.tsx +238 -0
  221. package/src/pages/sentry-install-page.tsx +17 -0
  222. package/src/pages/source-control-onboarding-page.test.tsx +46 -0
  223. package/src/pages/source-control-onboarding-page.tsx +26 -0
  224. package/src/provider-catalog.test.ts +42 -0
  225. package/src/provider-catalog.ts +49 -0
  226. package/src/routes/gitea.tsx +4 -0
  227. package/src/routes/github-callback.tsx +114 -0
  228. package/src/routes/github.tsx +4 -0
  229. package/src/routes/integrations.tsx +4 -0
  230. package/src/routes/linear-callback.tsx +4 -0
  231. package/src/routes/linear.tsx +4 -0
  232. package/src/routes/sentry-callback.tsx +4 -0
  233. package/src/routes/sentry.tsx +4 -0
  234. package/src/sentry-callback.test.ts +239 -0
  235. package/src/sentry-callback.ts +142 -0
  236. package/test/render.tsx +111 -0
  237. package/test/setup.ts +3 -0
  238. package/tsconfig.build.json +9 -0
  239. package/tsconfig.build.tsbuildinfo +1 -0
  240. package/tsconfig.json +3 -0
  241. package/tsconfig.test.json +8 -0
  242. package/vercel.json +8 -0
  243. package/vitest.config.ts +75 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copyable-value.d.ts","sourceRoot":"","sources":["../../../src/components/webhook/copyable-value.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrC,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAC,EAAE,kBAAkB,+BAwDhF"}
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@shipfox/react-ui/button';
3
+ import { useCopyToClipboard } from '@shipfox/react-ui/hooks';
4
+ import { toast } from '@shipfox/react-ui/toast';
5
+ import { Code, Text } from '@shipfox/react-ui/typography';
6
+ import { cn } from '@shipfox/react-ui/utils';
7
+ import { useEffect, useRef, useState } from 'react';
8
+ export function CopyableValue({ label, value, note, className }) {
9
+ const [copied, setCopied] = useState(false);
10
+ const timeoutRef = useRef(undefined);
11
+ const { copy } = useCopyToClipboard({
12
+ text: value,
13
+ onCopy: ()=>{
14
+ setCopied(true);
15
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
16
+ timeoutRef.current = setTimeout(()=>setCopied(false), 2000);
17
+ }
18
+ });
19
+ useEffect(()=>{
20
+ return ()=>{
21
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
22
+ };
23
+ }, []);
24
+ async function handleCopy() {
25
+ try {
26
+ await copy();
27
+ } catch {
28
+ toast.error('Could not copy.');
29
+ }
30
+ }
31
+ return /*#__PURE__*/ _jsxs("div", {
32
+ className: cn('flex w-full min-w-0 flex-col gap-8', className),
33
+ children: [
34
+ /*#__PURE__*/ _jsxs("div", {
35
+ className: "flex min-w-0 items-center gap-8",
36
+ children: [
37
+ /*#__PURE__*/ _jsx(Code, {
38
+ as: "span",
39
+ variant: "paragraph",
40
+ className: "min-w-0 flex-1 break-all rounded-4 border border-border-neutral-base bg-background-components-base px-8 py-6 text-foreground-neutral-base",
41
+ children: value
42
+ }),
43
+ /*#__PURE__*/ _jsx(Button, {
44
+ type: "button",
45
+ variant: "secondary",
46
+ size: "sm",
47
+ iconLeft: copied ? 'check' : 'copy',
48
+ "aria-label": `Copy ${label}`,
49
+ onClick: ()=>{
50
+ void handleCopy();
51
+ },
52
+ children: "Copy"
53
+ })
54
+ ]
55
+ }),
56
+ note ? /*#__PURE__*/ _jsx(Text, {
57
+ size: "sm",
58
+ className: "text-foreground-neutral-muted",
59
+ children: note
60
+ }) : null
61
+ ]
62
+ });
63
+ }
64
+
65
+ //# sourceMappingURL=copyable-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/webhook/copyable-value.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {useCopyToClipboard} from '@shipfox/react-ui/hooks';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport type {ReactNode} from 'react';\nimport {useEffect, useRef, useState} from 'react';\n\ninterface CopyableValueProps {\n label: string;\n value: string;\n note?: ReactNode;\n className?: string;\n}\n\nexport function CopyableValue({label, value, note, className}: CopyableValueProps) {\n const [copied, setCopied] = useState(false);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const {copy} = useCopyToClipboard({\n text: value,\n onCopy: () => {\n setCopied(true);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => setCopied(false), 2000);\n },\n });\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n };\n }, []);\n\n async function handleCopy() {\n try {\n await copy();\n } catch {\n toast.error('Could not copy.');\n }\n }\n\n return (\n <div className={cn('flex w-full min-w-0 flex-col gap-8', className)}>\n <div className=\"flex min-w-0 items-center gap-8\">\n <Code\n as=\"span\"\n variant=\"paragraph\"\n className=\"min-w-0 flex-1 break-all rounded-4 border border-border-neutral-base bg-background-components-base px-8 py-6 text-foreground-neutral-base\"\n >\n {value}\n </Code>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n iconLeft={copied ? 'check' : 'copy'}\n aria-label={`Copy ${label}`}\n onClick={() => {\n void handleCopy();\n }}\n >\n Copy\n </Button>\n </div>\n {note ? (\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {note}\n </Text>\n ) : null}\n </div>\n );\n}\n"],"names":["Button","useCopyToClipboard","toast","Code","Text","cn","useEffect","useRef","useState","CopyableValue","label","value","note","className","copied","setCopied","timeoutRef","undefined","copy","text","onCopy","current","clearTimeout","setTimeout","handleCopy","error","div","as","variant","type","size","iconLeft","aria-label","onClick"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,kBAAkB,QAAO,0BAA0B;AAC3D,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,IAAI,EAAEC,IAAI,QAAO,+BAA+B;AACxD,SAAQC,EAAE,QAAO,0BAA0B;AAE3C,SAAQC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAO,QAAQ;AASlD,OAAO,SAASC,cAAc,EAACC,KAAK,EAAEC,KAAK,EAAEC,IAAI,EAAEC,SAAS,EAAqB;IAC/E,MAAM,CAACC,QAAQC,UAAU,GAAGP,SAAS;IACrC,MAAMQ,aAAaT,OAAkDU;IACrE,MAAM,EAACC,IAAI,EAAC,GAAGjB,mBAAmB;QAChCkB,MAAMR;QACNS,QAAQ;YACNL,UAAU;YACV,IAAIC,WAAWK,OAAO,EAAEC,aAAaN,WAAWK,OAAO;YACvDL,WAAWK,OAAO,GAAGE,WAAW,IAAMR,UAAU,QAAQ;QAC1D;IACF;IAEAT,UAAU;QACR,OAAO;YACL,IAAIU,WAAWK,OAAO,EAAEC,aAAaN,WAAWK,OAAO;QACzD;IACF,GAAG,EAAE;IAEL,eAAeG;QACb,IAAI;YACF,MAAMN;QACR,EAAE,OAAM;YACNhB,MAAMuB,KAAK,CAAC;QACd;IACF;IAEA,qBACE,MAACC;QAAIb,WAAWR,GAAG,sCAAsCQ;;0BACvD,MAACa;gBAAIb,WAAU;;kCACb,KAACV;wBACCwB,IAAG;wBACHC,SAAQ;wBACRf,WAAU;kCAETF;;kCAEH,KAACX;wBACC6B,MAAK;wBACLD,SAAQ;wBACRE,MAAK;wBACLC,UAAUjB,SAAS,UAAU;wBAC7BkB,cAAY,CAAC,KAAK,EAAEtB,OAAO;wBAC3BuB,SAAS;4BACP,KAAKT;wBACP;kCACD;;;;YAIFZ,qBACC,KAACR;gBAAK0B,MAAK;gBAAKjB,WAAU;0BACvBD;iBAED;;;AAGV"}
@@ -0,0 +1,10 @@
1
+ import type { IntegrationConnectionDto } from '@shipfox/api-integration-core-dto';
2
+ interface WebhookCreateModalProps {
3
+ workspaceId: string;
4
+ open: boolean;
5
+ onOpenChange: (open: boolean) => void;
6
+ onCreated: (connection: IntegrationConnectionDto) => void;
7
+ }
8
+ export declare function WebhookCreateModal({ workspaceId, open, onOpenChange, onCreated, }: WebhookCreateModalProps): import("react").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=webhook-create-modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-create-modal.d.ts","sourceRoot":"","sources":["../../../src/components/webhook/webhook-create-modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,mCAAmC,CAAC;AA0BhF,UAAU,uBAAuB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,UAAU,EAAE,wBAAwB,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAgB,kBAAkB,CAAC,EACjC,WAAW,EACX,IAAI,EACJ,YAAY,EACZ,SAAS,GACV,EAAE,uBAAuB,+BAmKzB"}
@@ -0,0 +1,233 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createWebhookConnectionBodySchema, WEBHOOK_RESERVED_SLUGS, webhookSlugSchema } from '@shipfox/api-integration-webhook-dto';
3
+ import { displayNameFieldError } from '@shipfox/client-ui';
4
+ import { Button } from '@shipfox/react-ui/button';
5
+ import { Callout } from '@shipfox/react-ui/callout';
6
+ import { FormField, FormFieldInput, fieldError } from '@shipfox/react-ui/form-field';
7
+ import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, ModalTitle } from '@shipfox/react-ui/modal';
8
+ import { toast } from '@shipfox/react-ui/toast';
9
+ import { Code, Text } from '@shipfox/react-ui/typography';
10
+ import { useForm } from '@tanstack/react-form';
11
+ import { useEffect, useRef, useState } from 'react';
12
+ import { useCreateWebhookConnectionMutation } from '#hooks/api/webhook-connections.js';
13
+ import { webhookCreateErrorToFormError } from './webhook-form-errors.js';
14
+ export function WebhookCreateModal({ workspaceId, open, onOpenChange, onCreated }) {
15
+ const createWebhook = useCreateWebhookConnectionMutation();
16
+ const [formError, setFormError] = useState();
17
+ const [hasManualSlug, setHasManualSlug] = useState(false);
18
+ const nameInputRef = useRef(null);
19
+ const form = useForm({
20
+ defaultValues: {
21
+ name: '',
22
+ slug: ''
23
+ },
24
+ onSubmit: async ({ value })=>{
25
+ setFormError(undefined);
26
+ try {
27
+ const body = createWebhookConnectionBodySchema.parse({
28
+ workspace_id: workspaceId,
29
+ name: value.name.trim(),
30
+ slug: value.slug.trim()
31
+ });
32
+ const connection = await createWebhook.mutateAsync(body);
33
+ onCreated(toIntegrationConnection(connection));
34
+ toast.success('Webhook created.');
35
+ onOpenChange(false);
36
+ } catch (error) {
37
+ const mapped = webhookCreateErrorToFormError(error);
38
+ if (mapped.kind === 'field') {
39
+ form.setFieldMeta(mapped.field, (prev)=>({
40
+ ...prev,
41
+ errorMap: {
42
+ ...prev.errorMap,
43
+ onServer: mapped.message
44
+ }
45
+ }));
46
+ } else {
47
+ setFormError(mapped.message);
48
+ }
49
+ }
50
+ }
51
+ });
52
+ useEffect(()=>{
53
+ if (!open) {
54
+ setFormError(undefined);
55
+ setHasManualSlug(false);
56
+ form.reset();
57
+ return;
58
+ }
59
+ requestAnimationFrame(()=>nameInputRef.current?.focus());
60
+ }, [
61
+ form,
62
+ open
63
+ ]);
64
+ const handleOpenChange = (nextOpen)=>{
65
+ if (createWebhook.isPending && !nextOpen) return;
66
+ onOpenChange(nextOpen);
67
+ };
68
+ return /*#__PURE__*/ _jsx(Modal, {
69
+ open: open,
70
+ onOpenChange: handleOpenChange,
71
+ children: /*#__PURE__*/ _jsxs(ModalContent, {
72
+ "aria-describedby": undefined,
73
+ children: [
74
+ /*#__PURE__*/ _jsx(ModalTitle, {
75
+ className: "sr-only",
76
+ children: "Add webhook"
77
+ }),
78
+ /*#__PURE__*/ _jsx(ModalHeader, {
79
+ title: "Add webhook",
80
+ showClose: !createWebhook.isPending
81
+ }),
82
+ /*#__PURE__*/ _jsxs("form", {
83
+ noValidate: true,
84
+ onSubmit: (event)=>{
85
+ event.preventDefault();
86
+ event.stopPropagation();
87
+ void form.handleSubmit();
88
+ },
89
+ children: [
90
+ /*#__PURE__*/ _jsxs(ModalBody, {
91
+ className: "gap-16",
92
+ children: [
93
+ /*#__PURE__*/ _jsx(Text, {
94
+ size: "sm",
95
+ className: "text-foreground-neutral-muted",
96
+ children: "Create a named inbound webhook URL for this workspace."
97
+ }),
98
+ formError ? /*#__PURE__*/ _jsx(Callout, {
99
+ role: "alert",
100
+ type: "error",
101
+ children: formError
102
+ }) : null,
103
+ /*#__PURE__*/ _jsx(form.Field, {
104
+ name: "name",
105
+ validators: {
106
+ onBlur: ({ value })=>webhookNameFieldError(value),
107
+ onSubmit: ({ value })=>webhookNameFieldError(value)
108
+ },
109
+ children: (field)=>/*#__PURE__*/ _jsx(FormField, {
110
+ label: "Name",
111
+ id: "webhook-name",
112
+ error: fieldError(field),
113
+ className: "w-full",
114
+ children: /*#__PURE__*/ _jsx(FormFieldInput, {
115
+ ref: nameInputRef,
116
+ name: "name",
117
+ value: field.state.value,
118
+ onChange: (event)=>{
119
+ const nextName = event.target.value;
120
+ field.handleChange(nextName);
121
+ if (!hasManualSlug) {
122
+ form.setFieldValue('slug', nextName.trim() ? suggestWebhookSlug(nextName) : '');
123
+ }
124
+ },
125
+ onBlur: field.handleBlur,
126
+ placeholder: "Stripe production",
127
+ disabled: createWebhook.isPending
128
+ })
129
+ })
130
+ }),
131
+ /*#__PURE__*/ _jsx(form.Field, {
132
+ name: "slug",
133
+ validators: {
134
+ onBlur: ({ value })=>webhookSlugFieldError(value),
135
+ onSubmit: ({ value })=>webhookSlugFieldError(value)
136
+ },
137
+ children: (field)=>/*#__PURE__*/ _jsxs(FormField, {
138
+ label: "Slug",
139
+ id: "webhook-slug",
140
+ error: fieldError(field),
141
+ className: "w-full",
142
+ children: [
143
+ /*#__PURE__*/ _jsx(FormFieldInput, {
144
+ name: "slug",
145
+ value: field.state.value,
146
+ onChange: (event)=>{
147
+ const nextSlug = event.target.value;
148
+ setHasManualSlug(nextSlug.trim().length > 0);
149
+ field.handleChange(nextSlug);
150
+ if (nextSlug.trim().length === 0 && form.state.values.name.trim()) {
151
+ form.setFieldValue('slug', suggestWebhookSlug(form.state.values.name));
152
+ }
153
+ },
154
+ onBlur: field.handleBlur,
155
+ placeholder: "webhook-stripe-production",
156
+ disabled: createWebhook.isPending
157
+ }),
158
+ /*#__PURE__*/ _jsxs(Text, {
159
+ size: "sm",
160
+ className: "text-foreground-neutral-muted",
161
+ children: [
162
+ "Reference in workflows with",
163
+ ' ',
164
+ /*#__PURE__*/ _jsxs(Code, {
165
+ as: "span",
166
+ children: [
167
+ "source: ",
168
+ field.state.value || 'webhook-stripe-production'
169
+ ]
170
+ }),
171
+ "."
172
+ ]
173
+ })
174
+ ]
175
+ })
176
+ })
177
+ ]
178
+ }),
179
+ /*#__PURE__*/ _jsxs(ModalFooter, {
180
+ children: [
181
+ /*#__PURE__*/ _jsx(Button, {
182
+ type: "button",
183
+ variant: "secondary",
184
+ disabled: createWebhook.isPending,
185
+ onClick: ()=>onOpenChange(false),
186
+ children: "Cancel"
187
+ }),
188
+ /*#__PURE__*/ _jsx(Button, {
189
+ type: "submit",
190
+ isLoading: createWebhook.isPending,
191
+ children: "Create"
192
+ })
193
+ ]
194
+ })
195
+ ]
196
+ })
197
+ ]
198
+ })
199
+ });
200
+ }
201
+ function webhookNameFieldError(value) {
202
+ return displayNameFieldError(value.trim(), 'Webhook name', createWebhookConnectionBodySchema.shape.name);
203
+ }
204
+ function webhookSlugFieldError(value) {
205
+ const trimmed = value.trim();
206
+ if (trimmed.length === 0) return 'Slug is required.';
207
+ if (WEBHOOK_RESERVED_SLUGS.includes(trimmed)) {
208
+ return 'That slug is reserved.';
209
+ }
210
+ if (webhookSlugSchema.safeParse(trimmed).success) return undefined;
211
+ return 'Use lowercase letters, numbers, hyphens, or underscores.';
212
+ }
213
+ function suggestWebhookSlug(name) {
214
+ const prefix = 'webhook';
215
+ const suffix = name.toLowerCase().replaceAll(/[^a-z0-9]+/g, '-').replaceAll(/^-+|-+$/g, '').slice(0, 100 - prefix.length - 1).replaceAll(/-+$/g, '');
216
+ return suffix ? `${prefix}-${suffix}` : prefix;
217
+ }
218
+ function toIntegrationConnection(connection) {
219
+ return {
220
+ id: connection.id,
221
+ workspace_id: connection.workspace_id,
222
+ provider: 'webhook',
223
+ external_account_id: connection.slug,
224
+ slug: connection.slug,
225
+ display_name: connection.name,
226
+ lifecycle_status: connection.lifecycle_status,
227
+ capabilities: [],
228
+ created_at: connection.created_at,
229
+ updated_at: connection.updated_at
230
+ };
231
+ }
232
+
233
+ //# sourceMappingURL=webhook-create-modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/webhook/webhook-create-modal.tsx"],"sourcesContent":["import type {IntegrationConnectionDto} from '@shipfox/api-integration-core-dto';\nimport {\n createWebhookConnectionBodySchema,\n WEBHOOK_RESERVED_SLUGS,\n type WebhookConnectionDto,\n webhookSlugSchema,\n} from '@shipfox/api-integration-webhook-dto';\nimport {displayNameFieldError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {useEffect, useRef, useState} from 'react';\nimport {useCreateWebhookConnectionMutation} from '#hooks/api/webhook-connections.js';\nimport {webhookCreateErrorToFormError} from './webhook-form-errors.js';\n\ninterface WebhookCreateModalProps {\n workspaceId: string;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onCreated: (connection: IntegrationConnectionDto) => void;\n}\n\nexport function WebhookCreateModal({\n workspaceId,\n open,\n onOpenChange,\n onCreated,\n}: WebhookCreateModalProps) {\n const createWebhook = useCreateWebhookConnectionMutation();\n const [formError, setFormError] = useState<string | undefined>();\n const [hasManualSlug, setHasManualSlug] = useState(false);\n const nameInputRef = useRef<HTMLInputElement | null>(null);\n\n const form = useForm({\n defaultValues: {name: '', slug: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n const body = createWebhookConnectionBodySchema.parse({\n workspace_id: workspaceId,\n name: value.name.trim(),\n slug: value.slug.trim(),\n });\n const connection = await createWebhook.mutateAsync(body);\n onCreated(toIntegrationConnection(connection));\n toast.success('Webhook created.');\n onOpenChange(false);\n } catch (error) {\n const mapped = webhookCreateErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n useEffect(() => {\n if (!open) {\n setFormError(undefined);\n setHasManualSlug(false);\n form.reset();\n return;\n }\n requestAnimationFrame(() => nameInputRef.current?.focus());\n }, [form, open]);\n\n const handleOpenChange = (nextOpen: boolean) => {\n if (createWebhook.isPending && !nextOpen) return;\n onOpenChange(nextOpen);\n };\n\n return (\n <Modal open={open} onOpenChange={handleOpenChange}>\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">Add webhook</ModalTitle>\n <ModalHeader title=\"Add webhook\" showClose={!createWebhook.isPending} />\n <form\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n <ModalBody className=\"gap-16\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Create a named inbound webhook URL for this workspace.\n </Text>\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form.Field\n name=\"name\"\n validators={{\n onBlur: ({value}) => webhookNameFieldError(value),\n onSubmit: ({value}) => webhookNameFieldError(value),\n }}\n >\n {(field) => (\n <FormField\n label=\"Name\"\n id=\"webhook-name\"\n error={fieldError(field)}\n className=\"w-full\"\n >\n <FormFieldInput\n ref={nameInputRef}\n name=\"name\"\n value={field.state.value}\n onChange={(event) => {\n const nextName = event.target.value;\n field.handleChange(nextName);\n if (!hasManualSlug) {\n form.setFieldValue(\n 'slug',\n nextName.trim() ? suggestWebhookSlug(nextName) : '',\n );\n }\n }}\n onBlur={field.handleBlur}\n placeholder=\"Stripe production\"\n disabled={createWebhook.isPending}\n />\n </FormField>\n )}\n </form.Field>\n <form.Field\n name=\"slug\"\n validators={{\n onBlur: ({value}) => webhookSlugFieldError(value),\n onSubmit: ({value}) => webhookSlugFieldError(value),\n }}\n >\n {(field) => (\n <FormField\n label=\"Slug\"\n id=\"webhook-slug\"\n error={fieldError(field)}\n className=\"w-full\"\n >\n <FormFieldInput\n name=\"slug\"\n value={field.state.value}\n onChange={(event) => {\n const nextSlug = event.target.value;\n setHasManualSlug(nextSlug.trim().length > 0);\n field.handleChange(nextSlug);\n if (nextSlug.trim().length === 0 && form.state.values.name.trim()) {\n form.setFieldValue('slug', suggestWebhookSlug(form.state.values.name));\n }\n }}\n onBlur={field.handleBlur}\n placeholder=\"webhook-stripe-production\"\n disabled={createWebhook.isPending}\n />\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Reference in workflows with{' '}\n <Code as=\"span\">\n source: {field.state.value || 'webhook-stripe-production'}\n </Code>\n .\n </Text>\n </FormField>\n )}\n </form.Field>\n </ModalBody>\n <ModalFooter>\n <Button\n type=\"button\"\n variant=\"secondary\"\n disabled={createWebhook.isPending}\n onClick={() => onOpenChange(false)}\n >\n Cancel\n </Button>\n <Button type=\"submit\" isLoading={createWebhook.isPending}>\n Create\n </Button>\n </ModalFooter>\n </form>\n </ModalContent>\n </Modal>\n );\n}\n\nfunction webhookNameFieldError(value: string): string | undefined {\n return displayNameFieldError(\n value.trim(),\n 'Webhook name',\n createWebhookConnectionBodySchema.shape.name,\n );\n}\n\nfunction webhookSlugFieldError(value: string): string | undefined {\n const trimmed = value.trim();\n if (trimmed.length === 0) return 'Slug is required.';\n if (WEBHOOK_RESERVED_SLUGS.includes(trimmed as (typeof WEBHOOK_RESERVED_SLUGS)[number])) {\n return 'That slug is reserved.';\n }\n if (webhookSlugSchema.safeParse(trimmed).success) return undefined;\n return 'Use lowercase letters, numbers, hyphens, or underscores.';\n}\n\nfunction suggestWebhookSlug(name: string): string {\n const prefix = 'webhook';\n const suffix = name\n .toLowerCase()\n .replaceAll(/[^a-z0-9]+/g, '-')\n .replaceAll(/^-+|-+$/g, '')\n .slice(0, 100 - prefix.length - 1)\n .replaceAll(/-+$/g, '');\n\n return suffix ? `${prefix}-${suffix}` : prefix;\n}\n\nfunction toIntegrationConnection(connection: WebhookConnectionDto): IntegrationConnectionDto {\n return {\n id: connection.id,\n workspace_id: connection.workspace_id,\n provider: 'webhook',\n external_account_id: connection.slug,\n slug: connection.slug,\n display_name: connection.name,\n lifecycle_status: connection.lifecycle_status,\n capabilities: [],\n created_at: connection.created_at,\n updated_at: connection.updated_at,\n };\n}\n"],"names":["createWebhookConnectionBodySchema","WEBHOOK_RESERVED_SLUGS","webhookSlugSchema","displayNameFieldError","Button","Callout","FormField","FormFieldInput","fieldError","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","toast","Code","Text","useForm","useEffect","useRef","useState","useCreateWebhookConnectionMutation","webhookCreateErrorToFormError","WebhookCreateModal","workspaceId","open","onOpenChange","onCreated","createWebhook","formError","setFormError","hasManualSlug","setHasManualSlug","nameInputRef","form","defaultValues","name","slug","onSubmit","value","undefined","body","parse","workspace_id","trim","connection","mutateAsync","toIntegrationConnection","success","error","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","message","reset","requestAnimationFrame","current","focus","handleOpenChange","nextOpen","isPending","aria-describedby","className","title","showClose","noValidate","event","preventDefault","stopPropagation","handleSubmit","size","role","type","Field","validators","onBlur","webhookNameFieldError","label","id","ref","state","onChange","nextName","target","handleChange","setFieldValue","suggestWebhookSlug","handleBlur","placeholder","disabled","webhookSlugFieldError","nextSlug","length","values","as","variant","onClick","isLoading","shape","trimmed","includes","safeParse","prefix","suffix","toLowerCase","replaceAll","slice","provider","external_account_id","display_name","lifecycle_status","capabilities","created_at","updated_at"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export type WebhookCreateField = 'slug';
2
+ export type WebhookCreateFormErrorMapping = {
3
+ kind: 'field';
4
+ field: WebhookCreateField;
5
+ message: string;
6
+ } | {
7
+ kind: 'form';
8
+ message: string;
9
+ };
10
+ export declare function webhookCreateErrorToFormError(error: unknown): WebhookCreateFormErrorMapping;
11
+ //# sourceMappingURL=webhook-form-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-form-errors.d.ts","sourceRoot":"","sources":["../../../src/components/webhook/webhook-form-errors.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAExC,MAAM,MAAM,6BAA6B,GACrC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GAC3D;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC;AAEpC,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,6BAA6B,CAY3F"}
@@ -0,0 +1,27 @@
1
+ import { ApiError } from '@shipfox/client-api';
2
+ export function webhookCreateErrorToFormError(error) {
3
+ const code = error instanceof ApiError ? error.code : undefined;
4
+ if (code === 'slug-already-exists') {
5
+ return {
6
+ kind: 'field',
7
+ field: 'slug',
8
+ message: 'A webhook with this slug already exists.'
9
+ };
10
+ }
11
+ return {
12
+ kind: 'form',
13
+ message: webhookCreateErrorMessage(error)
14
+ };
15
+ }
16
+ function webhookCreateErrorMessage(error) {
17
+ if (error instanceof ApiError) {
18
+ if (error.code === 'network-error') {
19
+ return "We couldn't reach the server. Check your connection and try again.";
20
+ }
21
+ return error.message;
22
+ }
23
+ if (error instanceof Error) return error.message;
24
+ return 'Something went wrong. Try again.';
25
+ }
26
+
27
+ //# sourceMappingURL=webhook-form-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/webhook/webhook-form-errors.ts"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\n\nexport type WebhookCreateField = 'slug';\n\nexport type WebhookCreateFormErrorMapping =\n | {kind: 'field'; field: WebhookCreateField; message: string}\n | {kind: 'form'; message: string};\n\nexport function webhookCreateErrorToFormError(error: unknown): WebhookCreateFormErrorMapping {\n const code = error instanceof ApiError ? error.code : undefined;\n\n if (code === 'slug-already-exists') {\n return {\n kind: 'field',\n field: 'slug',\n message: 'A webhook with this slug already exists.',\n };\n }\n\n return {kind: 'form', message: webhookCreateErrorMessage(error)};\n}\n\nfunction webhookCreateErrorMessage(error: unknown): string {\n if (error instanceof ApiError) {\n if (error.code === 'network-error') {\n return \"We couldn't reach the server. Check your connection and try again.\";\n }\n return error.message;\n }\n if (error instanceof Error) return error.message;\n return 'Something went wrong. Try again.';\n}\n"],"names":["ApiError","webhookCreateErrorToFormError","error","code","undefined","kind","field","message","webhookCreateErrorMessage","Error"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,sBAAsB;AAQ7C,OAAO,SAASC,8BAA8BC,KAAc;IAC1D,MAAMC,OAAOD,iBAAiBF,WAAWE,MAAMC,IAAI,GAAGC;IAEtD,IAAID,SAAS,uBAAuB;QAClC,OAAO;YACLE,MAAM;YACNC,OAAO;YACPC,SAAS;QACX;IACF;IAEA,OAAO;QAACF,MAAM;QAAQE,SAASC,0BAA0BN;IAAM;AACjE;AAEA,SAASM,0BAA0BN,KAAc;IAC/C,IAAIA,iBAAiBF,UAAU;QAC7B,IAAIE,MAAMC,IAAI,KAAK,iBAAiB;YAClC,OAAO;QACT;QACA,OAAOD,MAAMK,OAAO;IACtB;IACA,IAAIL,iBAAiBO,OAAO,OAAOP,MAAMK,OAAO;IAChD,OAAO;AACT"}
@@ -0,0 +1,25 @@
1
+ import type { StoryObj } from '@storybook/react';
2
+ type Scenario = 'create-form' | 'create-success' | 'usage-active' | 'usage-disabled' | 'delete-confirm' | 'copyable-value';
3
+ interface WebhookModalStoryProps {
4
+ scenario: Scenario;
5
+ }
6
+ declare function WebhookModalStory({ scenario }: WebhookModalStoryProps): import("react").JSX.Element;
7
+ declare const meta: {
8
+ title: string;
9
+ component: typeof WebhookModalStory;
10
+ parameters: {
11
+ layout: string;
12
+ };
13
+ args: {
14
+ scenario: "create-form";
15
+ };
16
+ };
17
+ export default meta;
18
+ type Story = StoryObj<typeof meta>;
19
+ export declare const Playground: Story;
20
+ export declare const CreateSuccess: Story;
21
+ export declare const UsageActive: Story;
22
+ export declare const UsageDisabled: Story;
23
+ export declare const DeleteConfirm: Story;
24
+ export declare const CopyableValueState: Story;
25
+ //# sourceMappingURL=webhook-modals.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-modals.stories.d.ts","sourceRoot":"","sources":["../../../src/components/webhook/webhook-modals.stories.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAO,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAqBrD,KAAK,QAAQ,GACT,aAAa,GACb,gBAAgB,GAChB,cAAc,GACd,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,CAAC;AAErB,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAoCD,iBAAS,iBAAiB,CAAC,EAAC,QAAQ,EAAC,EAAE,sBAAsB,+BAoB5D;AAED,QAAA,MAAM,IAAI;;;;;;;;;CAKgC,CAAC;AAE3C,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,UAAU,EAAE,KAAU,CAAC;AAEpC,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAEhC,CAAC"}