zudoku 0.25.3 → 0.26.1

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 (278) hide show
  1. package/dist/cli/dev/handler.js +2 -2
  2. package/dist/cli/dev/handler.js.map +1 -1
  3. package/dist/config/config.d.ts +1 -0
  4. package/dist/config/loader.js +1 -1
  5. package/dist/config/loader.js.map +1 -1
  6. package/dist/config/validators/common.d.ts +39 -28
  7. package/dist/config/validators/common.js +1 -0
  8. package/dist/config/validators/common.js.map +1 -1
  9. package/dist/config/validators/icon-types.d.ts +1 -1
  10. package/dist/config/validators/validate.d.ts +17 -12
  11. package/dist/lib/authentication/providers/auth0.js +1 -1
  12. package/dist/lib/authentication/providers/auth0.js.map +1 -1
  13. package/dist/lib/authentication/providers/openid.d.ts +1 -1
  14. package/dist/lib/authentication/providers/openid.js +10 -6
  15. package/dist/lib/authentication/providers/openid.js.map +1 -1
  16. package/dist/lib/components/Autocomplete.d.ts +12 -0
  17. package/dist/lib/components/Autocomplete.js +47 -0
  18. package/dist/lib/components/Autocomplete.js.map +1 -0
  19. package/dist/lib/components/Header.js +3 -3
  20. package/dist/lib/components/Header.js.map +1 -1
  21. package/dist/lib/components/index.js +2 -2
  22. package/dist/lib/components/index.js.map +1 -1
  23. package/dist/lib/components/navigation/SidebarCategory.js +1 -1
  24. package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
  25. package/dist/lib/plugins/markdown/MdxPage.js +8 -2
  26. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  27. package/dist/lib/plugins/openapi/OperationList.js +3 -0
  28. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  29. package/dist/lib/plugins/openapi/ParameterListItem.js +1 -1
  30. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  31. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.d.ts +3 -1
  32. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js +3 -2
  33. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -1
  34. package/dist/lib/plugins/openapi/RequestBodySidecarBox.d.ts +2 -1
  35. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js +2 -2
  36. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  37. package/dist/lib/plugins/openapi/Sidecar.js +9 -6
  38. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  39. package/dist/lib/plugins/openapi/SidecarBox.js +1 -1
  40. package/dist/lib/plugins/openapi/SidecarBox.js.map +1 -1
  41. package/dist/lib/plugins/openapi/SidecarExamples.d.ts +2 -1
  42. package/dist/lib/plugins/openapi/SidecarExamples.js +7 -4
  43. package/dist/lib/plugins/openapi/SidecarExamples.js.map +1 -1
  44. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.d.ts +6 -0
  45. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js +12 -0
  46. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js.map +1 -0
  47. package/dist/lib/plugins/openapi/playground/Headers.js +66 -4
  48. package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
  49. package/dist/lib/plugins/openapi/playground/Playground.d.ts +5 -1
  50. package/dist/lib/plugins/openapi/playground/Playground.js +36 -11
  51. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  52. package/dist/lib/plugins/openapi/playground/QueryParams.js +20 -30
  53. package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
  54. package/dist/lib/plugins/openapi/post-processors/removeExtensions.d.ts +2 -1
  55. package/dist/lib/plugins/openapi/post-processors/removeExtensions.js +5 -3
  56. package/dist/lib/plugins/openapi/post-processors/removeExtensions.js.map +1 -1
  57. package/dist/lib/plugins/openapi/post-processors/removeExtensions.test.js +49 -0
  58. package/dist/lib/plugins/openapi/post-processors/removeExtensions.test.js.map +1 -1
  59. package/dist/lib/plugins/openapi/post-processors/removeParameters.d.ts +10 -0
  60. package/dist/lib/plugins/openapi/post-processors/removeParameters.js +66 -0
  61. package/dist/lib/plugins/openapi/post-processors/removeParameters.js.map +1 -0
  62. package/dist/lib/plugins/openapi/post-processors/removeParameters.test.d.ts +1 -0
  63. package/dist/lib/plugins/openapi/post-processors/removeParameters.test.js +131 -0
  64. package/dist/lib/plugins/openapi/post-processors/removeParameters.test.js.map +1 -0
  65. package/dist/lib/plugins/openapi/schema/SchemaComponents.js +1 -1
  66. package/dist/lib/plugins/openapi/schema/SchemaComponents.js.map +1 -1
  67. package/dist/lib/ui/Badge.d.ts +1 -1
  68. package/dist/lib/ui/Badge.js +1 -0
  69. package/dist/lib/ui/Badge.js.map +1 -1
  70. package/dist/lib/ui/Command.d.ts +9 -1
  71. package/dist/lib/ui/Command.js +5 -1
  72. package/dist/lib/ui/Command.js.map +1 -1
  73. package/dist/lib/util/joinUrl.d.ts +1 -0
  74. package/dist/lib/util/joinUrl.js +40 -0
  75. package/dist/lib/util/joinUrl.js.map +1 -0
  76. package/dist/vite/build.js +10 -10
  77. package/dist/vite/build.js.map +1 -1
  78. package/dist/vite/config.js +4 -1
  79. package/dist/vite/config.js.map +1 -1
  80. package/dist/vite/config.test.js +5 -1
  81. package/dist/vite/config.test.js.map +1 -1
  82. package/dist/vite/dev-server.js +4 -1
  83. package/dist/vite/dev-server.js.map +1 -1
  84. package/dist/vite/plugin-api.d.ts +1 -1
  85. package/dist/vite/plugin-api.js +23 -5
  86. package/dist/vite/plugin-api.js.map +1 -1
  87. package/dist/vite/plugin-auth.js +4 -1
  88. package/dist/vite/plugin-auth.js.map +1 -1
  89. package/dist/vite/plugin-mdx.js +9 -4
  90. package/dist/vite/plugin-mdx.js.map +1 -1
  91. package/dist/vite/prerender.d.ts +2 -2
  92. package/dist/vite/prerender.js +4 -4
  93. package/dist/vite/prerender.js.map +1 -1
  94. package/dist/zuplo/enrich-with-zuplo.d.ts +5 -0
  95. package/dist/zuplo/enrich-with-zuplo.js +184 -0
  96. package/dist/zuplo/enrich-with-zuplo.js.map +1 -0
  97. package/dist/zuplo/env.d.ts +1 -0
  98. package/dist/zuplo/env.js +3 -0
  99. package/dist/zuplo/env.js.map +1 -1
  100. package/dist/zuplo/policy-types.d.ts +33 -0
  101. package/dist/zuplo/policy-types.js +8 -0
  102. package/dist/zuplo/policy-types.js.map +1 -0
  103. package/dist/zuplo/with-zuplo-processors.d.ts +3 -0
  104. package/dist/zuplo/with-zuplo-processors.js +26 -0
  105. package/dist/zuplo/with-zuplo-processors.js.map +1 -0
  106. package/dist/zuplo/with-zuplo.d.ts +1 -2
  107. package/dist/zuplo/with-zuplo.js +6 -27
  108. package/dist/zuplo/with-zuplo.js.map +1 -1
  109. package/lib/{AnchorLink-DFZZbmvr.js → AnchorLink-bObQitZv.js} +3 -3
  110. package/lib/{AnchorLink-DFZZbmvr.js.map → AnchorLink-bObQitZv.js.map} +1 -1
  111. package/lib/{AuthenticationPlugin-D7G3me8L.js → AuthenticationPlugin-C9SwOxkc.js} +4 -4
  112. package/lib/{AuthenticationPlugin-D7G3me8L.js.map → AuthenticationPlugin-C9SwOxkc.js.map} +1 -1
  113. package/lib/{CategoryHeading-CBconmtI.js → CategoryHeading-MYL1u_6K.js} +3 -3
  114. package/lib/{CategoryHeading-CBconmtI.js.map → CategoryHeading-MYL1u_6K.js.map} +1 -1
  115. package/lib/{Markdown-CZDLNOFc.js → Markdown-DFN6p0J-.js} +1041 -1041
  116. package/lib/{Markdown-CZDLNOFc.js.map → Markdown-DFN6p0J-.js.map} +1 -1
  117. package/lib/{MdxPage-DKMbBROv.js → MdxPage-D9c4z09Q.js} +61 -56
  118. package/lib/MdxPage-D9c4z09Q.js.map +1 -0
  119. package/lib/{OperationList-B8bHMKme.js → OperationList-DGJWDx1G.js} +1264 -1244
  120. package/lib/OperationList-DGJWDx1G.js.map +1 -0
  121. package/lib/{Route-DYwKZ_c_.js → Route-VdmEyOD0.js} +5 -5
  122. package/lib/{Route-DYwKZ_c_.js.map → Route-VdmEyOD0.js.map} +1 -1
  123. package/lib/{Select-B_IxRUUC.js → Select-D3O7wISy.js} +36 -36
  124. package/lib/{Select-B_IxRUUC.js.map → Select-D3O7wISy.js.map} +1 -1
  125. package/lib/{SlotletProvider-pfc9oejW.js → SlotletProvider-_3zzX_g_.js} +53 -53
  126. package/lib/{SlotletProvider-pfc9oejW.js.map → SlotletProvider-_3zzX_g_.js.map} +1 -1
  127. package/lib/{Button-DeAoTouo.js → Spinner-BlzrEEk1.js} +16 -13
  128. package/lib/Spinner-BlzrEEk1.js.map +1 -0
  129. package/lib/{SyntaxHighlight-Bz-lOJtH.js → SyntaxHighlight-CJCSPG1F.js} +297 -301
  130. package/lib/{SyntaxHighlight-Bz-lOJtH.js.map → SyntaxHighlight-CJCSPG1F.js.map} +1 -1
  131. package/lib/{ZudokuContext-hmLMUdf2.js → ZudokuContext-DeQZEp-x.js} +357 -356
  132. package/lib/ZudokuContext-DeQZEp-x.js.map +1 -0
  133. package/lib/{chunk-D52XG6IA-Dl7HLe6j.js → chunk-SYFQ2XB5-BF5IDYrB.js} +410 -412
  134. package/lib/chunk-SYFQ2XB5-BF5IDYrB.js.map +1 -0
  135. package/lib/context-rwLGh-6_.js +22 -0
  136. package/lib/{context-h_UkBLvr.js.map → context-rwLGh-6_.js.map} +1 -1
  137. package/lib/{createServer-BznDkeSA.js → createServer-BcaswoFO.js} +1274 -1286
  138. package/lib/createServer-BcaswoFO.js.map +1 -0
  139. package/lib/{hook-CHq7pFyz.js → hook-BRQEDRbn.js} +17 -17
  140. package/lib/{hook-CHq7pFyz.js.map → hook-BRQEDRbn.js.map} +1 -1
  141. package/lib/index-B7mqiOei.js +509 -0
  142. package/lib/index-B7mqiOei.js.map +1 -0
  143. package/lib/index-CXRrqOIl.js +1750 -0
  144. package/lib/index-CXRrqOIl.js.map +1 -0
  145. package/lib/index-Djenk2Hj.js +36 -0
  146. package/lib/{index-CPNSgwSb.js.map → index-Djenk2Hj.js.map} +1 -1
  147. package/lib/{index-CBXSgjaE.js → index-Dl3Yl0yb.js} +65 -69
  148. package/lib/index-Dl3Yl0yb.js.map +1 -0
  149. package/lib/{index.esm-BSV1C092.js → index.esm-9-TF9KQB.js} +52 -52
  150. package/lib/{index.esm-BSV1C092.js.map → index.esm-9-TF9KQB.js.map} +1 -1
  151. package/lib/index.esm-CrSoEshU.js +1207 -0
  152. package/lib/index.esm-CrSoEshU.js.map +1 -0
  153. package/lib/joinUrl-BTy9bvoK.js +20 -0
  154. package/lib/joinUrl-BTy9bvoK.js.map +1 -0
  155. package/lib/{jsx-runtime-Dx-03ztt.js → jsx-runtime-Bdg6XQ1m.js} +135 -135
  156. package/lib/{jsx-runtime-Dx-03ztt.js.map → jsx-runtime-Bdg6XQ1m.js.map} +1 -1
  157. package/lib/post-processors/removeExtensions.js +7 -7
  158. package/lib/post-processors/removeExtensions.js.map +1 -1
  159. package/lib/post-processors/removeParameters.js +48 -0
  160. package/lib/post-processors/removeParameters.js.map +1 -0
  161. package/lib/{prism-bash.min-DadFsM4Z.js → prism-bash.min-HHIMdNJ_.js} +4 -4
  162. package/lib/{prism-bash.min-DadFsM4Z.js.map → prism-bash.min-HHIMdNJ_.js.map} +1 -1
  163. package/lib/{prism-csharp.min-DUwvItt4.js → prism-csharp.min-bQAo2pmx.js} +33 -33
  164. package/lib/{prism-csharp.min-DUwvItt4.js.map → prism-csharp.min-bQAo2pmx.js.map} +1 -1
  165. package/lib/{prism-java.min-BtgBR4yd.js → prism-java.min-BpvsOuIa.js} +12 -12
  166. package/lib/{prism-java.min-BtgBR4yd.js.map → prism-java.min-BpvsOuIa.js.map} +1 -1
  167. package/lib/{prism-markdown.min-F3U-vPBi.js → prism-markdown.min-C0Qn0m-5.js} +30 -30
  168. package/lib/{prism-markdown.min-F3U-vPBi.js.map → prism-markdown.min-C0Qn0m-5.js.map} +1 -1
  169. package/lib/{prism-ruby.min-DeDXCp1r.js → prism-ruby.min-Dx9KO9ds.js} +16 -16
  170. package/lib/{prism-ruby.min-DeDXCp1r.js.map → prism-ruby.min-Dx9KO9ds.js.map} +1 -1
  171. package/lib/prism-typescript.min-CD7H2IYQ.js.map +1 -1
  172. package/lib/state-mM7uaXTW.js +202 -0
  173. package/lib/state-mM7uaXTW.js.map +1 -0
  174. package/lib/ui/Accordion.js +1 -1
  175. package/lib/ui/ActionButton.js +10 -11
  176. package/lib/ui/ActionButton.js.map +1 -1
  177. package/lib/ui/Alert.js +2 -2
  178. package/lib/ui/AlertDialog.js +1 -1
  179. package/lib/ui/Badge.js +3 -2
  180. package/lib/ui/Badge.js.map +1 -1
  181. package/lib/ui/Breadcrumb.js +1 -1
  182. package/lib/ui/Button.js +2 -2
  183. package/lib/ui/Callout.js +1 -1
  184. package/lib/ui/Card.js +1 -1
  185. package/lib/ui/Carousel.js +3 -3
  186. package/lib/ui/Carousel.js.map +1 -1
  187. package/lib/ui/Checkbox.js +2 -2
  188. package/lib/ui/Command.js +125 -13
  189. package/lib/ui/Command.js.map +1 -1
  190. package/lib/ui/Dialog.js +1 -1
  191. package/lib/ui/Drawer.js +520 -519
  192. package/lib/ui/Drawer.js.map +1 -1
  193. package/lib/ui/DropdownMenu.js +1 -1
  194. package/lib/ui/Form.js +2 -2
  195. package/lib/ui/HoverCard.js +1 -1
  196. package/lib/ui/Input.js +1 -1
  197. package/lib/ui/Label.js +2 -2
  198. package/lib/ui/Pagination.js +7 -7
  199. package/lib/ui/Popover.js +1 -1
  200. package/lib/ui/Progress.js +1 -1
  201. package/lib/ui/RadioGroup.js +1 -1
  202. package/lib/ui/ScrollArea.js +1 -1
  203. package/lib/ui/Select.js +1 -1
  204. package/lib/ui/Skeleton.js +1 -1
  205. package/lib/ui/Slider.js +1 -1
  206. package/lib/ui/Switch.js +1 -1
  207. package/lib/ui/Tabs.js +1 -1
  208. package/lib/ui/Textarea.js +1 -1
  209. package/lib/ui/Toggle.js +2 -2
  210. package/lib/ui/ToggleGroup.js +1 -1
  211. package/lib/ui/Tooltip.js +1 -1
  212. package/lib/{useExposedProps-DE9lR6MF.js → useExposedProps-CetwhZpP.js} +2 -2
  213. package/lib/{useExposedProps-DE9lR6MF.js.map → useExposedProps-CetwhZpP.js.map} +1 -1
  214. package/lib/zudoku.auth-auth0.js +8 -10
  215. package/lib/zudoku.auth-auth0.js.map +1 -1
  216. package/lib/zudoku.auth-clerk.js +18 -18
  217. package/lib/zudoku.auth-openid.js +225 -221
  218. package/lib/zudoku.auth-openid.js.map +1 -1
  219. package/lib/zudoku.components.js +476 -461
  220. package/lib/zudoku.components.js.map +1 -1
  221. package/lib/zudoku.plugin-api-catalog.js +5 -5
  222. package/lib/zudoku.plugin-api-keys.js +7 -7
  223. package/lib/zudoku.plugin-custom-pages.js +3 -3
  224. package/lib/zudoku.plugin-markdown.js +2 -2
  225. package/lib/zudoku.plugin-openapi.js +5 -5
  226. package/lib/zudoku.plugin-redirect.js +1 -1
  227. package/lib/zudoku.plugin-search-inkeep.js +9 -9
  228. package/package.json +48 -48
  229. package/src/app/main.css +50 -50
  230. package/src/lib/authentication/providers/auth0.tsx +1 -4
  231. package/src/lib/authentication/providers/openid.tsx +12 -5
  232. package/src/lib/components/Autocomplete.tsx +111 -0
  233. package/src/lib/components/Header.tsx +3 -3
  234. package/src/lib/components/index.ts +2 -2
  235. package/src/lib/components/navigation/SidebarCategory.tsx +2 -2
  236. package/src/lib/plugins/markdown/MdxPage.tsx +9 -1
  237. package/src/lib/plugins/openapi/OperationList.tsx +4 -0
  238. package/src/lib/plugins/openapi/ParameterListItem.tsx +1 -5
  239. package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +5 -0
  240. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +8 -2
  241. package/src/lib/plugins/openapi/Sidecar.tsx +15 -7
  242. package/src/lib/plugins/openapi/SidecarBox.tsx +1 -1
  243. package/src/lib/plugins/openapi/SidecarExamples.tsx +14 -6
  244. package/src/lib/plugins/openapi/playground/ExamplesDropdown.tsx +51 -0
  245. package/src/lib/plugins/openapi/playground/Headers.tsx +138 -41
  246. package/src/lib/plugins/openapi/playground/Playground.tsx +156 -62
  247. package/src/lib/plugins/openapi/playground/QueryParams.tsx +89 -122
  248. package/src/lib/plugins/openapi/post-processors/removeExtensions.test.ts +58 -0
  249. package/src/lib/plugins/openapi/post-processors/removeExtensions.ts +7 -4
  250. package/src/lib/plugins/openapi/post-processors/removeParameters.test.ts +148 -0
  251. package/src/lib/plugins/openapi/post-processors/removeParameters.ts +101 -0
  252. package/src/lib/plugins/openapi/schema/SchemaComponents.tsx +1 -1
  253. package/src/lib/ui/Badge.tsx +1 -0
  254. package/src/lib/ui/Command.tsx +20 -0
  255. package/src/lib/util/joinUrl.ts +57 -0
  256. package/dist/lib/plugins/openapi/playground/EnumSelector.d.ts +0 -8
  257. package/dist/lib/plugins/openapi/playground/EnumSelector.js +0 -21
  258. package/dist/lib/plugins/openapi/playground/EnumSelector.js.map +0 -1
  259. package/lib/Button-DeAoTouo.js.map +0 -1
  260. package/lib/Command-9x_kZHr4.js +0 -611
  261. package/lib/Command-9x_kZHr4.js.map +0 -1
  262. package/lib/MdxPage-DKMbBROv.js.map +0 -1
  263. package/lib/OperationList-B8bHMKme.js.map +0 -1
  264. package/lib/Spinner-DuxJLLNE.js +0 -7
  265. package/lib/Spinner-DuxJLLNE.js.map +0 -1
  266. package/lib/ZudokuContext-hmLMUdf2.js.map +0 -1
  267. package/lib/chunk-D52XG6IA-Dl7HLe6j.js.map +0 -1
  268. package/lib/context-h_UkBLvr.js +0 -22
  269. package/lib/createServer-BznDkeSA.js.map +0 -1
  270. package/lib/index-CBXSgjaE.js.map +0 -1
  271. package/lib/index-CPNSgwSb.js +0 -36
  272. package/lib/index-sD8L1_Dl.js +0 -1292
  273. package/lib/index-sD8L1_Dl.js.map +0 -1
  274. package/lib/index.esm-BnnBRKJX.js +0 -1214
  275. package/lib/index.esm-BnnBRKJX.js.map +0 -1
  276. package/lib/state-CFQsUZUP.js +0 -202
  277. package/lib/state-CFQsUZUP.js.map +0 -1
  278. package/src/lib/plugins/openapi/playground/EnumSelector.tsx +0 -86
@@ -1,6 +1,10 @@
1
1
  import { useMutation } from "@tanstack/react-query";
2
+ import { InfoIcon } from "lucide-react";
2
3
  import { Fragment, useEffect, useRef, useTransition } from "react";
3
4
  import { FormProvider, useForm } from "react-hook-form";
5
+ import { Alert, AlertDescription, AlertTitle } from "zudoku/ui/Alert.js";
6
+ import { Label } from "zudoku/ui/Label.js";
7
+ import { RadioGroup, RadioGroupItem } from "zudoku/ui/RadioGroup.js";
4
8
  import {
5
9
  Select,
6
10
  SelectContent,
@@ -8,6 +12,7 @@ import {
8
12
  SelectTrigger,
9
13
  SelectValue,
10
14
  } from "zudoku/ui/Select.js";
15
+ import { Textarea } from "zudoku/ui/Textarea.js";
11
16
  import { useSelectedServerStore } from "../../../authentication/state.js";
12
17
  import { useApiIdentities } from "../../../components/context/ZudokuContext.js";
13
18
  import { Spinner } from "../../../components/Spinner.js";
@@ -15,8 +20,11 @@ import { Button } from "../../../ui/Button.js";
15
20
  import { Callout } from "../../../ui/Callout.js";
16
21
  import { Card, CardContent, CardHeader, CardTitle } from "../../../ui/Card.js";
17
22
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../../ui/Tabs.js";
23
+ import { cn } from "../../../util/cn.js";
18
24
  import { ColorizedParam } from "../ColorizedParam.js";
25
+ import { Content } from "../SidecarExamples.js";
19
26
  import { createUrl } from "./createUrl.js";
27
+ import ExamplesDropdown from "./ExamplesDropdown.js";
20
28
  import { Headers } from "./Headers.js";
21
29
  import { PathParams } from "./PathParams.js";
22
30
  import { QueryParams } from "./QueryParams.js";
@@ -40,6 +48,7 @@ const statusCodeMap: Record<number, string> = {
40
48
  export type Header = {
41
49
  name: string;
42
50
  defaultValue?: string;
51
+ defaultActive?: boolean;
43
52
  };
44
53
  export type QueryParam = {
45
54
  name: string;
@@ -67,6 +76,7 @@ export type PlaygroundForm = {
67
76
  headers: Array<{
68
77
  name: string;
69
78
  value: string;
79
+ active: boolean;
70
80
  }>;
71
81
  identity?: string;
72
82
  };
@@ -80,6 +90,7 @@ export type PlaygroundContentProps = {
80
90
  queryParams?: QueryParam[];
81
91
  pathParams?: PathParam[];
82
92
  defaultBody?: string;
93
+ examples?: Content;
83
94
  };
84
95
 
85
96
  export const Playground = ({
@@ -91,6 +102,7 @@ export const Playground = ({
91
102
  queryParams = [],
92
103
  pathParams = [],
93
104
  defaultBody = "",
105
+ examples,
94
106
  }: PlaygroundContentProps) => {
95
107
  const { selectedServer, setSelectedServer } = useSelectedServerStore();
96
108
  const [, startTransition] = useTransition();
@@ -98,20 +110,38 @@ export const Playground = ({
98
110
  useForm<PlaygroundForm>({
99
111
  defaultValues: {
100
112
  body: defaultBody,
101
- queryParams: queryParams.map((param) => ({
102
- name: param.name,
103
- value: param.defaultValue ?? "",
104
- active: param.defaultActive ?? false,
105
- enum: param.enum ?? [],
106
- })),
113
+ queryParams: queryParams
114
+ .map((param) => ({
115
+ name: param.name,
116
+ value: param.defaultValue ?? "",
117
+ active: param.defaultActive ?? false,
118
+ enum: param.enum ?? [],
119
+ }))
120
+ .concat([
121
+ {
122
+ name: "",
123
+ value: "",
124
+ active: false,
125
+ enum: [],
126
+ },
127
+ ]),
107
128
  pathParams: pathParams.map((param) => ({
108
129
  name: param.name,
109
130
  value: param.defaultValue ?? "",
110
131
  })),
111
- headers: headers.map((header) => ({
112
- name: header.name,
113
- value: header.defaultValue ?? "",
114
- })),
132
+ headers: headers
133
+ .map((header) => ({
134
+ name: header.name,
135
+ value: header.defaultValue ?? "",
136
+ active: header.defaultActive ?? false,
137
+ }))
138
+ .concat([
139
+ {
140
+ name: "",
141
+ value: "",
142
+ active: false,
143
+ },
144
+ ]),
115
145
  identity: NO_IDENTITY,
116
146
  },
117
147
  });
@@ -137,7 +167,7 @@ export const Playground = ({
137
167
  method: method.toUpperCase(),
138
168
  headers: Object.fromEntries(
139
169
  data.headers
140
- .filter((h) => h.name)
170
+ .filter((h) => h.name && h.active)
141
171
  .map((header) => [header.name, header.value]),
142
172
  ),
143
173
  body: data.body ? data.body : undefined,
@@ -229,6 +259,7 @@ export const Playground = ({
229
259
  });
230
260
  }}
231
261
  value={selectedServer}
262
+ defaultValue={selectedServer}
232
263
  >
233
264
  <SelectTrigger className="p-0 border-none flex-row-reverse bg-transparent text-xs gap-0.5 h-auto">
234
265
  <SelectValue />
@@ -256,7 +287,7 @@ export const Playground = ({
256
287
  <div className="flex flex-col gap-4 p-4 after:bg-muted-foreground/20 relative after:absolute after:w-px after:inset-0 after:left-auto">
257
288
  <div className="flex gap-2 items-stretch">
258
289
  <div className="flex flex-1 items-center w-full border rounded-md">
259
- <div className="border-r p-2 bg-muted rounded-l-md self-stretch font-semibold font-mono">
290
+ <div className="border-r p-2 bg-muted rounded-l-md self-stretch font-semibold font-mono flex items-center">
260
291
  {method.toUpperCase()}
261
292
  </div>
262
293
  <div className="flex items-center flex-wrap p-2 font-mono text-xs">
@@ -270,54 +301,30 @@ export const Playground = ({
270
301
  Send
271
302
  </Button>
272
303
  </div>
273
- <Tabs
274
- defaultValue={
275
- queryParams.length + pathParams.length > 0
276
- ? "parameters"
277
- : "headers"
278
- }
279
- >
304
+ <Tabs defaultValue="parameters">
280
305
  <div className="flex flex-wrap gap-1 justify-between">
281
306
  <TabsList>
282
- {queryParams.length + pathParams.length > 0 && (
283
- <TabsTrigger value="parameters">Parameters</TabsTrigger>
284
- )}
307
+ <TabsTrigger value="parameters">
308
+ Parameters
309
+ {(formState.pathParams.some((p) => p.value !== "") ||
310
+ formState.queryParams.some((p) => p.active)) && (
311
+ <div className="w-2 h-2 rounded-full bg-blue-400 ml-2" />
312
+ )}
313
+ </TabsTrigger>
285
314
  <TabsTrigger value="headers">
286
- Headers{" "}
287
- {formState.headers.length > 0 &&
288
- `(${formState.headers.length})`}
315
+ Headers
316
+ {formState.headers.filter((h) => h.active).length > 0 && (
317
+ <div className="w-2 h-2 rounded-full bg-blue-400 ml-2" />
318
+ )}
289
319
  </TabsTrigger>
290
- <TabsTrigger
291
- value="body"
292
- disabled={
293
- !["POST", "PUT", "PATCH", "DELETE"].includes(
294
- method.toUpperCase(),
295
- )
296
- }
297
- >
298
- Body
320
+ <TabsTrigger value="auth">
321
+ Auth
322
+ {formState.identity !== NO_IDENTITY && (
323
+ <div className="w-2 h-2 rounded-full bg-blue-400 ml-2" />
324
+ )}
299
325
  </TabsTrigger>
326
+ <TabsTrigger value="body">Body</TabsTrigger>
300
327
  </TabsList>
301
- <div className="flex gap-2 items-center">
302
- Auth:
303
- <Select
304
- onValueChange={(value) => setValue("identity", value)}
305
- value={formState.identity}
306
- defaultValue={formState.identity}
307
- >
308
- <SelectTrigger className="w-[180px] flex">
309
- {identities.isPending ? <Spinner /> : <SelectValue />}
310
- </SelectTrigger>
311
- <SelectContent align="center">
312
- <SelectItem value={NO_IDENTITY}>None</SelectItem>
313
- {identities.data?.map((identity) => (
314
- <SelectItem key={identity.id} value={identity.id}>
315
- {identity.label}
316
- </SelectItem>
317
- ))}
318
- </SelectContent>
319
- </Select>
320
- </div>
321
328
  </div>
322
329
  <TabsContent value="headers">
323
330
  <Headers control={control} register={register} />
@@ -329,18 +336,105 @@ export const Playground = ({
329
336
  <PathParams control={control} />
330
337
  </div>
331
338
  )}
332
- {queryParams.length > 0 && (
333
- <div className="flex flex-col gap-4 my-4">
334
- <span className="font-semibold">Query Parameters</span>
335
- <QueryParams control={control} queryParams={queryParams} />
336
- </div>
337
- )}
339
+ <div className="flex flex-col gap-4 my-4">
340
+ <span className="font-semibold">Query Parameters</span>
341
+ <QueryParams control={control} queryParams={queryParams} />
342
+ </div>
338
343
  </TabsContent>
339
344
  <TabsContent value="body">
340
- <textarea
345
+ {!["POST", "PUT", "PATCH", "DELETE"].includes(
346
+ method.toUpperCase(),
347
+ ) && (
348
+ <Alert className="mb-2">
349
+ <InfoIcon className="w-4 h-4" />
350
+ <AlertTitle>Body</AlertTitle>
351
+ <AlertDescription>
352
+ Body is only supported for POST, PUT, PATCH, and DELETE
353
+ requests
354
+ </AlertDescription>
355
+ </Alert>
356
+ )}
357
+ <Textarea
341
358
  {...register("body")}
342
- className="border w-full rounded p-2 bg-muted h-40"
359
+ className={cn(
360
+ "border w-full rounded-lg p-2 bg-muted h-40 font-mono",
361
+ !["POST", "PUT", "PATCH", "DELETE"].includes(
362
+ method.toUpperCase(),
363
+ ) && "h-20",
364
+ )}
365
+ placeholder={
366
+ !["POST", "PUT", "PATCH", "DELETE"].includes(
367
+ method.toUpperCase(),
368
+ )
369
+ ? "This request does not support a body"
370
+ : undefined
371
+ }
372
+ disabled={
373
+ !["POST", "PUT", "PATCH", "DELETE"].includes(
374
+ method.toUpperCase(),
375
+ )
376
+ }
343
377
  />
378
+ {examples && (
379
+ <ExamplesDropdown
380
+ examples={examples}
381
+ onSelect={(example) =>
382
+ setValue("body", JSON.stringify(example.value, null, 2))
383
+ }
384
+ />
385
+ )}
386
+ </TabsContent>
387
+ <TabsContent value="auth">
388
+ <div className="flex flex-col gap-4 my-4">
389
+ {identities.data?.length === 0 && (
390
+ <Alert>
391
+ <InfoIcon className="w-4 h-4" />
392
+ <AlertTitle>Authentication</AlertTitle>
393
+ <AlertDescription>
394
+ No identities found. Please create an identity first.
395
+ </AlertDescription>
396
+ </Alert>
397
+ )}
398
+ <div className="flex flex-col items-center gap-2">
399
+ <Card className="w-full overflow-hidden">
400
+ <RadioGroup
401
+ onValueChange={(value) => setValue("identity", value)}
402
+ value={formState.identity}
403
+ defaultValue={formState.identity}
404
+ className="gap-0"
405
+ disabled={identities.data?.length === 0}
406
+ >
407
+ <Label
408
+ className="h-12 border-b items-center flex p-4 cursor-pointer hover:bg-accent"
409
+ htmlFor="none"
410
+ >
411
+ <RadioGroupItem value={NO_IDENTITY} id="none">
412
+ None
413
+ </RadioGroupItem>
414
+ <Label htmlFor="none" className="ml-2">
415
+ None
416
+ </Label>
417
+ </Label>
418
+ {identities.data?.map((identity) => (
419
+ <Label
420
+ key={identity.id}
421
+ className="h-12 border-b items-center flex p-4 cursor-pointer hover:bg-accent"
422
+ >
423
+ <RadioGroupItem
424
+ value={identity.id}
425
+ id={identity.id}
426
+ >
427
+ {identity.label}
428
+ </RadioGroupItem>
429
+ <Label htmlFor={identity.id} className="ml-2">
430
+ {identity.label}
431
+ </Label>
432
+ </Label>
433
+ ))}
434
+ </RadioGroup>
435
+ </Card>
436
+ </div>
437
+ </div>
344
438
  </TabsContent>
345
439
  </Tabs>
346
440
  </div>
@@ -1,4 +1,3 @@
1
- import { EraserIcon } from "lucide-react";
2
1
  import {
3
2
  Control,
4
3
  Controller,
@@ -7,16 +6,10 @@ import {
7
6
  } from "react-hook-form";
8
7
  import { Card } from "zudoku/ui/Card.js";
9
8
  import { Checkbox } from "zudoku/ui/Checkbox.js";
10
- import { Button } from "../../../ui/Button.js";
9
+ import { Autocomplete } from "../../../components/Autocomplete.js";
11
10
  import { Input } from "../../../ui/Input.js";
12
- import { cn } from "../../../util/cn.js";
13
- import { EnumSelector } from "./EnumSelector.js";
14
11
  import { InlineInput } from "./InlineInput.js";
15
- import {
16
- NO_IDENTITY,
17
- type PlaygroundForm,
18
- type QueryParam,
19
- } from "./Playground.js";
12
+ import { type PlaygroundForm, type QueryParam } from "./Playground.js";
20
13
 
21
14
  export const QueryParams = ({
22
15
  control,
@@ -33,127 +26,101 @@ export const QueryParams = ({
33
26
 
34
27
  const requiredFields = queryParams.map((param) => Boolean(param.isRequired));
35
28
 
36
- const selectedIdentity = form.watch("identity");
37
- const hasSelectedIdentity = selectedIdentity !== NO_IDENTITY;
38
-
39
29
  return (
40
30
  <Card className="rounded-lg">
41
- <table className="w-full">
42
- <tbody>
43
- {fields
44
- .filter(
45
- // TODO remove this hack for Accu or make it more generic
46
- (field) => !(hasSelectedIdentity && field.name === "apikey"),
47
- )
48
- .map((field, i) => {
49
- const currentParam = queryParams.find(
50
- (param) => param.name === field.name,
51
- );
52
- return (
53
- <tr key={field.id} className="hover:bg-accent/40">
54
- <td className="w-5/12 flex items-center ps-3">
55
- <Controller
56
- control={control}
57
- name={`queryParams.${i}.active`}
58
- render={({ field }) => (
59
- <Checkbox
60
- variant="outline"
61
- id={`queryParams.${i}.active`}
62
- checked={field.value}
63
- onCheckedChange={field.onChange}
64
- />
65
- )}
66
- />
67
- <Controller
68
- control={control}
69
- render={({ field }) => (
70
- <InlineInput asChild>
71
- <label
72
- className="flex items-center cursor-pointer gap-1"
73
- htmlFor={`queryParams.${i}.active`}
74
- title={
75
- requiredFields[i] ? "Required field" : undefined
76
- }
77
- >
78
- {field.value}
79
- {requiredFields[i] && <sup>&nbsp;*</sup>}
80
- </label>
81
- </InlineInput>
82
- )}
83
- name={`queryParams.${i}.name`}
31
+ <div className="w-full ">
32
+ {fields.map((field, i) => {
33
+ const currentParam = queryParams.find(
34
+ (param) => param.name === field.name,
35
+ );
36
+ return (
37
+ <div
38
+ key={field.id}
39
+ className="hover:bg-accent/40 grid grid-cols-[min-content_1fr_1fr] gap-2 items-center px-3"
40
+ >
41
+ <Controller
42
+ control={control}
43
+ name={`queryParams.${i}.active`}
44
+ render={({ field }) => (
45
+ <Checkbox
46
+ variant="outline"
47
+ id={`queryParams.${i}.active`}
48
+ className="mr-2"
49
+ checked={field.value}
50
+ onCheckedChange={field.onChange}
51
+ />
52
+ )}
53
+ />
54
+ <Controller
55
+ control={control}
56
+ render={({ field }) =>
57
+ !requiredFields[i] ? (
58
+ <Autocomplete
59
+ value={field.value}
60
+ options={queryParams.map((param) => param.name)}
61
+ onChange={(e) => {
62
+ field.onChange(e);
63
+ }}
64
+ className="border-0 font-mono text-xs bg-transparent hover:bg-transparent"
84
65
  />
85
- </td>
86
- <td className="w-7/12">
87
- <div className="flex justify-between items-center">
88
- <Controller
89
- control={control}
90
- render={({ field }) => {
91
- const hasEnum =
92
- currentParam?.enum && currentParam.enum.length > 0;
66
+ ) : (
67
+ <InlineInput asChild>
68
+ <label
69
+ className="flex items-center cursor-pointer gap-1"
70
+ htmlFor={`queryParams.${i}.active`}
71
+ title={requiredFields[i] ? "Required field" : undefined}
72
+ >
73
+ {field.value}
74
+ {requiredFields[i] && <sup>&nbsp;*</sup>}
75
+ </label>
76
+ </InlineInput>
77
+ )
78
+ }
79
+ name={`queryParams.${i}.name`}
80
+ />
93
81
 
94
- if (!hasEnum) {
95
- return (
96
- <Input
97
- {...field}
98
- onChange={(e) => {
99
- field.onChange(e.target.value);
100
- if (e.target.value.length > 0) {
101
- form.setValue(
102
- `queryParams.${i}.active`,
103
- true,
104
- );
105
- }
106
- }}
107
- placeholder="Enter value"
108
- className="w-full border-0 shadow-none text-xs font-mono hover:bg-accent"
109
- />
110
- );
111
- }
82
+ <div className="flex justify-between items-center">
83
+ <Controller
84
+ control={control}
85
+ render={({ field }) => {
86
+ const hasEnum =
87
+ currentParam?.enum && currentParam.enum.length > 0;
112
88
 
113
- const enumValues = currentParam.enum ?? [];
89
+ if (!hasEnum) {
90
+ return (
91
+ <Input
92
+ {...field}
93
+ onChange={(e) => {
94
+ field.onChange(e.target.value);
95
+ if (e.target.value.length > 0) {
96
+ form.setValue(`queryParams.${i}.active`, true);
97
+ }
98
+ }}
99
+ placeholder="Enter value"
100
+ className="w-full border-0 shadow-none text-xs font-mono"
101
+ />
102
+ );
103
+ }
114
104
 
115
- return (
116
- <EnumSelector
117
- value={field.value}
118
- enumValues={enumValues}
119
- onChange={field.onChange}
120
- onValueSelected={() => {
121
- form.setValue(`queryParams.${i}.active`, true);
122
- }}
123
- />
124
- );
105
+ return (
106
+ <Autocomplete
107
+ value={field.value}
108
+ options={currentParam.enum ?? []}
109
+ onChange={(e) => {
110
+ field.onChange(e);
111
+ form.setValue(`queryParams.${i}.active`, true);
125
112
  }}
126
- name={`queryParams.${i}.value`}
127
- />
128
- <Controller
129
- control={control}
130
- render={({ field }) => (
131
- <Button
132
- size="icon"
133
- type="button"
134
- variant="ghost"
135
- aria-label="Clear value"
136
- className={cn(
137
- "ms-2 mr-1",
138
- field.value.length === 0
139
- ? "opacity-0 pointer-events-none"
140
- : "opacity-100",
141
- )}
142
- title="Clear value"
143
- onClick={() => field.onChange("")}
144
- >
145
- <EraserIcon size={16} />
146
- </Button>
147
- )}
148
- name={`queryParams.${i}.value`}
113
+ className="font-mono text-xs border-0 ring-1 ring-ring"
149
114
  />
150
- </div>
151
- </td>
152
- </tr>
153
- );
154
- })}
155
- </tbody>
156
- </table>
115
+ );
116
+ }}
117
+ name={`queryParams.${i}.value`}
118
+ />
119
+ </div>
120
+ </div>
121
+ );
122
+ })}
123
+ </div>
157
124
  </Card>
158
125
  );
159
126
  };
@@ -4,28 +4,34 @@ import { removeExtensions } from "./removeExtensions.js";
4
4
  const baseDoc = {
5
5
  openapi: "3.1.0",
6
6
  "x-root-ext": "remove me",
7
+ "x-zuplo-ext": "remove me too",
7
8
  info: {
8
9
  title: "Test API",
9
10
  version: "1.0.0",
10
11
  "x-info-ext": "remove me",
12
+ "x-zuplo-info": "remove me too",
11
13
  },
12
14
  paths: {
13
15
  "/test": {
14
16
  "x-path-ext": "remove me",
17
+ "x-zuplo-path": "remove me too",
15
18
  parameters: [
16
19
  {
17
20
  name: "param1",
18
21
  in: "query",
19
22
  schema: { type: "string" },
20
23
  "x-param-ext": "remove me",
24
+ "x-zuplo-param": "remove me too",
21
25
  },
22
26
  ],
23
27
  get: {
24
28
  "x-operation-ext": "remove me",
29
+ "x-zuplo-route": "remove me too",
25
30
  responses: {
26
31
  "200": {
27
32
  description: "OK",
28
33
  "x-response-ext": "remove me",
34
+ "x-zuplo-response": "remove me too",
29
35
  },
30
36
  },
31
37
  parameters: [
@@ -34,6 +40,7 @@ const baseDoc = {
34
40
  in: "header",
35
41
  schema: { type: "string" },
36
42
  "x-op-param-ext": "remove me",
43
+ "x-zuplo-param": "remove me too",
37
44
  },
38
45
  ],
39
46
  },
@@ -43,6 +50,7 @@ const baseDoc = {
43
50
  {
44
51
  name: "example",
45
52
  "x-tag-ext": "remove me",
53
+ "x-zuplo-tag": "remove me too",
46
54
  },
47
55
  ],
48
56
  components: {
@@ -52,6 +60,7 @@ const baseDoc = {
52
60
  name: "api_key",
53
61
  in: "header",
54
62
  "x-security-ext": "remove me",
63
+ "x-zuplo-security": "remove me too",
55
64
  },
56
65
  },
57
66
  },
@@ -141,4 +150,53 @@ describe("removeExtensions", () => {
141
150
 
142
151
  expect(processed).toEqual(docWithoutExtensions);
143
152
  });
153
+
154
+ it("removes extensions based on shouldRemove callback", () => {
155
+ const processed = removeExtensions({
156
+ shouldRemove: (key) => key.startsWith("x-zuplo"),
157
+ })(baseDoc);
158
+
159
+ // Should remove x-zuplo extensions
160
+ const removedExtensions = [
161
+ "x-zuplo-ext",
162
+ "info.x-zuplo-info",
163
+ "paths./test.x-zuplo-path",
164
+ "paths./test.parameters.0.x-zuplo-param",
165
+ "paths./test.get.x-zuplo-route",
166
+ "paths./test.get.responses.200.x-zuplo-response",
167
+ "paths./test.get.parameters.0.x-zuplo-param",
168
+ "tags.0.x-zuplo-tag",
169
+ "components.securitySchemes.ApiKeyAuth.x-zuplo-security",
170
+ ];
171
+
172
+ // Should keep other x- extensions
173
+ const keptExtensions = [
174
+ "x-root-ext",
175
+ "info.x-info-ext",
176
+ "paths./test.x-path-ext",
177
+ "paths./test.parameters.0.x-param-ext",
178
+ "paths./test.get.x-operation-ext",
179
+ "paths./test.get.responses.200.x-response-ext",
180
+ "paths./test.get.parameters.0.x-op-param-ext",
181
+ "tags.0.x-tag-ext",
182
+ "components.securitySchemes.ApiKeyAuth.x-security-ext",
183
+ ];
184
+
185
+ removedExtensions.forEach((ext) => {
186
+ expect(processed).not.toHaveProperty(ext.split("."));
187
+ });
188
+
189
+ keptExtensions.forEach((ext) => {
190
+ expect(processed).toHaveProperty(ext.split("."));
191
+ });
192
+
193
+ // Assert that non-x- fields remain unchanged
194
+ expect(processed).toHaveProperty("openapi", "3.1.0");
195
+ expect(processed).toHaveProperty("info.title", "Test API");
196
+ expect(processed).toHaveProperty(
197
+ "paths./test.get.responses.200.description",
198
+ "OK",
199
+ );
200
+ expect(processed).toHaveProperty("tags.0.name", "example");
201
+ });
144
202
  });