zudoku 0.27.0 → 0.28.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 (103) hide show
  1. package/dist/lib/components/navigation/SidebarCategory.js +3 -3
  2. package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
  3. package/dist/lib/oas/graphql/index.d.ts +1 -0
  4. package/dist/lib/oas/graphql/index.js +41 -23
  5. package/dist/lib/oas/graphql/index.js.map +1 -1
  6. package/dist/lib/plugins/openapi/Endpoint.js +2 -2
  7. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  8. package/dist/lib/plugins/openapi/{Route.d.ts → OpenApiRoute.d.ts} +2 -1
  9. package/dist/lib/plugins/openapi/{Route.js → OpenApiRoute.js} +3 -4
  10. package/dist/lib/plugins/openapi/OpenApiRoute.js.map +1 -0
  11. package/dist/lib/plugins/openapi/OperationList.d.ts +4 -1
  12. package/dist/lib/plugins/openapi/OperationList.js +20 -14
  13. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  14. package/dist/lib/plugins/openapi/RequestBodySidecarBox.d.ts +1 -1
  15. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js +2 -0
  16. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  17. package/dist/lib/plugins/openapi/Sidecar.js +1 -1
  18. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  19. package/dist/lib/plugins/openapi/SidecarExamples.js +17 -14
  20. package/dist/lib/plugins/openapi/SidecarExamples.js.map +1 -1
  21. package/dist/lib/plugins/openapi/graphql/gql.d.ts +6 -2
  22. package/dist/lib/plugins/openapi/graphql/gql.js +3 -2
  23. package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
  24. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +47 -26
  25. package/dist/lib/plugins/openapi/graphql/graphql.js +20 -16
  26. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  27. package/dist/lib/plugins/openapi/index.js +97 -54
  28. package/dist/lib/plugins/openapi/index.js.map +1 -1
  29. package/dist/lib/plugins/openapi/interfaces.d.ts +1 -0
  30. package/dist/lib/util/joinUrl.js +1 -1
  31. package/dist/lib/util/joinUrl.js.map +1 -1
  32. package/dist/lib/util/joinUrl.test.d.ts +1 -0
  33. package/dist/lib/util/joinUrl.test.js +43 -0
  34. package/dist/lib/util/joinUrl.test.js.map +1 -0
  35. package/dist/vite/plugin-api.js +7 -1
  36. package/dist/vite/plugin-api.js.map +1 -1
  37. package/lib/{AuthenticationPlugin-CO_YCd2x.js → AuthenticationPlugin-Du8cLBSr.js} +2 -2
  38. package/lib/{AuthenticationPlugin-CO_YCd2x.js.map → AuthenticationPlugin-Du8cLBSr.js.map} +1 -1
  39. package/lib/{Markdown-B8o9Qz4q.js → Markdown-Cyrx_JrO.js} +8 -9
  40. package/lib/{Markdown-B8o9Qz4q.js.map → Markdown-Cyrx_JrO.js.map} +1 -1
  41. package/lib/{MdxPage-BxRt3Ly7.js → MdxPage-DewragjB.js} +5 -5
  42. package/lib/{MdxPage-BxRt3Ly7.js.map → MdxPage-DewragjB.js.map} +1 -1
  43. package/lib/OpenApiRoute-UrC_t0e5.js +36 -0
  44. package/lib/OpenApiRoute-UrC_t0e5.js.map +1 -0
  45. package/lib/{OperationList-DH-zIgtq.js → OperationList-D_ejrepA.js} +1373 -1372
  46. package/lib/OperationList-D_ejrepA.js.map +1 -0
  47. package/lib/{Select-B7UXR0SB.js → Select-CnCZ4WhS.js} +3 -3
  48. package/lib/{Select-B7UXR0SB.js.map → Select-CnCZ4WhS.js.map} +1 -1
  49. package/lib/{SlotletProvider-CtIp8rP3.js → SlotletProvider-mQiPDQIH.js} +2 -2
  50. package/lib/{SlotletProvider-CtIp8rP3.js.map → SlotletProvider-mQiPDQIH.js.map} +1 -1
  51. package/lib/{SyntaxHighlight-C1w1QPdY.js → SyntaxHighlight-B0L4SC_N.js} +11 -5
  52. package/lib/SyntaxHighlight-B0L4SC_N.js.map +1 -0
  53. package/lib/{ZudokuContext-8jts0fF3.js → ZudokuContext-BTUJPpQl.js} +21 -21
  54. package/lib/{ZudokuContext-8jts0fF3.js.map → ZudokuContext-BTUJPpQl.js.map} +1 -1
  55. package/lib/{createServer-BV0tHzLK.js → createServer-BydbkTsd.js} +821 -808
  56. package/lib/{createServer-BV0tHzLK.js.map → createServer-BydbkTsd.js.map} +1 -1
  57. package/lib/{hook-BG02esyv.js → hook-FT3SJLe_.js} +2 -2
  58. package/lib/{hook-BG02esyv.js.map → hook-FT3SJLe_.js.map} +1 -1
  59. package/lib/{index-LNp6rxyU.js → index-CjJS0l4l.js} +2 -2
  60. package/lib/{index-LNp6rxyU.js.map → index-CjJS0l4l.js.map} +1 -1
  61. package/lib/{index-DmqsUPcm.js → index-DGugJOLc.js} +836 -777
  62. package/lib/index-DGugJOLc.js.map +1 -0
  63. package/lib/{joinUrl-BTy9bvoK.js → joinUrl-nLx9pD-Z.js} +2 -2
  64. package/lib/joinUrl-nLx9pD-Z.js.map +1 -0
  65. package/lib/{useScrollToAnchor-Bl6mz9_x.js → useScrollToAnchor-eRM9tVvD.js} +10 -9
  66. package/lib/useScrollToAnchor-eRM9tVvD.js.map +1 -0
  67. package/lib/zudoku.auth-clerk.js +1 -1
  68. package/lib/zudoku.auth-openid.js +3 -3
  69. package/lib/zudoku.components.js +153 -154
  70. package/lib/zudoku.components.js.map +1 -1
  71. package/lib/zudoku.plugin-api-catalog.js +3 -3
  72. package/lib/zudoku.plugin-api-keys.js +4 -4
  73. package/lib/zudoku.plugin-custom-pages.js +1 -1
  74. package/lib/zudoku.plugin-markdown.js +1 -1
  75. package/lib/zudoku.plugin-openapi.js +6 -5
  76. package/lib/zudoku.plugin-openapi.js.map +1 -1
  77. package/package.json +1 -1
  78. package/src/lib/components/navigation/SidebarCategory.tsx +3 -2
  79. package/src/lib/oas/graphql/index.ts +63 -35
  80. package/src/lib/plugins/openapi/Endpoint.tsx +2 -2
  81. package/src/lib/plugins/openapi/{Route.tsx → OpenApiRoute.tsx} +3 -3
  82. package/src/lib/plugins/openapi/OperationList.tsx +34 -12
  83. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +2 -0
  84. package/src/lib/plugins/openapi/Sidecar.tsx +1 -1
  85. package/src/lib/plugins/openapi/SidecarExamples.tsx +24 -24
  86. package/src/lib/plugins/openapi/graphql/gql.ts +12 -4
  87. package/src/lib/plugins/openapi/graphql/graphql.ts +66 -43
  88. package/src/lib/plugins/openapi/index.tsx +125 -67
  89. package/src/lib/plugins/openapi/interfaces.ts +1 -0
  90. package/src/lib/util/joinUrl.test.ts +62 -0
  91. package/src/lib/util/joinUrl.ts +1 -1
  92. package/dist/lib/plugins/openapi/Route.js.map +0 -1
  93. package/lib/OperationList-DH-zIgtq.js.map +0 -1
  94. package/lib/Route-DJ0ZlVq1.js +0 -35
  95. package/lib/Route-DJ0ZlVq1.js.map +0 -1
  96. package/lib/StaggeredRender-DgsamH_G.js +0 -17
  97. package/lib/StaggeredRender-DgsamH_G.js.map +0 -1
  98. package/lib/SyntaxHighlight-C1w1QPdY.js.map +0 -1
  99. package/lib/index-Bn6Lc9tq.js +0 -9
  100. package/lib/index-Bn6Lc9tq.js.map +0 -1
  101. package/lib/index-DmqsUPcm.js.map +0 -1
  102. package/lib/joinUrl-BTy9bvoK.js.map +0 -1
  103. package/lib/useScrollToAnchor-Bl6mz9_x.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { j as e } from "./jsx-runtime-Bdg6XQ1m.js";
2
- import { s as j } from "./index-LNp6rxyU.js";
3
- import { u as b } from "./ZudokuContext-8jts0fF3.js";
2
+ import { s as j } from "./index-CjJS0l4l.js";
3
+ import { u as b } from "./ZudokuContext-BTUJPpQl.js";
4
4
  import { b as y } from "./chunk-SYFQ2XB5-BPvC-soB.js";
5
5
  import { Head as v, Link as N } from "./zudoku.components.js";
6
6
  import { u as w } from "./state-mM7uaXTW.js";
7
- import { M as C } from "./Markdown-B8o9Qz4q.js";
7
+ import { M as C } from "./Markdown-Cyrx_JrO.js";
8
8
  import { c as h } from "./cn-qaFjX9_3.js";
9
9
  const f = (r, n) => j(`${r}-${n}`), k = ({
10
10
  items: r,
@@ -1,14 +1,14 @@
1
1
  import { j as e } from "./jsx-runtime-Bdg6XQ1m.js";
2
2
  import { RotateCwIcon as g, TrashIcon as f, EyeOffIcon as j, EyeIcon as v, CheckIcon as w, CopyIcon as b, FileKey2Icon as K } from "lucide-react";
3
- import { D as k, S as m, R as N } from "./SlotletProvider-CtIp8rP3.js";
3
+ import { D as k, S as m, R as N } from "./SlotletProvider-mQiPDQIH.js";
4
4
  import { i as c } from "./invariant-Caa8-XvF.js";
5
- import { u as d, S as I, a as S, b as A, c as C, d as E, e as x } from "./Select-B7UXR0SB.js";
5
+ import { u as d, S as I, a as S, b as A, c as C, d as E, e as x } from "./Select-CnCZ4WhS.js";
6
6
  import { a as P } from "./index.esm-CrSoEshU.js";
7
7
  import { a as D, L as u, O as R } from "./chunk-SYFQ2XB5-BPvC-soB.js";
8
- import { a as y, e as q, u as O } from "./ZudokuContext-8jts0fF3.js";
8
+ import { a as y, e as q, u as O } from "./ZudokuContext-BTUJPpQl.js";
9
9
  import { Button as l } from "./ui/Button.js";
10
10
  import { Input as z } from "./ui/Input.js";
11
- import { u as F } from "./hook-BG02esyv.js";
11
+ import { u as F } from "./hook-FT3SJLe_.js";
12
12
  import { useState as p } from "react";
13
13
  import { c as T } from "./cn-qaFjX9_3.js";
14
14
  const L = ({ service: t }) => {
@@ -1,6 +1,6 @@
1
1
  import { j as o } from "./jsx-runtime-Bdg6XQ1m.js";
2
2
  import a from "react";
3
- import { P as n } from "./Markdown-B8o9Qz4q.js";
3
+ import { P as n } from "./Markdown-Cyrx_JrO.js";
4
4
  import { c } from "./cn-qaFjX9_3.js";
5
5
  import { u as p } from "./useExposedProps-BLKFBylA.js";
6
6
  const u = ({
@@ -74,7 +74,7 @@ const C = (n) => ({
74
74
  const h = {
75
75
  path: r,
76
76
  lazy: async () => {
77
- const { MdxPage: l } = await import("./MdxPage-BxRt3Ly7.js"), { default: p, ...g } = await a();
77
+ const { MdxPage: l } = await import("./MdxPage-DewragjB.js"), { default: p, ...g } = await a();
78
78
  return {
79
79
  element: /* @__PURE__ */ P.jsx(
80
80
  l,
@@ -1,11 +1,12 @@
1
1
  import "./jsx-runtime-Bdg6XQ1m.js";
2
- import "./chunk-SYFQ2XB5-BPvC-soB.js";
3
- import { o as a } from "./index-DmqsUPcm.js";
2
+ import "./index-CjJS0l4l.js";
4
3
  import "lucide-react";
5
- import "./hook-BG02esyv.js";
4
+ import "./chunk-SYFQ2XB5-BPvC-soB.js";
5
+ import "./hook-FT3SJLe_.js";
6
6
  import "./ui/Button.js";
7
- import "./ZudokuContext-8jts0fF3.js";
7
+ import "./joinUrl-nLx9pD-Z.js";
8
+ import { o as f } from "./index-DGugJOLc.js";
8
9
  export {
9
- a as openApiPlugin
10
+ f as openApiPlugin
10
11
  };
11
12
  //# sourceMappingURL=zudoku.plugin-openapi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
1
+ {"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -67,7 +67,7 @@ export const SidebarCategory = ({
67
67
  isActive: false,
68
68
  className: [
69
69
  "text-start font-medium",
70
- isCollapsible
70
+ isCollapsible || typeof category.link !== "undefined"
71
71
  ? "cursor-pointer"
72
72
  : "cursor-default hover:bg-transparent",
73
73
  ],
@@ -82,7 +82,7 @@ export const SidebarCategory = ({
82
82
  {category.link?.type === "doc" ? (
83
83
  <NavLink
84
84
  to={joinPath(category.link.id)}
85
- className="flex-1"
85
+ className="flex-1 truncate"
86
86
  onClick={() => {
87
87
  // if it is the current path and closed then open it because there's no path change to trigger the open
88
88
  if (isActive && !open) {
@@ -112,6 +112,7 @@ export const SidebarCategory = ({
112
112
  className={cn(
113
113
  // CollapsibleContent class is used to animate and it should only be applied when the user has triggered the toggle
114
114
  hasInteracted && "CollapsibleContent",
115
+ category.items.length === 0 && "hidden",
115
116
  "ms-6 my-1",
116
117
  )}
117
118
  >
@@ -67,15 +67,26 @@ const builder = new SchemaBuilder<{
67
67
  };
68
68
  Context: {
69
69
  schema: OpenAPIDocument;
70
+ operations: GraphQLOperationObject[];
71
+ tags: TagObject[];
70
72
  schemaImports?: SchemaImports;
73
+ currentTag?: string;
74
+ slugify: CountableSlugify;
71
75
  };
72
76
  }>({});
73
77
 
78
+ type GraphQLOperationObject = OperationObject & {
79
+ path: string;
80
+ method: string;
81
+ slug?: string;
82
+ parentTag?: string;
83
+ };
84
+
74
85
  const JSONScalar = builder.addScalarType("JSON", GraphQLJSON);
75
86
  const JSONObjectScalar = builder.addScalarType("JSONObject", GraphQLJSONObject);
76
87
  const JSONSchemaScalar = builder.addScalarType("JSONSchema", GraphQLJSONSchema);
77
88
 
78
- const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
89
+ export const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
79
90
  const tags = schema.tags ?? [];
80
91
 
81
92
  // Extract tags from operations
@@ -94,10 +105,10 @@ const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
94
105
  return [...tags, ...uniqueOperationTags.map((tag) => ({ name: tag }))];
95
106
  };
96
107
 
97
- const getAllOperations = (paths?: PathsObject, tag?: string) => {
98
- const slugify = slugifyWithCounter();
108
+ const getAllOperations = (paths?: PathsObject) => {
109
+ const start = performance.now();
99
110
 
100
- return Object.entries(paths ?? {}).flatMap(([path, value]) =>
111
+ const operations = Object.entries(paths ?? {}).flatMap(([path, value]) =>
101
112
  HttpMethods.flatMap((method) => {
102
113
  if (!value?.[method]) return [];
103
114
 
@@ -118,23 +129,17 @@ const getAllOperations = (paths?: PathsObject, tag?: string) => {
118
129
  ...operationParameters,
119
130
  ];
120
131
 
121
- const slugData = {
122
- summary: operation.summary,
123
- operationId: operation.operationId,
124
- path,
125
- method,
126
- };
127
-
128
132
  return {
129
133
  ...operation,
130
134
  method,
131
135
  path,
132
136
  parameters,
133
137
  tags: operation.tags ?? [],
134
- slug: createOperationSlug(slugify, slugData, tag),
135
138
  };
136
139
  }),
137
140
  );
141
+
142
+ return operations;
138
143
  };
139
144
 
140
145
  const SchemaTag = builder.objectRef<TagObject>("SchemaTag").implement({
@@ -144,15 +149,19 @@ const SchemaTag = builder.objectRef<TagObject>("SchemaTag").implement({
144
149
  operations: t.field({
145
150
  type: [OperationItem],
146
151
  resolve: (parent, _args, ctx) => {
147
- const rootTags = getAllTags(ctx.schema).map((tag) => tag.name);
148
-
149
- return getAllOperations(ctx.schema.paths, parent.name).filter((item) =>
150
- parent.name
151
- ? item.tags.includes(parent.name)
152
- : item.tags.length === 0 ||
153
- // If none of the tags are present in the root tags, then show them here
154
- item.tags.every((tag) => !rootTags.includes(tag)),
155
- );
152
+ const rootTags = ctx.tags.map((tag) => tag.name);
153
+ return ctx.operations
154
+ .filter((item) =>
155
+ parent.name
156
+ ? item.tags?.includes(parent.name)
157
+ : item.tags?.length === 0 ||
158
+ // If none of the tags are present in the root tags, then show them here
159
+ item.tags?.every((tag) => !rootTags.includes(tag)),
160
+ )
161
+ .map((item) => ({
162
+ ...item,
163
+ parentTag: parent.name,
164
+ }));
156
165
  },
157
166
  }),
158
167
  }),
@@ -300,12 +309,24 @@ const ResponseItem = builder
300
309
  });
301
310
 
302
311
  const OperationItem = builder
303
- .objectRef<
304
- OperationObject & { path: string; method: string; slug: string }
305
- >("OperationItem")
312
+ .objectRef<GraphQLOperationObject>("OperationItem")
306
313
  .implement({
307
314
  fields: (t) => ({
308
- slug: t.exposeString("slug"),
315
+ slug: t.field({
316
+ type: "String",
317
+ resolve: (parent, _, ctx) => {
318
+ const slugData = {
319
+ summary: parent.summary,
320
+ operationId: parent.operationId,
321
+ path: parent.path,
322
+ method: parent.method,
323
+ };
324
+
325
+ //TODO: fix parent tag parent.tags
326
+ return createOperationSlug(ctx.slugify, slugData, parent.parentTag);
327
+ },
328
+ }),
329
+
309
330
  path: t.exposeString("path"),
310
331
  method: t.exposeString("method"),
311
332
  operationId: t.exposeString("operationId", { nullable: true }),
@@ -414,8 +435,8 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
414
435
  name: t.arg.string(),
415
436
  },
416
437
  type: [SchemaTag],
417
- resolve: (root, args) => {
418
- const tags = [...getAllTags(root), { name: "" }];
438
+ resolve: (root, args, ctx) => {
439
+ const tags = [...ctx.tags, { name: "" }];
419
440
  return args.name ? tags.filter((tag) => tag.name === args.name) : tags;
420
441
  },
421
442
  }),
@@ -426,15 +447,18 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
426
447
  method: t.arg.string(),
427
448
  operationId: t.arg.string(),
428
449
  tag: t.arg.string(),
450
+ untagged: t.arg.boolean(),
429
451
  },
430
- resolve: (parent, args) =>
431
- getAllOperations(parent.paths).filter(
432
- (item) =>
433
- (!args.operationId || item.operationId === args.operationId) &&
434
- (!args.path || item.path === args.path) &&
435
- (!args.method || item.method === args.method) &&
436
- (!args.tag || item.tags.includes(args.tag)),
437
- ),
452
+ resolve: (parent, args, ctx) =>
453
+ ctx.operations.filter((op) => {
454
+ return (
455
+ (!args.operationId || op.operationId === args.operationId) &&
456
+ (!args.path || op.path === args.path) &&
457
+ (!args.method || op.method === args.method) &&
458
+ (!args.tag || op.tags?.some((tag) => args.tag?.includes(tag))) &&
459
+ (!args.untagged || (op.tags ?? []).length === 0)
460
+ );
461
+ }),
438
462
  }),
439
463
  }),
440
464
  });
@@ -467,6 +491,10 @@ builder.queryType({
467
491
  }
468
492
 
469
493
  ctx.schema = schema;
494
+ ctx.operations = getAllOperations(schema.paths);
495
+ ctx.slugify = slugifyWithCounter();
496
+ ctx.tags = getAllTags(schema);
497
+
470
498
  return schema;
471
499
  },
472
500
  }),
@@ -77,14 +77,14 @@ export const Endpoint = () => {
77
77
  setSelectedServer(e.target.value);
78
78
  })
79
79
  }
80
- value={selectedServer ?? result.data.schema.url}
80
+ value={selectedServer ?? servers.at(0)!.url}
81
81
  showChevrons={servers.length > 1}
82
82
  options={servers.map((server) => ({
83
83
  value: server.url,
84
84
  label: server.url,
85
85
  }))}
86
86
  />
87
- <CopyButton url={selectedServer ?? result.data.schema.url} />
87
+ <CopyButton url={selectedServer ?? servers.at(0)!.url} />
88
88
  </div>
89
89
  );
90
90
  };
@@ -1,4 +1,4 @@
1
- import { Outlet, useParams } from "react-router";
1
+ import { Outlet } from "react-router";
2
2
  import { joinPath } from "../../util/joinPath.js";
3
3
  import type { GraphQLClient } from "./client/GraphQLClient.js";
4
4
  import { GraphQLProvider } from "./client/GraphQLContext.js";
@@ -8,16 +8,16 @@ import { type OasPluginConfig } from "./interfaces.js";
8
8
  export const OpenApiRoute = ({
9
9
  basePath,
10
10
  versions,
11
+ version,
11
12
  config,
12
13
  client,
13
14
  }: {
14
15
  basePath: string;
16
+ version?: string;
15
17
  versions: string[];
16
18
  config: OasPluginConfig;
17
19
  client: GraphQLClient;
18
20
  }) => {
19
- const { version } = useParams<"version">();
20
-
21
21
  const input =
22
22
  config.type === "file"
23
23
  ? {
@@ -17,7 +17,6 @@ import { useApiIdentities } from "../../components/context/ZudokuContext.js";
17
17
  import { cn } from "../../util/cn.js";
18
18
  import { Endpoint } from "./Endpoint.js";
19
19
  import { OperationListItem } from "./OperationListItem.js";
20
- import StaggeredRender from "./StaggeredRender.js";
21
20
  import { useCreateQuery } from "./client/useCreateQuery.js";
22
21
  import { useOasConfig } from "./context.js";
23
22
  import { graphql } from "./graphql/index.js";
@@ -90,35 +89,51 @@ export const OperationsFragment = graphql(/* GraphQL */ `
90
89
  export type OperationListItemResult = ResultOf<typeof OperationsFragment>;
91
90
 
92
91
  const AllOperationsQuery = graphql(/* GraphQL */ `
93
- query AllOperations($input: JSON!, $type: SchemaType!) {
92
+ query AllOperations(
93
+ $input: JSON!
94
+ $type: SchemaType!
95
+ $tag: String
96
+ $untagged: Boolean
97
+ ) {
94
98
  schema(input: $input, type: $type) {
95
99
  description
96
100
  summary
97
101
  title
98
102
  url
99
103
  version
100
- tags {
104
+ tags(name: $tag) {
101
105
  name
102
106
  description
103
- operations {
104
- slug
105
- ...OperationsFragment
106
- }
107
+ }
108
+ operations(tag: $tag, untagged: $untagged) {
109
+ slug
110
+ ...OperationsFragment
107
111
  }
108
112
  }
109
113
  }
110
114
  `);
111
115
 
112
- export const OperationList = () => {
116
+ export const OperationList = ({
117
+ tag,
118
+ untagged,
119
+ }: {
120
+ tag?: string;
121
+ untagged?: boolean;
122
+ }) => {
113
123
  const { input, type, versions, version } = useOasConfig();
114
- const query = useCreateQuery(AllOperationsQuery, { input, type });
124
+ const query = useCreateQuery(AllOperationsQuery, {
125
+ input,
126
+ type,
127
+ tag,
128
+ untagged,
129
+ });
115
130
  const { selectedServer } = useSelectedServerStore();
116
131
  const result = useSuspenseQuery(query);
117
132
  const title = result.data.schema.title;
118
133
  const summary = result.data.schema.summary;
119
134
  const description = result.data.schema.description;
120
135
  const navigate = useNavigate();
121
-
136
+ const operations = result.data.schema.operations;
122
137
  // Prefetch for Playground
123
138
  useApiIdentities();
124
139
 
@@ -175,7 +190,14 @@ export const OperationList = () => {
175
190
  <div className="my-4 flex items-center justify-end gap-4">
176
191
  <Endpoint />
177
192
  </div>
178
- {result.data.schema.tags
193
+ {operations.map((fragment) => (
194
+ <OperationListItem
195
+ serverUrl={selectedServer ?? result.data.schema.url ?? ""}
196
+ key={fragment.slug}
197
+ operationFragment={fragment}
198
+ />
199
+ ))}
200
+ {/* {result.data.schema.tags
179
201
  .filter((tag) => tag.operations.length > 0)
180
202
  .map((tag) => (
181
203
  // px, -mx is so that `content-visibility` doesn't cut off overflown heading anchor links '#'
@@ -199,7 +221,7 @@ export const OperationList = () => {
199
221
  </StaggeredRender>
200
222
  </div>
201
223
  </div>
202
- ))}
224
+ ))} */}
203
225
  </div>
204
226
  );
205
227
  };
@@ -8,6 +8,8 @@ export const RequestBodySidecarBox = ({
8
8
  content: Content;
9
9
  onExampleChange?: (example: unknown) => void;
10
10
  }) => {
11
+ if (content.length === 0) return null;
12
+
11
13
  return (
12
14
  <SidecarBox.Root>
13
15
  <SidecarBox.Head className="text-xs flex justify-between items-center">
@@ -196,7 +196,7 @@ export const Sidecar = ({
196
196
  </span>
197
197
  {isOnScreen && (
198
198
  <PlaygroundDialogWrapper
199
- server={result.data.schema.url}
199
+ server={result.data.schema.url ?? ""}
200
200
  servers={result.data.schema.servers.map((server) => server.url)}
201
201
  operation={operation}
202
202
  examples={requestBodyContent ?? undefined}
@@ -1,6 +1,6 @@
1
- import { useEffect, useState } from "react";
1
+ import { useEffect, useMemo, useState } from "react";
2
2
  import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
3
- import { type SchemaObject } from "../../oas/graphql/index.js";
3
+ import { SchemaObject } from "../../oas/parser/index.js";
4
4
  import { CollapsibleCode } from "./CollapsibleCode.js";
5
5
  import type { OperationListItemResult } from "./OperationList.js";
6
6
  import * as SidecarBox from "./SidecarBox.js";
@@ -57,27 +57,27 @@ export const SidecarExamples = ({
57
57
  const examples = effectiveContent?.examples ?? [];
58
58
  const selectedExample = examples[selectedExampleIndex];
59
59
 
60
- let exampleValue = undefined;
61
- if (selectedExample) {
62
- // If it's a wrapped example with a value field, use that
63
- exampleValue =
64
- "value" in selectedExample ? selectedExample.value : selectedExample;
65
- } else if (effectiveContent?.schema) {
66
- // No example provided, generate one from schema
67
- exampleValue = generateSchemaExample(
68
- effectiveContent.schema as SchemaObject,
69
- );
70
- }
60
+ const exampleValue = useMemo(() => {
61
+ if (selectedExample) {
62
+ // If it's a wrapped example with a value field, use that
63
+ return "value" in selectedExample
64
+ ? selectedExample.value
65
+ : selectedExample;
66
+ } else if (effectiveContent?.schema) {
67
+ // No example provided, generate one from schema
68
+ return generateSchemaExample(effectiveContent.schema as SchemaObject);
69
+ }
70
+ }, [selectedExample, effectiveContent?.schema]);
71
71
 
72
72
  useEffect(() => {
73
+ if (!exampleValue) return;
74
+
73
75
  onExampleChange?.(exampleValue);
74
76
  }, [exampleValue, onExampleChange]);
75
77
 
76
78
  const formattedExample = formatForDisplay(exampleValue);
77
79
  const language = getLanguage(effectiveContent?.mediaType);
78
80
 
79
- const hasContent = examples.length > 0 || content.length > 0;
80
-
81
81
  return (
82
82
  <>
83
83
  <SidecarBox.Body className="p-0">
@@ -109,13 +109,13 @@ export const SidecarExamples = ({
109
109
  </div>
110
110
  )}
111
111
  </SidecarBox.Body>
112
- {hasContent && (
113
- <SidecarBox.Footer className="text-xs p-0">
114
- {description && (
115
- <div className="text-muted-foreground text-xs border-b px-3 py-2">
116
- {description}
117
- </div>
118
- )}
112
+ <SidecarBox.Footer className="text-xs p-0 divide-y divide-border">
113
+ {description && (
114
+ <div className="text-muted-foreground text-xs px-3 py-2">
115
+ {description}
116
+ </div>
117
+ )}
118
+ {(examples.length !== 0 || content.length !== 0) && (
119
119
  <div className="flex items-center gap-2 justify-between min-w-0 px-3 py-2">
120
120
  <div className="flex items-center gap-2 min-w-0">
121
121
  {content.length > 1 ? (
@@ -156,8 +156,8 @@ export const SidecarExamples = ({
156
156
  </div>
157
157
  )}
158
158
  </div>
159
- </SidecarBox.Footer>
160
- )}
159
+ )}
160
+ </SidecarBox.Footer>
161
161
  </>
162
162
  );
163
163
  };
@@ -17,12 +17,14 @@ const documents = {
17
17
  types.ServersQueryDocument,
18
18
  "\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n parameters {\n name\n in\n description\n required\n schema\n style\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n examples {\n name\n description\n externalValue\n value\n summary\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n examples {\n name\n description\n externalValue\n value\n summary\n }\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n":
19
19
  types.OperationsFragmentFragmentDoc,
20
- "\n query AllOperations($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n description\n summary\n title\n url\n version\n tags {\n name\n description\n operations {\n slug\n ...OperationsFragment\n }\n }\n }\n }\n":
20
+ "\n query AllOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n description\n summary\n title\n url\n version\n tags(name: $tag) {\n name\n description\n }\n operations(tag: $tag, untagged: $untagged) {\n slug\n ...OperationsFragment\n }\n }\n }\n":
21
21
  types.AllOperationsDocument,
22
22
  "\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n":
23
23
  types.GetServerQueryDocument,
24
- "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n __typename\n name\n operations {\n __typename\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n }\n":
24
+ "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n name\n }\n }\n }\n":
25
25
  types.GetCategoriesDocument,
26
+ "\n query GetOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n operations(tag: $tag, untagged: $untagged) {\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n":
27
+ types.GetOperationsDocument,
26
28
  };
27
29
 
28
30
  /**
@@ -41,7 +43,7 @@ export function graphql(
41
43
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
42
44
  */
43
45
  export function graphql(
44
- source: "\n query AllOperations($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n description\n summary\n title\n url\n version\n tags {\n name\n description\n operations {\n slug\n ...OperationsFragment\n }\n }\n }\n }\n",
46
+ source: "\n query AllOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n description\n summary\n title\n url\n version\n tags(name: $tag) {\n name\n description\n }\n operations(tag: $tag, untagged: $untagged) {\n slug\n ...OperationsFragment\n }\n }\n }\n",
45
47
  ): typeof import("./graphql.js").AllOperationsDocument;
46
48
  /**
47
49
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
@@ -53,8 +55,14 @@ export function graphql(
53
55
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
54
56
  */
55
57
  export function graphql(
56
- source: "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n __typename\n name\n operations {\n __typename\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n }\n",
58
+ source: "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n name\n }\n }\n }\n",
57
59
  ): typeof import("./graphql.js").GetCategoriesDocument;
60
+ /**
61
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
62
+ */
63
+ export function graphql(
64
+ source: "\n query GetOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n operations(tag: $tag, untagged: $untagged) {\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n",
65
+ ): typeof import("./graphql.js").GetOperationsDocument;
58
66
 
59
67
  export function graphql(source: string) {
60
68
  return (documents as any)[source] ?? {};