@kurly-growth/growthman 0.1.2 → 0.1.5

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 (218) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +6 -6
  3. package/.next/fallback-build-manifest.json +2 -2
  4. package/.next/next-minimal-server.js.nft.json +1 -1
  5. package/.next/next-server.js.nft.json +1 -1
  6. package/.next/server/app/_global-error/page/build-manifest.json +4 -4
  7. package/.next/server/app/_global-error/page.js +8 -8
  8. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  9. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  10. package/.next/server/app/_global-error.html +2 -2
  11. package/.next/server/app/_global-error.rsc +8 -8
  12. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  13. package/.next/server/app/_global-error.segments/_full.segment.rsc +8 -8
  14. package/.next/server/app/_global-error.segments/_head.segment.rsc +4 -4
  15. package/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  16. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  17. package/.next/server/app/_not-found/page/build-manifest.json +4 -4
  18. package/.next/server/app/_not-found/page.js +10 -10
  19. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  20. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  21. package/.next/server/app/_not-found.html +1 -1
  22. package/.next/server/app/_not-found.rsc +10 -10
  23. package/.next/server/app/_not-found.segments/_full.segment.rsc +10 -10
  24. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  25. package/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
  26. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  27. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  28. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  29. package/.next/server/app/api/endpoints/[id]/route.js +5 -4
  30. package/.next/server/app/api/endpoints/[id]/route.js.nft.json +1 -1
  31. package/.next/server/app/api/endpoints/bulk/route.js +5 -4
  32. package/.next/server/app/api/endpoints/bulk/route.js.nft.json +1 -1
  33. package/.next/server/app/api/endpoints/import/route.js +5 -4
  34. package/.next/server/app/api/endpoints/import/route.js.nft.json +1 -1
  35. package/.next/server/app/api/endpoints/route.js +5 -4
  36. package/.next/server/app/api/endpoints/route.js.nft.json +1 -1
  37. package/.next/server/app/api/endpoints/sync/route.js +5 -4
  38. package/.next/server/app/api/endpoints/sync/route.js.nft.json +1 -1
  39. package/.next/server/app/api/mock/[...slug]/route.js +6 -5
  40. package/.next/server/app/api/mock/[...slug]/route.js.nft.json +1 -1
  41. package/.next/server/app/favicon.ico/route.js +4 -4
  42. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  43. package/.next/server/app/index.html +1 -1
  44. package/.next/server/app/index.rsc +12 -12
  45. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  46. package/.next/server/app/index.segments/_full.segment.rsc +12 -12
  47. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  48. package/.next/server/app/index.segments/_index.segment.rsc +5 -5
  49. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  50. package/.next/server/app/page/build-manifest.json +4 -4
  51. package/.next/server/app/page/react-loadable-manifest.json +3 -3
  52. package/.next/server/app/page.js +12 -12
  53. package/.next/server/app/page.js.nft.json +1 -1
  54. package/.next/server/app/page_client-reference-manifest.js +1 -1
  55. package/.next/server/chunks/8e02f__pnpm_34c6253f._.js +3 -0
  56. package/.next/server/chunks/8e02f__pnpm_34c6253f._.js.map +1 -0
  57. package/.next/server/chunks/{8e02f_next_dist_esm_build_templates_app-route_2d5d7dcf.js → 9ca2c_next_dist_esm_build_templates_app-route_84087e8c.js} +2 -2
  58. package/.next/server/chunks/9ca2c_next_dist_esm_build_templates_app-route_84087e8c.js.map +1 -0
  59. package/.next/server/chunks/{[root-of-the-server]__094b2f2b._.js → [externals]__cf2ccb51._.js} +2 -2
  60. package/.next/server/chunks/[externals]__cf2ccb51._.js.map +1 -0
  61. package/.next/server/chunks/[root-of-the-server]__41261df4._.js +3 -0
  62. package/.next/server/chunks/[root-of-the-server]__41261df4._.js.map +1 -0
  63. package/.next/server/chunks/[root-of-the-server]__76e3e5c5._.js +3 -0
  64. package/.next/server/chunks/[root-of-the-server]__76e3e5c5._.js.map +1 -0
  65. package/.next/server/chunks/[root-of-the-server]__9f34b8fa._.js +129 -0
  66. package/.next/server/chunks/[root-of-the-server]__9f34b8fa._.js.map +1 -0
  67. package/.next/server/chunks/[root-of-the-server]__a757185b._.js +3 -0
  68. package/.next/server/chunks/[root-of-the-server]__a757185b._.js.map +1 -0
  69. package/.next/server/chunks/[root-of-the-server]__e59e1188._.js +3 -0
  70. package/.next/server/chunks/[root-of-the-server]__e59e1188._.js.map +1 -0
  71. package/.next/server/chunks/[root-of-the-server]__e9fe7c9a._.js +21 -0
  72. package/.next/server/chunks/[root-of-the-server]__e9fe7c9a._.js.map +1 -0
  73. package/.next/server/chunks/[root-of-the-server]__eff896e6._.js +3 -0
  74. package/.next/server/chunks/[root-of-the-server]__eff896e6._.js.map +1 -0
  75. package/.next/server/chunks/ssr/{Desktop_Project_Web_growth-mock-server_4d3bfee7._.js → 9ca2c_next_dist_3cd898b4._.js} +3 -3
  76. package/.next/server/chunks/ssr/9ca2c_next_dist_3cd898b4._.js.map +1 -0
  77. package/.next/server/chunks/ssr/{8e02f_next_dist_client_components_builtin_forbidden_8e6242aa.js → 9ca2c_next_dist_client_components_builtin_forbidden_f49335c3.js} +2 -2
  78. package/.next/server/chunks/ssr/9ca2c_next_dist_client_components_builtin_forbidden_f49335c3.js.map +1 -0
  79. package/.next/server/chunks/ssr/9ca2c_next_dist_client_components_builtin_global-error_f88aa19b.js +3 -0
  80. package/.next/server/chunks/ssr/9ca2c_next_dist_client_components_builtin_global-error_f88aa19b.js.map +1 -0
  81. package/.next/server/chunks/ssr/{8e02f_next_dist_client_components_builtin_unauthorized_d6f465ad.js → 9ca2c_next_dist_client_components_builtin_unauthorized_e72efa43.js} +2 -2
  82. package/.next/server/chunks/ssr/9ca2c_next_dist_client_components_builtin_unauthorized_e72efa43.js.map +1 -0
  83. package/.next/server/chunks/ssr/{8e02f_next_dist_client_components_b780ac2a._.js → 9ca2c_next_dist_client_components_fcf027b5._.js} +2 -2
  84. package/.next/server/chunks/ssr/9ca2c_next_dist_client_components_fcf027b5._.js.map +1 -0
  85. package/.next/server/chunks/ssr/9ca2c_next_dist_d1e0d146._.js +3 -0
  86. package/.next/server/chunks/ssr/9ca2c_next_dist_d1e0d146._.js.map +1 -0
  87. package/.next/server/chunks/ssr/9ca2c_next_dist_dedb0e75._.js +6 -0
  88. package/.next/server/chunks/ssr/9ca2c_next_dist_dedb0e75._.js.map +1 -0
  89. package/.next/server/chunks/ssr/{8e02f_next_dist_a79dfbb1._.js → 9ca2c_next_dist_esm_build_templates_app-page_535865d4.js} +3 -3
  90. package/.next/server/chunks/ssr/9ca2c_next_dist_esm_build_templates_app-page_535865d4.js.map +1 -0
  91. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_99247fbd._.js +3 -0
  92. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_99247fbd._.js.map +1 -0
  93. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_c7522028._.js +7 -0
  94. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_c7522028._.js.map +1 -0
  95. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_d48712e4._.js +4 -0
  96. package/.next/server/chunks/ssr/{8e02f_next_dist_a79dfbb1._.js.map → Desktop_Project_Web_growth-mock-server_d48712e4._.js.map} +1 -1
  97. package/.next/server/chunks/ssr/{[root-of-the-server]__caa92361._.js → [root-of-the-server]__17853f53._.js} +2 -2
  98. package/.next/server/chunks/ssr/[root-of-the-server]__18a26c10._.js +3 -0
  99. package/.next/server/chunks/ssr/[root-of-the-server]__18a26c10._.js.map +1 -0
  100. package/.next/server/chunks/ssr/{[root-of-the-server]__c9e25af2._.js → [root-of-the-server]__307548a6._.js} +2 -2
  101. package/.next/server/chunks/ssr/[root-of-the-server]__307548a6._.js.map +1 -0
  102. package/.next/server/chunks/ssr/[root-of-the-server]__4390a85d._.js +10 -0
  103. package/.next/server/chunks/ssr/[root-of-the-server]__4390a85d._.js.map +1 -0
  104. package/.next/server/chunks/ssr/{[root-of-the-server]__0715ef20._.js → [root-of-the-server]__6a5dc11f._.js} +2 -2
  105. package/.next/server/chunks/ssr/[root-of-the-server]__6a5dc11f._.js.map +1 -0
  106. package/.next/server/chunks/ssr/{[root-of-the-server]__e5032d8c._.js → [root-of-the-server]__92f5730f._.js} +2 -2
  107. package/.next/server/chunks/ssr/[root-of-the-server]__92f5730f._.js.map +1 -0
  108. package/.next/server/chunks/ssr/[root-of-the-server]__c6e8de01._.js +1 -1
  109. package/.next/server/chunks/ssr/[root-of-the-server]__d2eb7012._.js +3 -0
  110. package/.next/server/chunks/ssr/[root-of-the-server]__d2eb7012._.js.map +1 -0
  111. package/.next/server/chunks/ssr/{[root-of-the-server]__88eba3a3._.js → [root-of-the-server]__e3541a66._.js} +2 -2
  112. package/.next/server/chunks/ssr/[root-of-the-server]__e3541a66._.js.map +1 -0
  113. package/.next/server/chunks/ssr/{[root-of-the-server]__6f5c427b._.js → [root-of-the-server]__e5e3a413._.js} +2 -2
  114. package/.next/server/chunks/ssr/[root-of-the-server]__e5e3a413._.js.map +1 -0
  115. package/.next/server/chunks/ssr/[root-of-the-server]__fb4cb1db._.js +3 -0
  116. package/.next/server/chunks/ssr/[root-of-the-server]__fb4cb1db._.js.map +1 -0
  117. package/.next/server/chunks/ssr/b9a5c_lucide-react_dist_esm_createLucideIcon_3a4054f7.js +3 -0
  118. package/.next/server/chunks/ssr/b9a5c_lucide-react_dist_esm_createLucideIcon_3a4054f7.js.map +1 -0
  119. package/.next/server/middleware-build-manifest.js +4 -4
  120. package/.next/server/pages/404.html +1 -1
  121. package/.next/server/pages/500.html +2 -2
  122. package/.next/static/chunks/010e555b4a1dcd52.js +5 -0
  123. package/.next/static/chunks/0275b0ee12e7ce52.js +1 -0
  124. package/.next/static/chunks/33ea23f1243e96f0.js +1 -0
  125. package/.next/static/chunks/525197a7544b0e96.js +1 -0
  126. package/.next/static/chunks/560974ba92e6363e.js +5 -0
  127. package/.next/static/chunks/{31523f3a41fdf0b5.js → 6b128c466fac1211.js} +1 -1
  128. package/.next/static/chunks/8d6c35afc42e5d8e.js +1 -0
  129. package/.next/static/chunks/9fff2b37cf885aa6.js +1 -0
  130. package/.next/static/chunks/a6dad97d9634a72d.js.map +1 -1
  131. package/.next/static/chunks/bb9110e6d0dd8068.css +3 -0
  132. package/.next/static/chunks/{turbopack-7ea3b444f61e390f.js → turbopack-68dbd89b378e971c.js} +2 -2
  133. package/.next/trace +1 -1
  134. package/.next/trace-build +1 -1
  135. package/.next/types/validator.ts +124 -0
  136. package/README.md +32 -1
  137. package/package.json +13 -2
  138. package/prisma/schema.prisma +1 -0
  139. package/.claude/settings.local.json +0 -10
  140. package/.next/server/chunks/8e02f_529f6098._.js +0 -3
  141. package/.next/server/chunks/8e02f_529f6098._.js.map +0 -1
  142. package/.next/server/chunks/8e02f_next_dist_esm_build_templates_app-route_2d5d7dcf.js.map +0 -1
  143. package/.next/server/chunks/[root-of-the-server]__094b2f2b._.js.map +0 -1
  144. package/.next/server/chunks/[root-of-the-server]__0ecd8530._.js +0 -3
  145. package/.next/server/chunks/[root-of-the-server]__0ecd8530._.js.map +0 -1
  146. package/.next/server/chunks/[root-of-the-server]__5b9c1ed8._.js +0 -3
  147. package/.next/server/chunks/[root-of-the-server]__5b9c1ed8._.js.map +0 -1
  148. package/.next/server/chunks/[root-of-the-server]__5d7c02da._.js +0 -3
  149. package/.next/server/chunks/[root-of-the-server]__5d7c02da._.js.map +0 -1
  150. package/.next/server/chunks/[root-of-the-server]__88f1e82c._.js +0 -21
  151. package/.next/server/chunks/[root-of-the-server]__88f1e82c._.js.map +0 -1
  152. package/.next/server/chunks/[root-of-the-server]__a413808a._.js +0 -3
  153. package/.next/server/chunks/[root-of-the-server]__a413808a._.js.map +0 -1
  154. package/.next/server/chunks/[root-of-the-server]__fbfc7922._.js +0 -3
  155. package/.next/server/chunks/[root-of-the-server]__fbfc7922._.js.map +0 -1
  156. package/.next/server/chunks/ssr/8e02f_lucide-react_dist_esm_createLucideIcon_92babc87.js +0 -3
  157. package/.next/server/chunks/ssr/8e02f_lucide-react_dist_esm_createLucideIcon_92babc87.js.map +0 -1
  158. package/.next/server/chunks/ssr/8e02f_next_dist_5f7af8e7._.js +0 -3
  159. package/.next/server/chunks/ssr/8e02f_next_dist_5f7af8e7._.js.map +0 -1
  160. package/.next/server/chunks/ssr/8e02f_next_dist_8b7d79d3._.js +0 -6
  161. package/.next/server/chunks/ssr/8e02f_next_dist_8b7d79d3._.js.map +0 -1
  162. package/.next/server/chunks/ssr/8e02f_next_dist_client_components_b780ac2a._.js.map +0 -1
  163. package/.next/server/chunks/ssr/8e02f_next_dist_client_components_builtin_forbidden_8e6242aa.js.map +0 -1
  164. package/.next/server/chunks/ssr/8e02f_next_dist_client_components_builtin_global-error_fef7daa4.js +0 -3
  165. package/.next/server/chunks/ssr/8e02f_next_dist_client_components_builtin_global-error_fef7daa4.js.map +0 -1
  166. package/.next/server/chunks/ssr/8e02f_next_dist_client_components_builtin_unauthorized_d6f465ad.js.map +0 -1
  167. package/.next/server/chunks/ssr/8e02f_next_dist_esm_build_templates_app-page_aefc7b05.js +0 -4
  168. package/.next/server/chunks/ssr/8e02f_next_dist_esm_build_templates_app-page_aefc7b05.js.map +0 -1
  169. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_192f26a7._.js +0 -3
  170. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_192f26a7._.js.map +0 -1
  171. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_4d3bfee7._.js.map +0 -1
  172. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_e3bf5efe._.js +0 -7
  173. package/.next/server/chunks/ssr/Desktop_Project_Web_growth-mock-server_e3bf5efe._.js.map +0 -1
  174. package/.next/server/chunks/ssr/[root-of-the-server]__0715ef20._.js.map +0 -1
  175. package/.next/server/chunks/ssr/[root-of-the-server]__0c263e23._.js +0 -3
  176. package/.next/server/chunks/ssr/[root-of-the-server]__0c263e23._.js.map +0 -1
  177. package/.next/server/chunks/ssr/[root-of-the-server]__2cf79de7._.js +0 -10
  178. package/.next/server/chunks/ssr/[root-of-the-server]__2cf79de7._.js.map +0 -1
  179. package/.next/server/chunks/ssr/[root-of-the-server]__5d3307e0._.js +0 -3
  180. package/.next/server/chunks/ssr/[root-of-the-server]__5d3307e0._.js.map +0 -1
  181. package/.next/server/chunks/ssr/[root-of-the-server]__6f5c427b._.js.map +0 -1
  182. package/.next/server/chunks/ssr/[root-of-the-server]__7f083271._.js +0 -3
  183. package/.next/server/chunks/ssr/[root-of-the-server]__7f083271._.js.map +0 -1
  184. package/.next/server/chunks/ssr/[root-of-the-server]__88eba3a3._.js.map +0 -1
  185. package/.next/server/chunks/ssr/[root-of-the-server]__c9e25af2._.js.map +0 -1
  186. package/.next/server/chunks/ssr/[root-of-the-server]__e5032d8c._.js.map +0 -1
  187. package/.next/static/chunks/3a3338ff069e0977.js +0 -5
  188. package/.next/static/chunks/68c20af4dfeb36d0.js +0 -1
  189. package/.next/static/chunks/77942ffae83b12ce.js +0 -1
  190. package/.next/static/chunks/81faf4667437d774.js +0 -1
  191. package/.next/static/chunks/8c554104dfee37e0.js +0 -5
  192. package/.next/static/chunks/ab3bc4985a0e98d2.css +0 -3
  193. package/.next/static/chunks/d71bf6d63636cd19.js +0 -1
  194. package/.next/static/chunks/f32c6649a0ca2698.js +0 -1
  195. package/CLAUDE.md +0 -58
  196. package/app/favicon.ico +0 -0
  197. package/app/globals.css +0 -125
  198. package/app/layout.tsx +0 -36
  199. package/app/page.tsx +0 -184
  200. package/components/endpoint-edit-dialog.tsx +0 -181
  201. package/components/endpoint-table.tsx +0 -133
  202. package/components/openapi-upload-dialog.tsx +0 -196
  203. package/components/ui/button.tsx +0 -62
  204. package/components/ui/checkbox.tsx +0 -32
  205. package/components/ui/dialog.tsx +0 -143
  206. package/components/ui/input.tsx +0 -21
  207. package/components/ui/label.tsx +0 -24
  208. package/components/ui/sonner.tsx +0 -37
  209. package/components/ui/table.tsx +0 -116
  210. package/components/ui/textarea.tsx +0 -18
  211. package/components.json +0 -22
  212. package/next-env.d.ts +0 -6
  213. package/pnpm-workspace.yaml +0 -4
  214. package/postcss.config.mjs +0 -7
  215. /package/.next/server/chunks/ssr/{[root-of-the-server]__caa92361._.js.map → [root-of-the-server]__17853f53._.js.map} +0 -0
  216. /package/.next/static/{xP3uHv1GK0YyrTIpyEo8D → ywToWYz8OMPylsW9u-DSJ}/_buildManifest.js +0 -0
  217. /package/.next/static/{xP3uHv1GK0YyrTIpyEo8D → ywToWYz8OMPylsW9u-DSJ}/_clientMiddlewareManifest.json +0 -0
  218. /package/.next/static/{xP3uHv1GK0YyrTIpyEo8D → ywToWYz8OMPylsW9u-DSJ}/_ssgManifest.js +0 -0
@@ -1,133 +0,0 @@
1
- 'use client'
2
-
3
- import { MockEndpoint } from '@/types/endpoint'
4
- import {
5
- Table,
6
- TableBody,
7
- TableCell,
8
- TableHead,
9
- TableHeader,
10
- TableRow,
11
- } from '@/components/ui/table'
12
- import { Button } from '@/components/ui/button'
13
- import { Checkbox } from '@/components/ui/checkbox'
14
-
15
- interface EndpointTableProps {
16
- endpoints: MockEndpoint[]
17
- onEdit: (endpoint: MockEndpoint) => void
18
- onDelete: (id: string) => void
19
- selectedIds: Set<string>
20
- onSelectionChange: (ids: Set<string>) => void
21
- }
22
-
23
- const methodColors: Record<string, string> = {
24
- GET: 'bg-green-100 text-green-800',
25
- POST: 'bg-blue-100 text-blue-800',
26
- PUT: 'bg-yellow-100 text-yellow-800',
27
- PATCH: 'bg-orange-100 text-orange-800',
28
- DELETE: 'bg-red-100 text-red-800',
29
- }
30
-
31
- export function EndpointTable({
32
- endpoints,
33
- onEdit,
34
- onDelete,
35
- selectedIds,
36
- onSelectionChange,
37
- }: EndpointTableProps) {
38
- const allSelected = endpoints.length > 0 && endpoints.every((e) => selectedIds.has(e.id))
39
- const someSelected = endpoints.some((e) => selectedIds.has(e.id)) && !allSelected
40
-
41
- const handleSelectAll = (checked: boolean) => {
42
- if (checked) {
43
- onSelectionChange(new Set(endpoints.map((e) => e.id)))
44
- } else {
45
- onSelectionChange(new Set())
46
- }
47
- }
48
-
49
- const handleSelectOne = (id: string, checked: boolean) => {
50
- const newSet = new Set(selectedIds)
51
- if (checked) {
52
- newSet.add(id)
53
- } else {
54
- newSet.delete(id)
55
- }
56
- onSelectionChange(newSet)
57
- }
58
-
59
- return (
60
- <Table>
61
- <TableHeader>
62
- <TableRow>
63
- <TableHead className="w-[50px]">
64
- <Checkbox
65
- checked={allSelected}
66
- ref={(el) => {
67
- if (el) {
68
- (el as unknown as HTMLInputElement).indeterminate = someSelected
69
- }
70
- }}
71
- onCheckedChange={(checked) => handleSelectAll(checked === true)}
72
- aria-label="Select all"
73
- />
74
- </TableHead>
75
- <TableHead className="w-[100px]">Method</TableHead>
76
- <TableHead>Path</TableHead>
77
- <TableHead>Description</TableHead>
78
- <TableHead className="w-[150px]">Actions</TableHead>
79
- </TableRow>
80
- </TableHeader>
81
- <TableBody>
82
- {endpoints.length === 0 ? (
83
- <TableRow>
84
- <TableCell colSpan={5} className="text-center text-gray-500">
85
- No endpoints registered yet
86
- </TableCell>
87
- </TableRow>
88
- ) : (
89
- endpoints.map((endpoint) => (
90
- <TableRow key={endpoint.id}>
91
- <TableCell>
92
- <Checkbox
93
- checked={selectedIds.has(endpoint.id)}
94
- onCheckedChange={(checked) => handleSelectOne(endpoint.id, checked === true)}
95
- aria-label={`Select ${endpoint.path}`}
96
- />
97
- </TableCell>
98
- <TableCell>
99
- <span
100
- className={`px-2 py-1 rounded text-xs font-medium ${methodColors[endpoint.method] || 'bg-gray-100'}`}
101
- >
102
- {endpoint.method}
103
- </span>
104
- </TableCell>
105
- <TableCell className="font-mono text-sm">{endpoint.path}</TableCell>
106
- <TableCell className="text-gray-600">
107
- {endpoint.description || '-'}
108
- </TableCell>
109
- <TableCell>
110
- <div className="flex gap-2">
111
- <Button
112
- variant="outline"
113
- size="sm"
114
- onClick={() => onEdit(endpoint)}
115
- >
116
- Edit
117
- </Button>
118
- <Button
119
- variant="destructive"
120
- size="sm"
121
- onClick={() => onDelete(endpoint.id)}
122
- >
123
- Delete
124
- </Button>
125
- </div>
126
- </TableCell>
127
- </TableRow>
128
- ))
129
- )}
130
- </TableBody>
131
- </Table>
132
- )
133
- }
@@ -1,196 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, useRef } from 'react'
4
- import {
5
- Dialog,
6
- DialogContent,
7
- DialogHeader,
8
- DialogTitle,
9
- DialogFooter,
10
- } from '@/components/ui/dialog'
11
- import { Button } from '@/components/ui/button'
12
- import { Input } from '@/components/ui/input'
13
- import { Label } from '@/components/ui/label'
14
- import { toast } from 'sonner'
15
-
16
- interface OpenAPIUploadDialogProps {
17
- open: boolean
18
- onOpenChange: (open: boolean) => void
19
- onImportComplete: () => void
20
- }
21
-
22
- type ImportMode = 'url' | 'file'
23
-
24
- export function OpenAPIUploadDialog({
25
- open,
26
- onOpenChange,
27
- onImportComplete,
28
- }: OpenAPIUploadDialogProps) {
29
- const [mode, setMode] = useState<ImportMode>('url')
30
- const [url, setUrl] = useState('')
31
- const [file, setFile] = useState<File | null>(null)
32
- const [loading, setLoading] = useState(false)
33
- const [error, setError] = useState<string | null>(null)
34
- const fileInputRef = useRef<HTMLInputElement>(null)
35
-
36
- const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
37
- const selectedFile = e.target.files?.[0]
38
- if (selectedFile) {
39
- setFile(selectedFile)
40
- setError(null)
41
- }
42
- }
43
-
44
- const handleImport = async () => {
45
- setLoading(true)
46
- setError(null)
47
-
48
- try {
49
- let response: Response
50
-
51
- if (mode === 'url') {
52
- if (!url.trim()) {
53
- throw new Error('Please enter a URL')
54
- }
55
- response = await fetch('/api/endpoints/sync', {
56
- method: 'POST',
57
- headers: { 'Content-Type': 'application/json' },
58
- body: JSON.stringify({ url: url.trim() }),
59
- })
60
- } else {
61
- if (!file) {
62
- throw new Error('Please select a file')
63
- }
64
- const text = await file.text()
65
- const spec = JSON.parse(text)
66
- response = await fetch('/api/endpoints/import', {
67
- method: 'POST',
68
- headers: { 'Content-Type': 'application/json' },
69
- body: JSON.stringify(spec),
70
- })
71
- }
72
-
73
- const data = await response.json()
74
-
75
- if (!response.ok) {
76
- throw new Error(data.error || 'Import failed')
77
- }
78
-
79
- const succeeded = data.succeeded ?? data.created
80
- const failed = data.failed ?? 0
81
- if (failed > 0) {
82
- toast.warning(`Imported ${succeeded} endpoints (${failed} failed)`)
83
- } else {
84
- toast.success(`Successfully imported ${succeeded} endpoints`)
85
- }
86
- onImportComplete()
87
- handleClose()
88
- } catch (err) {
89
- const message = err instanceof Error ? err.message : 'Import failed'
90
- setError(message)
91
- toast.error(message)
92
- } finally {
93
- setLoading(false)
94
- }
95
- }
96
-
97
- const handleClose = () => {
98
- setUrl('')
99
- setFile(null)
100
- setError(null)
101
- onOpenChange(false)
102
- }
103
-
104
- const canImport = mode === 'url' ? url.trim().length > 0 : file !== null
105
-
106
- return (
107
- <Dialog open={open} onOpenChange={handleClose}>
108
- <DialogContent className="sm:max-w-lg">
109
- <DialogHeader>
110
- <DialogTitle>Import OpenAPI Specification</DialogTitle>
111
- </DialogHeader>
112
-
113
- <div className="py-4 space-y-4">
114
- {/* Mode Toggle */}
115
- <div className="flex gap-2">
116
- <Button
117
- type="button"
118
- variant={mode === 'url' ? 'default' : 'outline'}
119
- size="sm"
120
- onClick={() => setMode('url')}
121
- >
122
- From URL
123
- </Button>
124
- <Button
125
- type="button"
126
- variant={mode === 'file' ? 'default' : 'outline'}
127
- size="sm"
128
- onClick={() => setMode('file')}
129
- >
130
- From File
131
- </Button>
132
- </div>
133
-
134
- {/* URL Input */}
135
- {mode === 'url' && (
136
- <div className="space-y-2">
137
- <Label htmlFor="url">OpenAPI JSON URL</Label>
138
- <Input
139
- id="url"
140
- type="url"
141
- placeholder="https://api.example.com/api-docs-json"
142
- value={url}
143
- onChange={(e) => {
144
- setUrl(e.target.value)
145
- setError(null)
146
- }}
147
- />
148
- <p className="text-xs text-gray-500">
149
- Enter the URL to your OpenAPI/Swagger JSON specification
150
- </p>
151
- </div>
152
- )}
153
-
154
- {/* File Upload */}
155
- {mode === 'file' && (
156
- <div
157
- className="border-2 border-dashed rounded-lg p-8 text-center cursor-pointer hover:border-gray-400 transition-colors"
158
- onClick={() => fileInputRef.current?.click()}
159
- >
160
- <input
161
- ref={fileInputRef}
162
- type="file"
163
- accept=".json"
164
- onChange={handleFileChange}
165
- className="hidden"
166
- />
167
- {file ? (
168
- <p className="text-sm">
169
- Selected: <span className="font-medium">{file.name}</span>
170
- </p>
171
- ) : (
172
- <p className="text-gray-500">
173
- Click to select an OpenAPI JSON file
174
- </p>
175
- )}
176
- </div>
177
- )}
178
-
179
- {/* Error */}
180
- {error && (
181
- <p className="text-red-500 text-sm">{error}</p>
182
- )}
183
- </div>
184
-
185
- <DialogFooter>
186
- <Button variant="outline" onClick={handleClose}>
187
- Cancel
188
- </Button>
189
- <Button onClick={handleImport} disabled={!canImport || loading}>
190
- {loading ? 'Importing...' : 'Import'}
191
- </Button>
192
- </DialogFooter>
193
- </DialogContent>
194
- </Dialog>
195
- )
196
- }
@@ -1,62 +0,0 @@
1
- import * as React from "react"
2
- import { Slot } from "@radix-ui/react-slot"
3
- import { cva, type VariantProps } from "class-variance-authority"
4
-
5
- import { cn } from "@/lib/utils"
6
-
7
- const buttonVariants = cva(
8
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9
- {
10
- variants: {
11
- variant: {
12
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
13
- destructive:
14
- "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
15
- outline:
16
- "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
17
- secondary:
18
- "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19
- ghost:
20
- "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
21
- link: "text-primary underline-offset-4 hover:underline",
22
- },
23
- size: {
24
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
25
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
26
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
27
- icon: "size-9",
28
- "icon-sm": "size-8",
29
- "icon-lg": "size-10",
30
- },
31
- },
32
- defaultVariants: {
33
- variant: "default",
34
- size: "default",
35
- },
36
- }
37
- )
38
-
39
- function Button({
40
- className,
41
- variant = "default",
42
- size = "default",
43
- asChild = false,
44
- ...props
45
- }: React.ComponentProps<"button"> &
46
- VariantProps<typeof buttonVariants> & {
47
- asChild?: boolean
48
- }) {
49
- const Comp = asChild ? Slot : "button"
50
-
51
- return (
52
- <Comp
53
- data-slot="button"
54
- data-variant={variant}
55
- data-size={size}
56
- className={cn(buttonVariants({ variant, size, className }))}
57
- {...props}
58
- />
59
- )
60
- }
61
-
62
- export { Button, buttonVariants }
@@ -1,32 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
5
- import { CheckIcon } from "lucide-react"
6
-
7
- import { cn } from "@/lib/utils"
8
-
9
- function Checkbox({
10
- className,
11
- ...props
12
- }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
13
- return (
14
- <CheckboxPrimitive.Root
15
- data-slot="checkbox"
16
- className={cn(
17
- "peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
18
- className
19
- )}
20
- {...props}
21
- >
22
- <CheckboxPrimitive.Indicator
23
- data-slot="checkbox-indicator"
24
- className="grid place-content-center text-current transition-none"
25
- >
26
- <CheckIcon className="size-3.5" />
27
- </CheckboxPrimitive.Indicator>
28
- </CheckboxPrimitive.Root>
29
- )
30
- }
31
-
32
- export { Checkbox }
@@ -1,143 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import * as DialogPrimitive from "@radix-ui/react-dialog"
5
- import { XIcon } from "lucide-react"
6
-
7
- import { cn } from "@/lib/utils"
8
-
9
- function Dialog({
10
- ...props
11
- }: React.ComponentProps<typeof DialogPrimitive.Root>) {
12
- return <DialogPrimitive.Root data-slot="dialog" {...props} />
13
- }
14
-
15
- function DialogTrigger({
16
- ...props
17
- }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
18
- return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
19
- }
20
-
21
- function DialogPortal({
22
- ...props
23
- }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
24
- return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
25
- }
26
-
27
- function DialogClose({
28
- ...props
29
- }: React.ComponentProps<typeof DialogPrimitive.Close>) {
30
- return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
31
- }
32
-
33
- function DialogOverlay({
34
- className,
35
- ...props
36
- }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
37
- return (
38
- <DialogPrimitive.Overlay
39
- data-slot="dialog-overlay"
40
- className={cn(
41
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
42
- className
43
- )}
44
- {...props}
45
- />
46
- )
47
- }
48
-
49
- function DialogContent({
50
- className,
51
- children,
52
- showCloseButton = true,
53
- ...props
54
- }: React.ComponentProps<typeof DialogPrimitive.Content> & {
55
- showCloseButton?: boolean
56
- }) {
57
- return (
58
- <DialogPortal data-slot="dialog-portal">
59
- <DialogOverlay />
60
- <DialogPrimitive.Content
61
- data-slot="dialog-content"
62
- className={cn(
63
- "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none",
64
- className
65
- )}
66
- {...props}
67
- >
68
- {children}
69
- {showCloseButton && (
70
- <DialogPrimitive.Close
71
- data-slot="dialog-close"
72
- className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
73
- >
74
- <XIcon />
75
- <span className="sr-only">Close</span>
76
- </DialogPrimitive.Close>
77
- )}
78
- </DialogPrimitive.Content>
79
- </DialogPortal>
80
- )
81
- }
82
-
83
- function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
84
- return (
85
- <div
86
- data-slot="dialog-header"
87
- className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
88
- {...props}
89
- />
90
- )
91
- }
92
-
93
- function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
94
- return (
95
- <div
96
- data-slot="dialog-footer"
97
- className={cn(
98
- "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
99
- className
100
- )}
101
- {...props}
102
- />
103
- )
104
- }
105
-
106
- function DialogTitle({
107
- className,
108
- ...props
109
- }: React.ComponentProps<typeof DialogPrimitive.Title>) {
110
- return (
111
- <DialogPrimitive.Title
112
- data-slot="dialog-title"
113
- className={cn("text-lg leading-none font-semibold", className)}
114
- {...props}
115
- />
116
- )
117
- }
118
-
119
- function DialogDescription({
120
- className,
121
- ...props
122
- }: React.ComponentProps<typeof DialogPrimitive.Description>) {
123
- return (
124
- <DialogPrimitive.Description
125
- data-slot="dialog-description"
126
- className={cn("text-muted-foreground text-sm", className)}
127
- {...props}
128
- />
129
- )
130
- }
131
-
132
- export {
133
- Dialog,
134
- DialogClose,
135
- DialogContent,
136
- DialogDescription,
137
- DialogFooter,
138
- DialogHeader,
139
- DialogOverlay,
140
- DialogPortal,
141
- DialogTitle,
142
- DialogTrigger,
143
- }
@@ -1,21 +0,0 @@
1
- import * as React from "react"
2
-
3
- import { cn } from "@/lib/utils"
4
-
5
- function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6
- return (
7
- <input
8
- type={type}
9
- data-slot="input"
10
- className={cn(
11
- "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
12
- "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
13
- "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
14
- className
15
- )}
16
- {...props}
17
- />
18
- )
19
- }
20
-
21
- export { Input }
@@ -1,24 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import * as LabelPrimitive from "@radix-ui/react-label"
5
-
6
- import { cn } from "@/lib/utils"
7
-
8
- function Label({
9
- className,
10
- ...props
11
- }: React.ComponentProps<typeof LabelPrimitive.Root>) {
12
- return (
13
- <LabelPrimitive.Root
14
- data-slot="label"
15
- className={cn(
16
- "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
17
- className
18
- )}
19
- {...props}
20
- />
21
- )
22
- }
23
-
24
- export { Label }
@@ -1,37 +0,0 @@
1
- "use client"
2
-
3
- import {
4
- CircleCheckIcon,
5
- InfoIcon,
6
- Loader2Icon,
7
- OctagonXIcon,
8
- TriangleAlertIcon,
9
- } from "lucide-react"
10
- import { Toaster as Sonner, type ToasterProps } from "sonner"
11
-
12
- const Toaster = ({ ...props }: ToasterProps) => {
13
- return (
14
- <Sonner
15
- theme="light"
16
- className="toaster group"
17
- icons={{
18
- success: <CircleCheckIcon className="size-4" />,
19
- info: <InfoIcon className="size-4" />,
20
- warning: <TriangleAlertIcon className="size-4" />,
21
- error: <OctagonXIcon className="size-4" />,
22
- loading: <Loader2Icon className="size-4 animate-spin" />,
23
- }}
24
- style={
25
- {
26
- "--normal-bg": "var(--popover)",
27
- "--normal-text": "var(--popover-foreground)",
28
- "--normal-border": "var(--border)",
29
- "--border-radius": "var(--radius)",
30
- } as React.CSSProperties
31
- }
32
- {...props}
33
- />
34
- )
35
- }
36
-
37
- export { Toaster }