@djangocfg/ui-tools 2.1.289 → 2.1.291
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -3
- package/dist/{DocsLayout-YDR7DSMM.cjs → DocsLayout-IKH7BLSU.cjs} +1537 -682
- package/dist/DocsLayout-IKH7BLSU.cjs.map +1 -0
- package/dist/{DocsLayout-TKJQ5W5E.mjs → DocsLayout-JPXFUKAR.mjs} +1429 -574
- package/dist/DocsLayout-JPXFUKAR.mjs.map +1 -0
- package/dist/{PrettyCode.client-5GABIN2I.cjs → PrettyCode.client-RPDIE5CH.cjs} +104 -3
- package/dist/PrettyCode.client-RPDIE5CH.cjs.map +1 -0
- package/dist/{PrettyCode.client-IZTXXYHG.mjs → PrettyCode.client-SPMTQEG4.mjs} +106 -5
- package/dist/PrettyCode.client-SPMTQEG4.mjs.map +1 -0
- package/dist/{chunk-IULI4XII.cjs → chunk-5Q4UMSWB.cjs} +355 -9
- package/dist/chunk-5Q4UMSWB.cjs.map +1 -0
- package/dist/{chunk-VZGQC3NG.mjs → chunk-EFWOJPA6.mjs} +349 -9
- package/dist/chunk-EFWOJPA6.mjs.map +1 -0
- package/dist/index.cjs +18 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.mjs +13 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -15
- package/src/components/markdown/MarkdownMessage.tsx +46 -0
- package/src/tools/MarkdownEditor/MarkdownEditor.tsx +42 -1
- package/src/tools/OpenapiViewer/OpenapiViewer.story.tsx +87 -178
- package/src/tools/OpenapiViewer/README.md +114 -6
- package/src/tools/OpenapiViewer/components/DocsLayout/ApiIntroSection.tsx +20 -6
- package/src/tools/OpenapiViewer/components/DocsLayout/DocsView.tsx +6 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/CodeSamples/LanguageTabs.tsx +36 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/CodeSamples/index.tsx +56 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/CodeSamples/useCodeSnippet.ts +77 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/MetaActions.tsx +146 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/MethodBadge.tsx +6 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/PathDisplay.tsx +26 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/index.tsx +87 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Parameters/ParamGroup.tsx +30 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Parameters/ParamRow.tsx +36 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Parameters/index.tsx +22 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/RequestBody/index.tsx +33 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Responses/ResponseBody.tsx +76 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Responses/ResponseRow.tsx +80 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Responses/StatusTag.tsx +32 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Responses/index.tsx +21 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/FieldRow.tsx +106 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts +127 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/index.tsx +31 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/types.ts +28 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Section/SectionHeader.tsx +87 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Section/defaults.ts +27 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Section/index.tsx +45 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/context.tsx +56 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/hooks/useSectionHash.ts +63 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/index.tsx +96 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/store/index.ts +133 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/store/selectors.ts +40 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/types.ts +17 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/SchemaCopyMenu.tsx +8 -2
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/BrandHeader.tsx +48 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/CategoryBlock.tsx +33 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/EndpointRow.tsx +73 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/MethodChips.tsx +43 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/SchemaSection.tsx +27 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/SearchInput.tsx +45 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/SidebarBody.tsx +50 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/Toolbar.tsx +64 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/buildVM.ts +126 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/index.tsx +112 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/types.ts +42 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar/useDebouncedValue.ts +14 -0
- package/src/tools/OpenapiViewer/components/DocsLayout/SlideInPlayground.tsx +10 -7
- package/src/tools/OpenapiViewer/components/DocsLayout/TryItSheet.tsx +9 -6
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/PrettyView.tsx +55 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/PreviewView.tsx +115 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/RawView.tsx +24 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/StatusBar.tsx +63 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/ViewTabs.tsx +45 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/detectContent.ts +97 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/index.tsx +93 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/types.ts +26 -0
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel/useResponseView.ts +62 -0
- package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +41 -71
- package/src/tools/OpenapiViewer/types.ts +10 -0
- package/src/tools/OpenapiViewer/utils/codeSamples.ts +287 -0
- package/src/tools/OpenapiViewer/utils/index.ts +3 -0
- package/src/tools/OpenapiViewer/utils/operationToHar.ts +119 -0
- package/src/tools/OpenapiViewer/utils/sampler.ts +72 -0
- package/src/tools/PrettyCode/PrettyCode.client.tsx +88 -1
- package/src/tools/PrettyCode/PrettyCode.story.tsx +114 -361
- package/src/tools/PrettyCode/index.tsx +13 -0
- package/src/tools/PrettyCode/lazy.tsx +5 -0
- package/src/tools/PrettyCode/registerPrismLanguages.ts +111 -0
- package/dist/DocsLayout-TKJQ5W5E.mjs.map +0 -1
- package/dist/DocsLayout-YDR7DSMM.cjs.map +0 -1
- package/dist/PrettyCode.client-5GABIN2I.cjs.map +0 -1
- package/dist/PrettyCode.client-IZTXXYHG.mjs.map +0 -1
- package/dist/chunk-IULI4XII.cjs.map +0 -1
- package/dist/chunk-VZGQC3NG.mjs.map +0 -1
- package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc.tsx +0 -273
- package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar.tsx +0 -439
- package/src/tools/OpenapiViewer/components/shared/ResponsePanel.tsx +0 -127
|
@@ -1,58 +1,20 @@
|
|
|
1
|
-
import { deduplicateEndpoints, dereferenceSchema, resolveBaseUrl, usePlaygroundContext, toMarkdown, toCompactJson, toRawJson, formatBytes, MarkdownMessage,
|
|
1
|
+
import { deduplicateEndpoints, dereferenceSchema, resolveBaseUrl, usePlaygroundContext, toMarkdown, toCompactJson, toRawJson, formatBytes, MarkdownMessage, CODE_SAMPLE_TARGETS, buildHarRequest, resolveAbsolute, renderSnippet, PrettyCode_default, relativePath, endpointToMarkdown, isValidJson, findApiKeyById, parseRequestHeaders, UrlBuilder, sampleSchemaJson, joinUrl } from './chunk-EFWOJPA6.mjs';
|
|
2
2
|
import { JsonTree_default } from './chunk-LFWQ36LJ.mjs';
|
|
3
3
|
import './chunk-SSUOENAZ.mjs';
|
|
4
4
|
import { __name } from './chunk-CGILA3WO.mjs';
|
|
5
|
-
import
|
|
5
|
+
import React12, { createContext, useRef, useCallback, useEffect, useMemo, useState, useContext } from 'react';
|
|
6
6
|
import { groupBy, orderBy, partition, sortBy, keyBy } from 'lodash-es';
|
|
7
|
-
import { Tooltip, TooltipTrigger, TooltipContent, DropdownMenu, DropdownMenuTrigger, Button, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem, Combobox,
|
|
7
|
+
import { Tooltip, TooltipTrigger, TooltipContent, DropdownMenu, DropdownMenuTrigger, Button, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem, Input, Combobox, SafeTooltipProvider, CopyButton, Switch, Textarea, SidePanel, ResponsiveSheet, ResponsiveSheetContent, ResponsiveSheetHeader, ResponsiveSheetTitle, Skeleton, TooltipProvider } from '@djangocfg/ui-core/components';
|
|
8
8
|
import { toast, useMediaQuery } from '@djangocfg/ui-core/hooks';
|
|
9
9
|
import consola from 'consola';
|
|
10
|
-
import { ChevronRight, Sparkles, ChevronDown, Check, Search, Link2, Play, Minus, Plus, RotateCcw, Send, Key, Terminal, Loader2, WifiOff, AlertCircle } from 'lucide-react';
|
|
10
|
+
import { ChevronRight, Sparkles, ChevronDown, Check, Search, X, Link2, FileCode2, ChevronsDownUp, ChevronsUpDown, Play, Minus, Plus, RotateCcw, Send, Key, Terminal, Info, ShieldCheck, Loader2, WifiOff, AlertCircle } from 'lucide-react';
|
|
11
11
|
import { cn } from '@djangocfg/ui-core/lib';
|
|
12
12
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
13
|
+
import { create } from 'zustand';
|
|
14
|
+
import { persist, createJSONStorage } from 'zustand/middleware';
|
|
13
15
|
|
|
14
|
-
function exampleFromSchema(schema, depth = 0) {
|
|
15
|
-
if (!schema || depth > 8) return null;
|
|
16
|
-
if (schema.example !== void 0) return schema.example;
|
|
17
|
-
if (schema.default !== void 0) return schema.default;
|
|
18
|
-
if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum[0];
|
|
19
|
-
switch (schema.type) {
|
|
20
|
-
case "object": {
|
|
21
|
-
const out = {};
|
|
22
|
-
const props = schema.properties ?? {};
|
|
23
|
-
for (const [k, v] of Object.entries(props)) {
|
|
24
|
-
out[k] = exampleFromSchema(v, depth + 1);
|
|
25
|
-
}
|
|
26
|
-
return out;
|
|
27
|
-
}
|
|
28
|
-
case "array":
|
|
29
|
-
return [exampleFromSchema(schema.items, depth + 1)];
|
|
30
|
-
case "integer":
|
|
31
|
-
case "number":
|
|
32
|
-
return 0;
|
|
33
|
-
case "boolean":
|
|
34
|
-
return false;
|
|
35
|
-
case "string":
|
|
36
|
-
if (schema.format === "date-time") return (/* @__PURE__ */ new Date()).toISOString();
|
|
37
|
-
if (schema.format === "date") return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
38
|
-
if (schema.format === "email") return "user@example.com";
|
|
39
|
-
if (schema.format === "uri" || schema.format === "url") return "https://example.com";
|
|
40
|
-
if (schema.format === "uuid") return "00000000-0000-0000-0000-000000000000";
|
|
41
|
-
return "";
|
|
42
|
-
default:
|
|
43
|
-
if (schema.properties) {
|
|
44
|
-
const out = {};
|
|
45
|
-
for (const [k, v] of Object.entries(schema.properties)) {
|
|
46
|
-
out[k] = exampleFromSchema(v, depth + 1);
|
|
47
|
-
}
|
|
48
|
-
return out;
|
|
49
|
-
}
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
__name(exampleFromSchema, "exampleFromSchema");
|
|
54
16
|
var HTTP_METHODS = ["get", "post", "put", "patch", "delete"];
|
|
55
|
-
var extractEndpoints = /* @__PURE__ */ __name((schema, baseUrl, schemaId) => {
|
|
17
|
+
var extractEndpoints = /* @__PURE__ */ __name((schema, baseUrl, schemaId, specRoot) => {
|
|
56
18
|
const endpoints = [];
|
|
57
19
|
if (!schema.paths) return [];
|
|
58
20
|
for (const [path, methods] of Object.entries(schema.paths)) {
|
|
@@ -76,9 +38,17 @@ var extractEndpoints = /* @__PURE__ */ __name((schema, baseUrl, schemaId) => {
|
|
|
76
38
|
const responses = [];
|
|
77
39
|
if (op.responses) {
|
|
78
40
|
for (const [code, response] of Object.entries(op.responses)) {
|
|
41
|
+
const respContent = response.content;
|
|
42
|
+
const contentKeys = respContent ? Object.keys(respContent) : [];
|
|
43
|
+
const chosenContentType = respContent?.["application/json"] ? "application/json" : contentKeys[0];
|
|
44
|
+
const chosen = chosenContentType ? respContent?.[chosenContentType] : void 0;
|
|
45
|
+
const respSchema = chosen?.schema;
|
|
79
46
|
responses.push({
|
|
80
47
|
code,
|
|
81
|
-
description: response.description || `Response ${code}
|
|
48
|
+
description: response.description || `Response ${code}`,
|
|
49
|
+
contentType: chosenContentType,
|
|
50
|
+
schema: respSchema,
|
|
51
|
+
example: respSchema ? sampleSchemaJson(respSchema, { skipWriteOnly: true }, specRoot) : void 0
|
|
82
52
|
});
|
|
83
53
|
}
|
|
84
54
|
}
|
|
@@ -91,7 +61,7 @@ var extractEndpoints = /* @__PURE__ */ __name((schema, baseUrl, schemaId) => {
|
|
|
91
61
|
type: rawSchema?.type || "object",
|
|
92
62
|
description: op.requestBody.description,
|
|
93
63
|
schema: rawSchema,
|
|
94
|
-
example: rawSchema ?
|
|
64
|
+
example: rawSchema ? sampleSchemaJson(rawSchema, { skipReadOnly: true }, specRoot) : void 0
|
|
95
65
|
};
|
|
96
66
|
}
|
|
97
67
|
const endpoint = {
|
|
@@ -163,8 +133,8 @@ function useOpenApiSchema({
|
|
|
163
133
|
[currentSchema?.baseUrl, configBaseUrl, currentOpenApiSchema]
|
|
164
134
|
);
|
|
165
135
|
const endpoints = useMemo(
|
|
166
|
-
() => dereferencedSchema ? extractEndpoints(dereferencedSchema, resolvedBaseUrl, currentSchemaId) : [],
|
|
167
|
-
[dereferencedSchema, resolvedBaseUrl, currentSchemaId]
|
|
136
|
+
() => dereferencedSchema ? extractEndpoints(dereferencedSchema, resolvedBaseUrl, currentSchemaId, currentOpenApiSchema ?? void 0) : [],
|
|
137
|
+
[dereferencedSchema, resolvedBaseUrl, currentSchemaId, currentOpenApiSchema]
|
|
168
138
|
);
|
|
169
139
|
const categories = useMemo(() => getCategories(endpoints), [endpoints]);
|
|
170
140
|
const schemaInfo = useMemo(() => {
|
|
@@ -266,7 +236,7 @@ function useOpenApiSchema({
|
|
|
266
236
|
description: raw.info.description,
|
|
267
237
|
servers: raw.servers
|
|
268
238
|
} : null;
|
|
269
|
-
const eps = deref ? extractEndpoints(deref, resolved, src.id) : [];
|
|
239
|
+
const eps = deref ? extractEndpoints(deref, resolved, src.id, raw ?? void 0) : [];
|
|
270
240
|
const state = loadStates.get(src.id) ?? { loading: !raw, error: null };
|
|
271
241
|
return {
|
|
272
242
|
source: src,
|
|
@@ -599,7 +569,7 @@ function CollapsibleSection({
|
|
|
599
569
|
children,
|
|
600
570
|
defaultOpen = false
|
|
601
571
|
}) {
|
|
602
|
-
const [open, setOpen] =
|
|
572
|
+
const [open, setOpen] = React12.useState(defaultOpen);
|
|
603
573
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-0", children: [
|
|
604
574
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
605
575
|
/* @__PURE__ */ jsxs(
|
|
@@ -620,75 +590,6 @@ function CollapsibleSection({
|
|
|
620
590
|
] });
|
|
621
591
|
}
|
|
622
592
|
__name(CollapsibleSection, "CollapsibleSection");
|
|
623
|
-
|
|
624
|
-
// src/tools/OpenapiViewer/components/DocsLayout/sidebarLabel.ts
|
|
625
|
-
function longestCommonPrefix(paths) {
|
|
626
|
-
if (paths.length === 0) return "";
|
|
627
|
-
if (paths.length === 1) return "";
|
|
628
|
-
const segments = paths.map((p) => p.split("/"));
|
|
629
|
-
const minLen = Math.min(...segments.map((s) => s.length));
|
|
630
|
-
const shared = [];
|
|
631
|
-
for (let i = 0; i < minLen; i++) {
|
|
632
|
-
const first = segments[0][i];
|
|
633
|
-
if (segments.every((s) => s[i] === first)) {
|
|
634
|
-
shared.push(first);
|
|
635
|
-
} else {
|
|
636
|
-
break;
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
const joined = shared.join("/");
|
|
640
|
-
return joined;
|
|
641
|
-
}
|
|
642
|
-
__name(longestCommonPrefix, "longestCommonPrefix");
|
|
643
|
-
function sidebarLabel(ep, groupCommonPrefix) {
|
|
644
|
-
if (ep.summary) return ep.summary;
|
|
645
|
-
if (groupCommonPrefix && ep.path.startsWith(groupCommonPrefix)) {
|
|
646
|
-
const tail = ep.path.slice(groupCommonPrefix.length) || "/";
|
|
647
|
-
return tail;
|
|
648
|
-
}
|
|
649
|
-
return relativePath2(ep.path);
|
|
650
|
-
}
|
|
651
|
-
__name(sidebarLabel, "sidebarLabel");
|
|
652
|
-
function relativePath2(full) {
|
|
653
|
-
try {
|
|
654
|
-
return new URL(full).pathname;
|
|
655
|
-
} catch {
|
|
656
|
-
return full;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
__name(relativePath2, "relativePath");
|
|
660
|
-
function sidebarTooltip(ep) {
|
|
661
|
-
return `${ep.method} ${relativePath2(ep.path)}`;
|
|
662
|
-
}
|
|
663
|
-
__name(sidebarTooltip, "sidebarTooltip");
|
|
664
|
-
|
|
665
|
-
// src/tools/OpenapiViewer/components/DocsLayout/grouping.ts
|
|
666
|
-
var METHOD_ORDER = {
|
|
667
|
-
GET: 0,
|
|
668
|
-
POST: 1,
|
|
669
|
-
PUT: 2,
|
|
670
|
-
PATCH: 3,
|
|
671
|
-
DELETE: 4
|
|
672
|
-
};
|
|
673
|
-
var methodRank = /* @__PURE__ */ __name((ep) => METHOD_ORDER[ep.method] ?? 99, "methodRank");
|
|
674
|
-
function groupEndpoints(list) {
|
|
675
|
-
const byCategory = groupBy(list, "category");
|
|
676
|
-
const all = Object.entries(byCategory).map(([category, endpoints]) => ({
|
|
677
|
-
category,
|
|
678
|
-
endpoints: orderBy(endpoints, ["path", methodRank], ["asc", "asc"]),
|
|
679
|
-
commonPrefix: longestCommonPrefix(endpoints.map((e) => e.path))
|
|
680
|
-
}));
|
|
681
|
-
const [other, named] = partition(all, (g) => g.category === "Other");
|
|
682
|
-
return [...sortBy(named, (g) => g.category.toLowerCase()), ...other];
|
|
683
|
-
}
|
|
684
|
-
__name(groupEndpoints, "groupEndpoints");
|
|
685
|
-
function buildSchemaSections(sources, endpointsBySchema) {
|
|
686
|
-
return sources.map((source) => ({
|
|
687
|
-
source,
|
|
688
|
-
groups: groupEndpoints(endpointsBySchema[source.id] ?? [])
|
|
689
|
-
}));
|
|
690
|
-
}
|
|
691
|
-
__name(buildSchemaSections, "buildSchemaSections");
|
|
692
593
|
var FLAVOUR_LABELS = {
|
|
693
594
|
markdown: {
|
|
694
595
|
title: "Markdown for LLM",
|
|
@@ -755,40 +656,150 @@ function SchemaCopyMenu({ schema, endpoints, baseUrl, variant = "button" }) {
|
|
|
755
656
|
"Copy for AI",
|
|
756
657
|
/* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3 opacity-60" })
|
|
757
658
|
] }) }),
|
|
758
|
-
/* @__PURE__ */ jsxs(
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
{
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
659
|
+
/* @__PURE__ */ jsxs(
|
|
660
|
+
DropdownMenuContent,
|
|
661
|
+
{
|
|
662
|
+
side: "right",
|
|
663
|
+
align: "start",
|
|
664
|
+
sideOffset: 6,
|
|
665
|
+
collisionPadding: 8,
|
|
666
|
+
className: "w-60 max-w-[calc(100vw-16px)]",
|
|
667
|
+
children: [
|
|
668
|
+
/* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-[10px] uppercase tracking-wider text-muted-foreground/70", children: "Copy schema" }),
|
|
669
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
670
|
+
flavours.map((f) => {
|
|
671
|
+
const label = FLAVOUR_LABELS[f];
|
|
672
|
+
const size = sizeCache[f];
|
|
673
|
+
const isDone = justCopied === f;
|
|
674
|
+
return /* @__PURE__ */ jsxs(
|
|
675
|
+
DropdownMenuItem,
|
|
676
|
+
{
|
|
677
|
+
onClick: (e) => {
|
|
678
|
+
e.preventDefault();
|
|
679
|
+
void handleCopy(f);
|
|
680
|
+
},
|
|
681
|
+
className: "flex flex-col items-start gap-0.5 py-2 cursor-pointer",
|
|
682
|
+
children: [
|
|
683
|
+
/* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-2", children: [
|
|
684
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium flex-1", children: label.title }),
|
|
685
|
+
isDone ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-[10px] text-emerald-500", children: [
|
|
686
|
+
/* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }),
|
|
687
|
+
" Copied"
|
|
688
|
+
] }) : size ? /* @__PURE__ */ jsx("span", { className: "text-[10px] font-mono text-muted-foreground/70 tabular-nums", children: size }) : null
|
|
689
|
+
] }),
|
|
690
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/70 leading-snug line-clamp-1", children: label.hint })
|
|
691
|
+
]
|
|
692
|
+
},
|
|
693
|
+
f
|
|
694
|
+
);
|
|
695
|
+
})
|
|
696
|
+
]
|
|
697
|
+
}
|
|
698
|
+
)
|
|
788
699
|
] });
|
|
789
700
|
}
|
|
790
701
|
__name(SchemaCopyMenu, "SchemaCopyMenu");
|
|
791
|
-
|
|
702
|
+
function BrandHeader({ info, endpoints, rawSchema, resolvedBaseUrl }) {
|
|
703
|
+
const apiTitle = info?.title ?? "API Reference";
|
|
704
|
+
const copyReady = rawSchema !== null && rawSchema !== void 0 && endpoints.length > 0;
|
|
705
|
+
return /* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b px-3 py-2.5 flex items-start gap-2", children: [
|
|
706
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
707
|
+
/* @__PURE__ */ jsx(
|
|
708
|
+
"div",
|
|
709
|
+
{
|
|
710
|
+
className: "text-[13px] font-semibold text-foreground leading-tight truncate",
|
|
711
|
+
title: apiTitle,
|
|
712
|
+
children: apiTitle
|
|
713
|
+
}
|
|
714
|
+
),
|
|
715
|
+
info?.version && /* @__PURE__ */ jsxs("div", { className: "font-mono text-[10px] text-muted-foreground/60 leading-tight mt-0.5", children: [
|
|
716
|
+
"v",
|
|
717
|
+
info.version
|
|
718
|
+
] })
|
|
719
|
+
] }),
|
|
720
|
+
copyReady && /* @__PURE__ */ jsx(
|
|
721
|
+
SchemaCopyMenu,
|
|
722
|
+
{
|
|
723
|
+
schema: rawSchema ?? null,
|
|
724
|
+
endpoints,
|
|
725
|
+
baseUrl: resolvedBaseUrl,
|
|
726
|
+
variant: "icon"
|
|
727
|
+
}
|
|
728
|
+
)
|
|
729
|
+
] });
|
|
730
|
+
}
|
|
731
|
+
__name(BrandHeader, "BrandHeader");
|
|
732
|
+
|
|
733
|
+
// src/tools/OpenapiViewer/components/DocsLayout/sidebarLabel.ts
|
|
734
|
+
function longestCommonPrefix(paths) {
|
|
735
|
+
if (paths.length === 0) return "";
|
|
736
|
+
if (paths.length === 1) return "";
|
|
737
|
+
const segments = paths.map((p) => p.split("/"));
|
|
738
|
+
const minLen = Math.min(...segments.map((s) => s.length));
|
|
739
|
+
const shared = [];
|
|
740
|
+
for (let i = 0; i < minLen; i++) {
|
|
741
|
+
const first = segments[0][i];
|
|
742
|
+
if (segments.every((s) => s[i] === first)) {
|
|
743
|
+
shared.push(first);
|
|
744
|
+
} else {
|
|
745
|
+
break;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
const joined = shared.join("/");
|
|
749
|
+
return joined;
|
|
750
|
+
}
|
|
751
|
+
__name(longestCommonPrefix, "longestCommonPrefix");
|
|
752
|
+
function sidebarLabel(ep, groupCommonPrefix) {
|
|
753
|
+
if (ep.summary) return ep.summary;
|
|
754
|
+
if (groupCommonPrefix && ep.path.startsWith(groupCommonPrefix)) {
|
|
755
|
+
const tail = ep.path.slice(groupCommonPrefix.length) || "/";
|
|
756
|
+
return tail;
|
|
757
|
+
}
|
|
758
|
+
return relativePath2(ep.path);
|
|
759
|
+
}
|
|
760
|
+
__name(sidebarLabel, "sidebarLabel");
|
|
761
|
+
function relativePath2(full) {
|
|
762
|
+
try {
|
|
763
|
+
return new URL(full).pathname;
|
|
764
|
+
} catch {
|
|
765
|
+
return full;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
__name(relativePath2, "relativePath");
|
|
769
|
+
function sidebarTooltip(ep) {
|
|
770
|
+
return `${ep.method} ${relativePath2(ep.path)}`;
|
|
771
|
+
}
|
|
772
|
+
__name(sidebarTooltip, "sidebarTooltip");
|
|
773
|
+
|
|
774
|
+
// src/tools/OpenapiViewer/components/DocsLayout/grouping.ts
|
|
775
|
+
var METHOD_ORDER = {
|
|
776
|
+
GET: 0,
|
|
777
|
+
POST: 1,
|
|
778
|
+
PUT: 2,
|
|
779
|
+
PATCH: 3,
|
|
780
|
+
DELETE: 4
|
|
781
|
+
};
|
|
782
|
+
var methodRank = /* @__PURE__ */ __name((ep) => METHOD_ORDER[ep.method] ?? 99, "methodRank");
|
|
783
|
+
function groupEndpoints(list) {
|
|
784
|
+
const byCategory = groupBy(list, "category");
|
|
785
|
+
const all = Object.entries(byCategory).map(([category, endpoints]) => ({
|
|
786
|
+
category,
|
|
787
|
+
endpoints: orderBy(endpoints, ["path", methodRank], ["asc", "asc"]),
|
|
788
|
+
commonPrefix: longestCommonPrefix(endpoints.map((e) => e.path))
|
|
789
|
+
}));
|
|
790
|
+
const [other, named] = partition(all, (g) => g.category === "Other");
|
|
791
|
+
return [...sortBy(named, (g) => g.category.toLowerCase()), ...other];
|
|
792
|
+
}
|
|
793
|
+
__name(groupEndpoints, "groupEndpoints");
|
|
794
|
+
function buildSchemaSections(sources, endpointsBySchema) {
|
|
795
|
+
return sources.map((source) => ({
|
|
796
|
+
source,
|
|
797
|
+
groups: groupEndpoints(endpointsBySchema[source.id] ?? [])
|
|
798
|
+
}));
|
|
799
|
+
}
|
|
800
|
+
__name(buildSchemaSections, "buildSchemaSections");
|
|
801
|
+
|
|
802
|
+
// src/tools/OpenapiViewer/components/DocsLayout/Sidebar/buildVM.ts
|
|
792
803
|
function filterEndpoints(list, query, method) {
|
|
793
804
|
let out = list;
|
|
794
805
|
if (method !== "ALL") {
|
|
@@ -824,14 +835,19 @@ function buildCategory(group, activeEndpointId, schemaId, keyPrefix) {
|
|
|
824
835
|
};
|
|
825
836
|
}
|
|
826
837
|
__name(buildCategory, "buildCategory");
|
|
827
|
-
|
|
838
|
+
function emptyTextFor(query, method, defaultText) {
|
|
828
839
|
if (query && method !== "ALL") return `No ${method} endpoints match "${query}"`;
|
|
829
840
|
if (query) return `No endpoints match "${query}"`;
|
|
830
841
|
if (method !== "ALL") return `No ${method} endpoints`;
|
|
831
842
|
return defaultText;
|
|
832
|
-
}
|
|
843
|
+
}
|
|
844
|
+
__name(emptyTextFor, "emptyTextFor");
|
|
833
845
|
function buildFlatVM(endpoints, selectedVersion, query, method, activeEndpointId) {
|
|
834
|
-
const filtered = filterEndpoints(
|
|
846
|
+
const filtered = filterEndpoints(
|
|
847
|
+
deduplicateEndpoints(endpoints, selectedVersion),
|
|
848
|
+
query,
|
|
849
|
+
method
|
|
850
|
+
);
|
|
835
851
|
const groups = groupEndpoints(filtered);
|
|
836
852
|
return {
|
|
837
853
|
kind: "flat",
|
|
@@ -844,13 +860,19 @@ function buildSectionsVM(schemas, endpointsBySchema, selectedVersion, query, met
|
|
|
844
860
|
const filteredMap = {};
|
|
845
861
|
for (const src of schemas) {
|
|
846
862
|
const raw = endpointsBySchema[src.id] ?? [];
|
|
847
|
-
filteredMap[src.id] = filterEndpoints(
|
|
863
|
+
filteredMap[src.id] = filterEndpoints(
|
|
864
|
+
deduplicateEndpoints(raw, selectedVersion),
|
|
865
|
+
query,
|
|
866
|
+
method
|
|
867
|
+
);
|
|
848
868
|
}
|
|
849
869
|
const rawSections = buildSchemaSections(schemas, filteredMap);
|
|
850
870
|
const sections = rawSections.filter((s) => s.groups.length > 0).map((s) => ({
|
|
851
871
|
sourceId: s.source.id,
|
|
852
872
|
sourceName: s.source.name,
|
|
853
|
-
categories: s.groups.map(
|
|
873
|
+
categories: s.groups.map(
|
|
874
|
+
(g) => buildCategory(g, activeEndpointId, s.source.id, `${s.source.id}-`)
|
|
875
|
+
)
|
|
854
876
|
}));
|
|
855
877
|
return {
|
|
856
878
|
kind: "sections",
|
|
@@ -859,159 +881,11 @@ function buildSectionsVM(schemas, endpointsBySchema, selectedVersion, query, met
|
|
|
859
881
|
};
|
|
860
882
|
}
|
|
861
883
|
__name(buildSectionsVM, "buildSectionsVM");
|
|
862
|
-
function
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
schemas,
|
|
866
|
-
currentSchemaId,
|
|
867
|
-
onSchemaChange,
|
|
868
|
-
activeEndpointId,
|
|
869
|
-
selectedVersion,
|
|
870
|
-
onNavigate,
|
|
871
|
-
grouping = "selector",
|
|
872
|
-
endpointsBySchema,
|
|
873
|
-
rawSchema,
|
|
874
|
-
resolvedBaseUrl
|
|
875
|
-
}) {
|
|
876
|
-
const [search, setSearch] = useState("");
|
|
877
|
-
const [debounced, setDebounced] = useState("");
|
|
878
|
-
const [methodFilter, setMethodFilter] = useState("ALL");
|
|
879
|
-
useEffect(() => {
|
|
880
|
-
const id = setTimeout(() => setDebounced(search), 120);
|
|
881
|
-
return () => clearTimeout(id);
|
|
882
|
-
}, [search]);
|
|
883
|
-
const body = useMemo(() => {
|
|
884
|
-
if (grouping === "sections") {
|
|
885
|
-
return buildSectionsVM(
|
|
886
|
-
schemas,
|
|
887
|
-
endpointsBySchema ?? {},
|
|
888
|
-
selectedVersion,
|
|
889
|
-
debounced,
|
|
890
|
-
methodFilter,
|
|
891
|
-
activeEndpointId
|
|
892
|
-
);
|
|
893
|
-
}
|
|
894
|
-
return buildFlatVM(endpoints, selectedVersion, debounced, methodFilter, activeEndpointId);
|
|
895
|
-
}, [
|
|
896
|
-
grouping,
|
|
897
|
-
schemas,
|
|
898
|
-
endpointsBySchema,
|
|
899
|
-
endpoints,
|
|
900
|
-
selectedVersion,
|
|
901
|
-
debounced,
|
|
902
|
-
methodFilter,
|
|
903
|
-
activeEndpointId
|
|
904
|
-
]);
|
|
905
|
-
const schemaOptions = useMemo(
|
|
906
|
-
() => schemas.map((s) => ({ value: s.id, label: s.name })),
|
|
907
|
-
[schemas]
|
|
908
|
-
);
|
|
909
|
-
const hasMultipleSchemas = schemas.length > 1;
|
|
910
|
-
const apiTitle = info?.title ?? "API Reference";
|
|
911
|
-
const showCombobox = grouping === "selector" && hasMultipleSchemas;
|
|
912
|
-
const copyReady = rawSchema !== null && rawSchema !== void 0 && endpoints.length > 0;
|
|
913
|
-
return /* @__PURE__ */ jsxs("aside", { className: "flex flex-col h-full min-h-0 border-r bg-muted/10", children: [
|
|
914
|
-
/* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b px-3 h-12 flex items-center gap-2", children: [
|
|
915
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [
|
|
916
|
-
/* @__PURE__ */ jsx("span", { className: "text-[13px] font-semibold text-foreground truncate", children: apiTitle }),
|
|
917
|
-
info?.version && /* @__PURE__ */ jsxs("span", { className: "font-mono text-[10px] text-muted-foreground/70 shrink-0", children: [
|
|
918
|
-
"v",
|
|
919
|
-
info.version
|
|
920
|
-
] })
|
|
921
|
-
] }),
|
|
922
|
-
copyReady && /* @__PURE__ */ jsx(
|
|
923
|
-
SchemaCopyMenu,
|
|
924
|
-
{
|
|
925
|
-
schema: rawSchema ?? null,
|
|
926
|
-
endpoints,
|
|
927
|
-
baseUrl: resolvedBaseUrl,
|
|
928
|
-
variant: "icon"
|
|
929
|
-
}
|
|
930
|
-
)
|
|
931
|
-
] }),
|
|
932
|
-
/* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b px-3 py-3 space-y-2", children: [
|
|
933
|
-
showCombobox && /* @__PURE__ */ jsx(
|
|
934
|
-
Combobox,
|
|
935
|
-
{
|
|
936
|
-
options: schemaOptions,
|
|
937
|
-
value: currentSchemaId ?? "",
|
|
938
|
-
onValueChange: (id) => id && onSchemaChange(id),
|
|
939
|
-
placeholder: "Select API",
|
|
940
|
-
searchPlaceholder: "Search APIs\u2026",
|
|
941
|
-
emptyText: "No APIs found",
|
|
942
|
-
className: "w-full h-8 text-xs"
|
|
943
|
-
}
|
|
944
|
-
),
|
|
945
|
-
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
946
|
-
/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground/50 pointer-events-none" }),
|
|
947
|
-
/* @__PURE__ */ jsx(
|
|
948
|
-
Input,
|
|
949
|
-
{
|
|
950
|
-
placeholder: "Search endpoints\u2026",
|
|
951
|
-
value: search,
|
|
952
|
-
onChange: (e) => setSearch(e.target.value),
|
|
953
|
-
className: "pl-8 h-8 text-xs"
|
|
954
|
-
}
|
|
955
|
-
)
|
|
956
|
-
] }),
|
|
957
|
-
/* @__PURE__ */ jsx(MethodChips, { value: methodFilter, onChange: setMethodFilter })
|
|
958
|
-
] }),
|
|
959
|
-
/* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx(SidebarBody, { body, onNavigate }) })
|
|
960
|
-
] });
|
|
961
|
-
}
|
|
962
|
-
__name(DocsSidebar, "DocsSidebar");
|
|
963
|
-
function MethodChips({
|
|
964
|
-
value,
|
|
965
|
-
onChange
|
|
966
|
-
}) {
|
|
967
|
-
return /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 flex-wrap", children: METHOD_FILTERS.map((m) => {
|
|
968
|
-
const active = value === m;
|
|
969
|
-
return /* @__PURE__ */ jsx(
|
|
970
|
-
"button",
|
|
971
|
-
{
|
|
972
|
-
type: "button",
|
|
973
|
-
onClick: () => onChange(m),
|
|
974
|
-
"aria-pressed": active,
|
|
975
|
-
className: cn(
|
|
976
|
-
"px-2 py-0.5 rounded font-mono text-[10px] font-semibold tracking-wide transition-colors border",
|
|
977
|
-
active ? "bg-primary/15 border-primary/40 text-foreground" : "bg-transparent border-border/40 text-muted-foreground hover:text-foreground hover:border-border"
|
|
978
|
-
),
|
|
979
|
-
children: m
|
|
980
|
-
},
|
|
981
|
-
m
|
|
982
|
-
);
|
|
983
|
-
}) });
|
|
984
|
-
}
|
|
985
|
-
__name(MethodChips, "MethodChips");
|
|
986
|
-
function SidebarBody({ body, onNavigate }) {
|
|
987
|
-
if (body.kind === "flat") {
|
|
988
|
-
if (body.categories.length === 0) {
|
|
989
|
-
return /* @__PURE__ */ jsx("div", { className: "py-10 px-4 text-center text-xs text-muted-foreground", children: body.emptyText });
|
|
990
|
-
}
|
|
991
|
-
return /* @__PURE__ */ jsx("nav", { className: "py-2", children: body.categories.map((cat) => /* @__PURE__ */ jsx(CategoryBlock, { category: cat, onNavigate }, cat.key)) });
|
|
992
|
-
}
|
|
993
|
-
if (body.sections.length === 0) {
|
|
994
|
-
return /* @__PURE__ */ jsx("div", { className: "py-10 px-4 text-center text-xs text-muted-foreground", children: body.emptyText });
|
|
995
|
-
}
|
|
996
|
-
return /* @__PURE__ */ jsx("nav", { className: "py-2", children: body.sections.map((section) => /* @__PURE__ */ jsxs("div", { className: "mb-5 last:mb-2", children: [
|
|
997
|
-
/* @__PURE__ */ jsx("div", { className: "px-4 py-2 sticky top-0 z-[1] bg-muted/30 backdrop-blur-[2px] border-b border-border/30", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold uppercase tracking-[0.12em] text-foreground/80", children: section.sourceName }) }),
|
|
998
|
-
section.categories.map((cat) => /* @__PURE__ */ jsx(CategoryBlock, { category: cat, onNavigate }, cat.key))
|
|
999
|
-
] }, section.sourceId)) });
|
|
1000
|
-
}
|
|
1001
|
-
__name(SidebarBody, "SidebarBody");
|
|
1002
|
-
var CategoryBlock = React6.memo(/* @__PURE__ */ __name(function CategoryBlock2({
|
|
1003
|
-
category,
|
|
1004
|
-
onNavigate
|
|
1005
|
-
}) {
|
|
1006
|
-
return /* @__PURE__ */ jsxs("div", { className: "mb-4 last:mb-2", children: [
|
|
1007
|
-
/* @__PURE__ */ jsx("div", { className: "px-4 py-1.5 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/50 select-none", children: category.category }),
|
|
1008
|
-
/* @__PURE__ */ jsx("div", { children: category.rows.map((row) => /* @__PURE__ */ jsx(EndpointRow, { row, onNavigate }, row.key)) })
|
|
1009
|
-
] });
|
|
1010
|
-
}, "CategoryBlock"));
|
|
1011
|
-
var EndpointRow = React6.memo(/* @__PURE__ */ __name(function EndpointRow2({
|
|
1012
|
-
row,
|
|
1013
|
-
onNavigate
|
|
884
|
+
var EndpointRow = React12.memo(/* @__PURE__ */ __name(function EndpointRow2({
|
|
885
|
+
row,
|
|
886
|
+
onNavigate
|
|
1014
887
|
}) {
|
|
888
|
+
const displayLabel = row.label.replace(/\.$/, "");
|
|
1015
889
|
return /* @__PURE__ */ jsxs(Tooltip, { delayDuration: 350, children: [
|
|
1016
890
|
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1017
891
|
"button",
|
|
@@ -1019,21 +893,21 @@ var EndpointRow = React6.memo(/* @__PURE__ */ __name(function EndpointRow2({
|
|
|
1019
893
|
onClick: () => onNavigate(row.anchor, row.schemaId),
|
|
1020
894
|
"aria-current": row.isActive ? "location" : void 0,
|
|
1021
895
|
className: cn(
|
|
1022
|
-
"relative
|
|
896
|
+
"relative w-full text-left grid grid-cols-[52px_minmax(0,1fr)] items-baseline gap-2 pl-3 pr-3 py-1 transition-colors",
|
|
1023
897
|
row.isActive ? "bg-primary/10 text-foreground" : "hover:bg-muted/40 text-foreground/75 hover:text-foreground"
|
|
1024
898
|
),
|
|
1025
899
|
children: [
|
|
1026
900
|
row.isActive && /* @__PURE__ */ jsx("span", { className: "absolute left-0 top-1 bottom-1 w-0.5 rounded-r bg-primary" }),
|
|
1027
|
-
/* @__PURE__ */ jsx("span", { className: "
|
|
901
|
+
/* @__PURE__ */ jsx("span", { className: "justify-self-start", children: /* @__PURE__ */ jsx(MethodBadge, { method: row.method }) }),
|
|
1028
902
|
/* @__PURE__ */ jsx(
|
|
1029
903
|
"span",
|
|
1030
904
|
{
|
|
1031
905
|
className: cn(
|
|
1032
|
-
"line-clamp-2 leading-snug
|
|
906
|
+
"line-clamp-2 leading-snug min-w-0",
|
|
1033
907
|
row.useMono ? "font-mono text-[11px] break-all" : "text-[12px]",
|
|
1034
908
|
row.isActive && "text-foreground font-medium"
|
|
1035
909
|
),
|
|
1036
|
-
children:
|
|
910
|
+
children: displayLabel
|
|
1037
911
|
}
|
|
1038
912
|
)
|
|
1039
913
|
]
|
|
@@ -1042,6 +916,202 @@ var EndpointRow = React6.memo(/* @__PURE__ */ __name(function EndpointRow2({
|
|
|
1042
916
|
/* @__PURE__ */ jsx(TooltipContent, { side: "right", align: "center", className: "font-mono text-[11px]", children: row.tooltip })
|
|
1043
917
|
] });
|
|
1044
918
|
}, "EndpointRow"));
|
|
919
|
+
var CategoryBlock = React12.memo(/* @__PURE__ */ __name(function CategoryBlock2({
|
|
920
|
+
category,
|
|
921
|
+
onNavigate
|
|
922
|
+
}) {
|
|
923
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-2.5 last:mb-1", children: [
|
|
924
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 pt-3 pb-1 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/50 select-none", children: category.category }),
|
|
925
|
+
/* @__PURE__ */ jsx("div", { children: category.rows.map((row) => /* @__PURE__ */ jsx(EndpointRow, { row, onNavigate }, row.key)) })
|
|
926
|
+
] });
|
|
927
|
+
}, "CategoryBlock"));
|
|
928
|
+
function SchemaSection({ section, onNavigate }) {
|
|
929
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-4 last:mb-2", children: [
|
|
930
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 sticky top-0 z-[1] bg-background/95 backdrop-blur-[2px] border-b border-border/40", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold uppercase tracking-[0.12em] text-foreground/80", children: section.sourceName }) }),
|
|
931
|
+
section.categories.map((cat) => /* @__PURE__ */ jsx(CategoryBlock, { category: cat, onNavigate }, cat.key))
|
|
932
|
+
] });
|
|
933
|
+
}
|
|
934
|
+
__name(SchemaSection, "SchemaSection");
|
|
935
|
+
function SidebarBody({ body, onNavigate }) {
|
|
936
|
+
if (body.kind === "flat") {
|
|
937
|
+
if (body.categories.length === 0) {
|
|
938
|
+
return /* @__PURE__ */ jsx("div", { className: "py-10 px-4 text-center text-xs text-muted-foreground", children: body.emptyText });
|
|
939
|
+
}
|
|
940
|
+
return /* @__PURE__ */ jsx("nav", { className: "py-1.5", children: body.categories.map((cat) => /* @__PURE__ */ jsx(CategoryBlock, { category: cat, onNavigate }, cat.key)) });
|
|
941
|
+
}
|
|
942
|
+
if (body.sections.length === 0) {
|
|
943
|
+
return /* @__PURE__ */ jsx("div", { className: "py-10 px-4 text-center text-xs text-muted-foreground", children: body.emptyText });
|
|
944
|
+
}
|
|
945
|
+
return /* @__PURE__ */ jsx("nav", { className: "py-1.5", children: body.sections.map((section) => /* @__PURE__ */ jsx(SchemaSection, { section, onNavigate }, section.sourceId)) });
|
|
946
|
+
}
|
|
947
|
+
__name(SidebarBody, "SidebarBody");
|
|
948
|
+
|
|
949
|
+
// src/tools/OpenapiViewer/components/DocsLayout/Sidebar/types.ts
|
|
950
|
+
var METHOD_FILTERS = ["ALL", "GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
951
|
+
function MethodChips({ value, onChange }) {
|
|
952
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 overflow-x-auto -mx-1 px-1 pb-px", children: METHOD_FILTERS.map((m) => {
|
|
953
|
+
const active = value === m;
|
|
954
|
+
return /* @__PURE__ */ jsx(
|
|
955
|
+
"button",
|
|
956
|
+
{
|
|
957
|
+
type: "button",
|
|
958
|
+
onClick: () => onChange(m),
|
|
959
|
+
"aria-pressed": active,
|
|
960
|
+
className: cn(
|
|
961
|
+
"shrink-0 px-2 h-6 rounded font-mono text-[10px] font-semibold tracking-wide uppercase transition-colors",
|
|
962
|
+
active ? "bg-foreground text-background" : "text-muted-foreground/70 hover:text-foreground hover:bg-muted"
|
|
963
|
+
),
|
|
964
|
+
children: m
|
|
965
|
+
},
|
|
966
|
+
m
|
|
967
|
+
);
|
|
968
|
+
}) });
|
|
969
|
+
}
|
|
970
|
+
__name(MethodChips, "MethodChips");
|
|
971
|
+
function SearchInput({ value, onChange, placeholder }) {
|
|
972
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
973
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground/50 pointer-events-none" }),
|
|
974
|
+
/* @__PURE__ */ jsx(
|
|
975
|
+
Input,
|
|
976
|
+
{
|
|
977
|
+
placeholder: placeholder ?? "Search endpoints\u2026",
|
|
978
|
+
value,
|
|
979
|
+
onChange: (e) => onChange(e.target.value),
|
|
980
|
+
className: "pl-8 pr-7 h-8 text-xs"
|
|
981
|
+
}
|
|
982
|
+
),
|
|
983
|
+
value && /* @__PURE__ */ jsx(
|
|
984
|
+
"button",
|
|
985
|
+
{
|
|
986
|
+
type: "button",
|
|
987
|
+
onClick: () => onChange(""),
|
|
988
|
+
"aria-label": "Clear search",
|
|
989
|
+
className: cn(
|
|
990
|
+
"absolute right-1.5 top-1/2 -translate-y-1/2 h-5 w-5 rounded",
|
|
991
|
+
"inline-flex items-center justify-center",
|
|
992
|
+
"text-muted-foreground/50 hover:text-foreground hover:bg-muted transition-colors"
|
|
993
|
+
),
|
|
994
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
|
|
995
|
+
}
|
|
996
|
+
)
|
|
997
|
+
] });
|
|
998
|
+
}
|
|
999
|
+
__name(SearchInput, "SearchInput");
|
|
1000
|
+
function Toolbar({
|
|
1001
|
+
schemas,
|
|
1002
|
+
currentSchemaId,
|
|
1003
|
+
onSchemaChange,
|
|
1004
|
+
showSchemaSelector,
|
|
1005
|
+
search,
|
|
1006
|
+
onSearchChange,
|
|
1007
|
+
methodFilter,
|
|
1008
|
+
onMethodFilterChange
|
|
1009
|
+
}) {
|
|
1010
|
+
const schemaOptions = React12.useMemo(
|
|
1011
|
+
() => schemas.map((s) => ({ value: s.id, label: s.name })),
|
|
1012
|
+
[schemas]
|
|
1013
|
+
);
|
|
1014
|
+
return /* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b px-3 py-2.5 space-y-2", children: [
|
|
1015
|
+
showSchemaSelector && /* @__PURE__ */ jsx(
|
|
1016
|
+
Combobox,
|
|
1017
|
+
{
|
|
1018
|
+
options: schemaOptions,
|
|
1019
|
+
value: currentSchemaId ?? "",
|
|
1020
|
+
onValueChange: (id) => id && onSchemaChange(id),
|
|
1021
|
+
placeholder: "Select API",
|
|
1022
|
+
searchPlaceholder: "Search APIs\u2026",
|
|
1023
|
+
emptyText: "No APIs found",
|
|
1024
|
+
className: "w-full h-8 text-xs"
|
|
1025
|
+
}
|
|
1026
|
+
),
|
|
1027
|
+
/* @__PURE__ */ jsx(SearchInput, { value: search, onChange: onSearchChange }),
|
|
1028
|
+
/* @__PURE__ */ jsx(MethodChips, { value: methodFilter, onChange: onMethodFilterChange })
|
|
1029
|
+
] });
|
|
1030
|
+
}
|
|
1031
|
+
__name(Toolbar, "Toolbar");
|
|
1032
|
+
function useDebouncedValue(value, delayMs = 120) {
|
|
1033
|
+
const [debounced, setDebounced] = useState(value);
|
|
1034
|
+
useEffect(() => {
|
|
1035
|
+
const id = setTimeout(() => setDebounced(value), delayMs);
|
|
1036
|
+
return () => clearTimeout(id);
|
|
1037
|
+
}, [value, delayMs]);
|
|
1038
|
+
return debounced;
|
|
1039
|
+
}
|
|
1040
|
+
__name(useDebouncedValue, "useDebouncedValue");
|
|
1041
|
+
function DocsSidebar({
|
|
1042
|
+
info,
|
|
1043
|
+
endpoints,
|
|
1044
|
+
schemas,
|
|
1045
|
+
currentSchemaId,
|
|
1046
|
+
onSchemaChange,
|
|
1047
|
+
activeEndpointId,
|
|
1048
|
+
selectedVersion,
|
|
1049
|
+
onNavigate,
|
|
1050
|
+
grouping = "selector",
|
|
1051
|
+
endpointsBySchema,
|
|
1052
|
+
rawSchema,
|
|
1053
|
+
resolvedBaseUrl
|
|
1054
|
+
}) {
|
|
1055
|
+
const [search, setSearch] = useState("");
|
|
1056
|
+
const [methodFilter, setMethodFilter] = useState("ALL");
|
|
1057
|
+
const debouncedSearch = useDebouncedValue(search);
|
|
1058
|
+
const body = useMemo(() => {
|
|
1059
|
+
if (grouping === "sections") {
|
|
1060
|
+
return buildSectionsVM(
|
|
1061
|
+
schemas,
|
|
1062
|
+
endpointsBySchema ?? {},
|
|
1063
|
+
selectedVersion,
|
|
1064
|
+
debouncedSearch,
|
|
1065
|
+
methodFilter,
|
|
1066
|
+
activeEndpointId
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
return buildFlatVM(
|
|
1070
|
+
endpoints,
|
|
1071
|
+
selectedVersion,
|
|
1072
|
+
debouncedSearch,
|
|
1073
|
+
methodFilter,
|
|
1074
|
+
activeEndpointId
|
|
1075
|
+
);
|
|
1076
|
+
}, [
|
|
1077
|
+
grouping,
|
|
1078
|
+
schemas,
|
|
1079
|
+
endpointsBySchema,
|
|
1080
|
+
endpoints,
|
|
1081
|
+
selectedVersion,
|
|
1082
|
+
debouncedSearch,
|
|
1083
|
+
methodFilter,
|
|
1084
|
+
activeEndpointId
|
|
1085
|
+
]);
|
|
1086
|
+
const hasMultipleSchemas = schemas.length > 1;
|
|
1087
|
+
const showSchemaSelector = grouping === "selector" && hasMultipleSchemas;
|
|
1088
|
+
return /* @__PURE__ */ jsxs("aside", { className: "flex flex-col h-full min-h-0 border-r bg-muted/10", children: [
|
|
1089
|
+
/* @__PURE__ */ jsx(
|
|
1090
|
+
BrandHeader,
|
|
1091
|
+
{
|
|
1092
|
+
info,
|
|
1093
|
+
endpoints,
|
|
1094
|
+
rawSchema,
|
|
1095
|
+
resolvedBaseUrl
|
|
1096
|
+
}
|
|
1097
|
+
),
|
|
1098
|
+
/* @__PURE__ */ jsx(
|
|
1099
|
+
Toolbar,
|
|
1100
|
+
{
|
|
1101
|
+
schemas,
|
|
1102
|
+
currentSchemaId,
|
|
1103
|
+
onSchemaChange,
|
|
1104
|
+
showSchemaSelector,
|
|
1105
|
+
search,
|
|
1106
|
+
onSearchChange: setSearch,
|
|
1107
|
+
methodFilter,
|
|
1108
|
+
onMethodFilterChange: setMethodFilter
|
|
1109
|
+
}
|
|
1110
|
+
),
|
|
1111
|
+
/* @__PURE__ */ jsx(ScrollArea, { children: /* @__PURE__ */ jsx(SidebarBody, { body, onNavigate }) })
|
|
1112
|
+
] });
|
|
1113
|
+
}
|
|
1114
|
+
__name(DocsSidebar, "DocsSidebar");
|
|
1045
1115
|
|
|
1046
1116
|
// src/tools/OpenapiViewer/utils/scrollParent.ts
|
|
1047
1117
|
function getScrollParent(el) {
|
|
@@ -1079,6 +1149,7 @@ function scrollTargetTo(target, top) {
|
|
|
1079
1149
|
}
|
|
1080
1150
|
__name(scrollTargetTo, "scrollTargetTo");
|
|
1081
1151
|
function ApiIntroSection({ info, schema, endpoints, resolvedBaseUrl }) {
|
|
1152
|
+
const baseUrlRows = resolvedBaseUrl ? [{ url: resolvedBaseUrl, description: info.servers?.[0]?.description }] : (info.servers ?? []).map((s) => ({ url: s.url, description: s.description }));
|
|
1082
1153
|
return /* @__PURE__ */ jsxs("section", { className: "pb-10 mb-10 border-b", children: [
|
|
1083
1154
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 flex-wrap", children: [
|
|
1084
1155
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-wrap min-w-0", children: [
|
|
@@ -1098,105 +1169,775 @@ function ApiIntroSection({ info, schema, endpoints, resolvedBaseUrl }) {
|
|
|
1098
1169
|
)
|
|
1099
1170
|
] }),
|
|
1100
1171
|
info.description && /* @__PURE__ */ jsx("div", { className: "mt-4 text-muted-foreground", children: /* @__PURE__ */ jsx(MarkdownMessage, { content: info.description }) }),
|
|
1101
|
-
|
|
1172
|
+
baseUrlRows.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-6 space-y-2", children: [
|
|
1102
1173
|
/* @__PURE__ */ jsx("h4", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/60", children: "Base URL" }),
|
|
1103
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-1.5", children:
|
|
1104
|
-
/* @__PURE__ */ jsx("code", { className: "font-mono text-xs px-2 py-1 rounded bg-muted border", children:
|
|
1105
|
-
|
|
1106
|
-
] }, `${
|
|
1174
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: baseUrlRows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
|
|
1175
|
+
/* @__PURE__ */ jsx("code", { className: "font-mono text-xs px-2 py-1 rounded bg-muted border", children: row.url }),
|
|
1176
|
+
row.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: row.description })
|
|
1177
|
+
] }, `${row.url}-${i}`)) })
|
|
1107
1178
|
] })
|
|
1108
1179
|
] });
|
|
1109
1180
|
}
|
|
1110
1181
|
__name(ApiIntroSection, "ApiIntroSection");
|
|
1182
|
+
var EndpointDocContext = createContext(null);
|
|
1183
|
+
function EndpointDocProvider({ endpointId, method, children }) {
|
|
1184
|
+
const value = useMemo(() => ({ endpointId, method }), [endpointId, method]);
|
|
1185
|
+
return /* @__PURE__ */ jsx(EndpointDocContext.Provider, { value, children });
|
|
1186
|
+
}
|
|
1187
|
+
__name(EndpointDocProvider, "EndpointDocProvider");
|
|
1188
|
+
function useEndpointDocContext() {
|
|
1189
|
+
const ctx = useContext(EndpointDocContext);
|
|
1190
|
+
if (!ctx) {
|
|
1191
|
+
throw new Error(
|
|
1192
|
+
"[OpenapiViewer] useEndpointDocContext must be used inside <EndpointDocProvider>."
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
return ctx;
|
|
1196
|
+
}
|
|
1197
|
+
__name(useEndpointDocContext, "useEndpointDocContext");
|
|
1198
|
+
var sectionKey = /* @__PURE__ */ __name((endpointId, sectionId) => `${endpointId}:${sectionId}`, "sectionKey");
|
|
1199
|
+
var initialState = {
|
|
1200
|
+
openSections: {},
|
|
1201
|
+
activeCodeTab: {}
|
|
1202
|
+
};
|
|
1203
|
+
var useEndpointDocStore = create()(
|
|
1204
|
+
persist(
|
|
1205
|
+
(set) => ({
|
|
1206
|
+
...initialState,
|
|
1207
|
+
toggleSection: /* @__PURE__ */ __name((endpointId, sectionId) => set((state) => {
|
|
1208
|
+
const key = sectionKey(endpointId, sectionId);
|
|
1209
|
+
const current = state.openSections[key];
|
|
1210
|
+
return {
|
|
1211
|
+
openSections: {
|
|
1212
|
+
...state.openSections,
|
|
1213
|
+
// If there's no explicit override yet, the user's
|
|
1214
|
+
// first click means "flip from the default". We
|
|
1215
|
+
// assume the default was ``true`` for the most
|
|
1216
|
+
// common case (bodies/responses) and ``false``
|
|
1217
|
+
// otherwise; the Section component tracks this
|
|
1218
|
+
// via its ``defaultOpen`` prop and never calls
|
|
1219
|
+
// toggle on sections whose defaults match the
|
|
1220
|
+
// next state.
|
|
1221
|
+
[key]: current === void 0 ? false : !current
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
}), "toggleSection"),
|
|
1225
|
+
setSectionOpen: /* @__PURE__ */ __name((endpointId, sectionId, open) => set((state) => ({
|
|
1226
|
+
openSections: {
|
|
1227
|
+
...state.openSections,
|
|
1228
|
+
[sectionKey(endpointId, sectionId)]: open
|
|
1229
|
+
}
|
|
1230
|
+
})), "setSectionOpen"),
|
|
1231
|
+
setCodeTab: /* @__PURE__ */ __name((endpointId, tab) => set((state) => ({
|
|
1232
|
+
activeCodeTab: {
|
|
1233
|
+
...state.activeCodeTab,
|
|
1234
|
+
[endpointId]: tab
|
|
1235
|
+
}
|
|
1236
|
+
})), "setCodeTab"),
|
|
1237
|
+
expandAll: /* @__PURE__ */ __name((endpointId, sectionIds) => set((state) => {
|
|
1238
|
+
const next = { ...state.openSections };
|
|
1239
|
+
for (const sid of sectionIds) {
|
|
1240
|
+
next[sectionKey(endpointId, sid)] = true;
|
|
1241
|
+
}
|
|
1242
|
+
return { openSections: next };
|
|
1243
|
+
}), "expandAll"),
|
|
1244
|
+
collapseAll: /* @__PURE__ */ __name((endpointId, sectionIds) => set((state) => {
|
|
1245
|
+
const next = { ...state.openSections };
|
|
1246
|
+
for (const sid of sectionIds) {
|
|
1247
|
+
next[sectionKey(endpointId, sid)] = false;
|
|
1248
|
+
}
|
|
1249
|
+
return { openSections: next };
|
|
1250
|
+
}), "collapseAll")
|
|
1251
|
+
}),
|
|
1252
|
+
{
|
|
1253
|
+
name: "openapi-viewer:endpoint-doc",
|
|
1254
|
+
storage: createJSONStorage(() => {
|
|
1255
|
+
if (typeof window === "undefined") {
|
|
1256
|
+
return {
|
|
1257
|
+
getItem: /* @__PURE__ */ __name(() => null, "getItem"),
|
|
1258
|
+
setItem: /* @__PURE__ */ __name(() => {
|
|
1259
|
+
}, "setItem"),
|
|
1260
|
+
removeItem: /* @__PURE__ */ __name(() => {
|
|
1261
|
+
}, "removeItem")
|
|
1262
|
+
};
|
|
1263
|
+
}
|
|
1264
|
+
return window.sessionStorage;
|
|
1265
|
+
}),
|
|
1266
|
+
// Only persist user overrides, not the functions. Zustand
|
|
1267
|
+
// serialises everything by default and logs a warning on
|
|
1268
|
+
// non-serialisable values; partialize keeps the payload lean.
|
|
1269
|
+
partialize: /* @__PURE__ */ __name((state) => ({
|
|
1270
|
+
openSections: state.openSections,
|
|
1271
|
+
activeCodeTab: state.activeCodeTab
|
|
1272
|
+
}), "partialize")
|
|
1273
|
+
}
|
|
1274
|
+
)
|
|
1275
|
+
);
|
|
1276
|
+
|
|
1277
|
+
// src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/store/selectors.ts
|
|
1278
|
+
function useIsSectionOpen(endpointId, sectionId, defaultOpen) {
|
|
1279
|
+
return useEndpointDocStore((s) => {
|
|
1280
|
+
const explicit = s.openSections[sectionKey(endpointId, sectionId)];
|
|
1281
|
+
return explicit === void 0 ? defaultOpen : explicit;
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
__name(useIsSectionOpen, "useIsSectionOpen");
|
|
1285
|
+
function useActiveCodeTab(endpointId, fallback = "curl") {
|
|
1286
|
+
return useEndpointDocStore((s) => s.activeCodeTab[endpointId] ?? fallback);
|
|
1287
|
+
}
|
|
1288
|
+
__name(useActiveCodeTab, "useActiveCodeTab");
|
|
1289
|
+
function LanguageTabs({ activeId, onChange }) {
|
|
1290
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 overflow-x-auto -mx-1 px-1", children: CODE_SAMPLE_TARGETS.map((t) => /* @__PURE__ */ jsx(
|
|
1291
|
+
"button",
|
|
1292
|
+
{
|
|
1293
|
+
type: "button",
|
|
1294
|
+
onClick: () => onChange(t.id),
|
|
1295
|
+
className: cn(
|
|
1296
|
+
"shrink-0 h-7 px-2.5 rounded text-xs font-medium transition-colors",
|
|
1297
|
+
activeId === t.id ? "bg-muted text-foreground" : "text-muted-foreground/70 hover:text-foreground hover:bg-muted/50"
|
|
1298
|
+
),
|
|
1299
|
+
children: t.label
|
|
1300
|
+
},
|
|
1301
|
+
t.id
|
|
1302
|
+
)) });
|
|
1303
|
+
}
|
|
1304
|
+
__name(LanguageTabs, "LanguageTabs");
|
|
1305
|
+
function useCodeSnippet({
|
|
1306
|
+
endpoint,
|
|
1307
|
+
body,
|
|
1308
|
+
parameters,
|
|
1309
|
+
headers,
|
|
1310
|
+
baseUrl,
|
|
1311
|
+
activeId
|
|
1312
|
+
}) {
|
|
1313
|
+
const effectiveBody = body ?? endpoint.requestBody?.example;
|
|
1314
|
+
const har = useMemo(() => {
|
|
1315
|
+
const h = buildHarRequest({
|
|
1316
|
+
endpoint,
|
|
1317
|
+
body: effectiveBody,
|
|
1318
|
+
parameters,
|
|
1319
|
+
headers,
|
|
1320
|
+
baseUrl
|
|
1321
|
+
});
|
|
1322
|
+
return baseUrl ? h : { ...h, url: resolveAbsolute(h.url) };
|
|
1323
|
+
}, [endpoint, effectiveBody, parameters, headers, baseUrl]);
|
|
1324
|
+
return useMemo(() => {
|
|
1325
|
+
const target = CODE_SAMPLE_TARGETS.find((t) => t.id === activeId);
|
|
1326
|
+
const code = renderSnippet(har, activeId);
|
|
1327
|
+
return {
|
|
1328
|
+
snippet: code ?? `// Snippet for ${target.label} is unavailable for this request.`,
|
|
1329
|
+
prism: target.prism
|
|
1330
|
+
};
|
|
1331
|
+
}, [har, activeId]);
|
|
1332
|
+
}
|
|
1333
|
+
__name(useCodeSnippet, "useCodeSnippet");
|
|
1334
|
+
function CodeSamples({ endpoint, body, parameters, headers, baseUrl }) {
|
|
1335
|
+
const { endpointId } = useEndpointDocContext();
|
|
1336
|
+
const activeId = useActiveCodeTab(endpointId);
|
|
1337
|
+
const setCodeTab = useEndpointDocStore((s) => s.setCodeTab);
|
|
1338
|
+
const { snippet, prism } = useCodeSnippet({
|
|
1339
|
+
endpoint,
|
|
1340
|
+
body,
|
|
1341
|
+
parameters,
|
|
1342
|
+
headers,
|
|
1343
|
+
baseUrl,
|
|
1344
|
+
activeId
|
|
1345
|
+
});
|
|
1346
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2.5", children: [
|
|
1347
|
+
/* @__PURE__ */ jsx(LanguageTabs, { activeId, onChange: (id) => setCodeTab(endpointId, id) }),
|
|
1348
|
+
/* @__PURE__ */ jsx(
|
|
1349
|
+
PrettyCode_default,
|
|
1350
|
+
{
|
|
1351
|
+
data: snippet,
|
|
1352
|
+
language: prism,
|
|
1353
|
+
isCompact: true,
|
|
1354
|
+
maxLines: 20
|
|
1355
|
+
}
|
|
1356
|
+
)
|
|
1357
|
+
] });
|
|
1358
|
+
}
|
|
1359
|
+
__name(CodeSamples, "CodeSamples");
|
|
1360
|
+
function IconButton({ label, onClick, children, active }) {
|
|
1361
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
1362
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
1363
|
+
"button",
|
|
1364
|
+
{
|
|
1365
|
+
type: "button",
|
|
1366
|
+
onClick,
|
|
1367
|
+
"aria-label": label,
|
|
1368
|
+
className: cn(
|
|
1369
|
+
"shrink-0 h-6 w-6 inline-flex items-center justify-center rounded",
|
|
1370
|
+
"text-muted-foreground/60 hover:text-foreground hover:bg-muted transition-colors",
|
|
1371
|
+
active && "text-emerald-500 hover:text-emerald-500"
|
|
1372
|
+
),
|
|
1373
|
+
children
|
|
1374
|
+
}
|
|
1375
|
+
) }),
|
|
1376
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "bottom", className: "text-[11px]", children: label })
|
|
1377
|
+
] });
|
|
1378
|
+
}
|
|
1379
|
+
__name(IconButton, "IconButton");
|
|
1380
|
+
function MetaActions({ anchor, endpointMarkdown, presentSections }) {
|
|
1381
|
+
const { endpointId } = useEndpointDocContext();
|
|
1382
|
+
const expandAll = useEndpointDocStore((s) => s.expandAll);
|
|
1383
|
+
const collapseAll = useEndpointDocStore((s) => s.collapseAll);
|
|
1384
|
+
const openSections = useEndpointDocStore((s) => s.openSections);
|
|
1385
|
+
const [justCopied, setJustCopied] = useState(null);
|
|
1386
|
+
const flash = useCallback((which) => {
|
|
1387
|
+
setJustCopied(which);
|
|
1388
|
+
setTimeout(() => setJustCopied(null), 1200);
|
|
1389
|
+
}, []);
|
|
1390
|
+
const mostlyOpen = useMemo(() => {
|
|
1391
|
+
if (presentSections.length === 0) return false;
|
|
1392
|
+
let openCount = 0;
|
|
1393
|
+
for (const sid of presentSections) {
|
|
1394
|
+
if (openSections[sectionKey(endpointId, sid)]) openCount += 1;
|
|
1395
|
+
}
|
|
1396
|
+
return openCount > presentSections.length / 2;
|
|
1397
|
+
}, [openSections, presentSections, endpointId]);
|
|
1398
|
+
const copyLink = useCallback(() => {
|
|
1399
|
+
if (typeof window === "undefined") return;
|
|
1400
|
+
const url = `${window.location.origin}${window.location.pathname}#${anchor}`;
|
|
1401
|
+
void navigator.clipboard?.writeText(url).then(() => flash("link"));
|
|
1402
|
+
}, [anchor, flash]);
|
|
1403
|
+
const copyMarkdown = useCallback(() => {
|
|
1404
|
+
if (typeof window === "undefined") return;
|
|
1405
|
+
void navigator.clipboard?.writeText(endpointMarkdown).then(() => flash("md"));
|
|
1406
|
+
}, [endpointMarkdown, flash]);
|
|
1407
|
+
const toggleAll = useCallback(() => {
|
|
1408
|
+
if (mostlyOpen) collapseAll(endpointId, presentSections);
|
|
1409
|
+
else expandAll(endpointId, presentSections);
|
|
1410
|
+
}, [mostlyOpen, collapseAll, expandAll, endpointId, presentSections]);
|
|
1411
|
+
return /* @__PURE__ */ jsx(SafeTooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
|
|
1412
|
+
/* @__PURE__ */ jsx(
|
|
1413
|
+
IconButton,
|
|
1414
|
+
{
|
|
1415
|
+
label: justCopied === "link" ? "Copied!" : "Copy link to endpoint",
|
|
1416
|
+
onClick: copyLink,
|
|
1417
|
+
active: justCopied === "link",
|
|
1418
|
+
children: justCopied === "link" ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5" })
|
|
1419
|
+
}
|
|
1420
|
+
),
|
|
1421
|
+
/* @__PURE__ */ jsx(
|
|
1422
|
+
IconButton,
|
|
1423
|
+
{
|
|
1424
|
+
label: justCopied === "md" ? "Copied!" : "Copy as Markdown (for AI)",
|
|
1425
|
+
onClick: copyMarkdown,
|
|
1426
|
+
active: justCopied === "md",
|
|
1427
|
+
children: justCopied === "md" ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(FileCode2, { className: "h-3.5 w-3.5" })
|
|
1428
|
+
}
|
|
1429
|
+
),
|
|
1430
|
+
presentSections.length >= 2 && /* @__PURE__ */ jsx(
|
|
1431
|
+
IconButton,
|
|
1432
|
+
{
|
|
1433
|
+
label: mostlyOpen ? "Collapse all sections" : "Expand all sections",
|
|
1434
|
+
onClick: toggleAll,
|
|
1435
|
+
children: mostlyOpen ? /* @__PURE__ */ jsx(ChevronsDownUp, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(ChevronsUpDown, { className: "h-3.5 w-3.5" })
|
|
1436
|
+
}
|
|
1437
|
+
)
|
|
1438
|
+
] }) });
|
|
1439
|
+
}
|
|
1440
|
+
__name(MetaActions, "MetaActions");
|
|
1441
|
+
function PathDisplay({ path }) {
|
|
1442
|
+
return /* @__PURE__ */ jsx(
|
|
1443
|
+
"code",
|
|
1444
|
+
{
|
|
1445
|
+
className: "block font-mono text-lg md:text-xl font-semibold text-foreground leading-tight",
|
|
1446
|
+
style: { overflowWrap: "anywhere", wordBreak: "break-word" },
|
|
1447
|
+
children: relativePath(path)
|
|
1448
|
+
}
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
__name(PathDisplay, "PathDisplay");
|
|
1452
|
+
function EndpointHeader({
|
|
1453
|
+
endpoint,
|
|
1454
|
+
anchor,
|
|
1455
|
+
isLoadedInPlayground,
|
|
1456
|
+
onTryIt,
|
|
1457
|
+
presentSections
|
|
1458
|
+
}) {
|
|
1459
|
+
const endpointMd = useMemo(() => endpointToMarkdown(endpoint), [endpoint]);
|
|
1460
|
+
return /* @__PURE__ */ jsxs("header", { className: "space-y-3", children: [
|
|
1461
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [
|
|
1462
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
1463
|
+
/* @__PURE__ */ jsx(MethodBadge, { method: endpoint.method }),
|
|
1464
|
+
/* @__PURE__ */ jsx(
|
|
1465
|
+
MetaActions,
|
|
1466
|
+
{
|
|
1467
|
+
anchor,
|
|
1468
|
+
endpointMarkdown: endpointMd,
|
|
1469
|
+
presentSections
|
|
1470
|
+
}
|
|
1471
|
+
)
|
|
1472
|
+
] }),
|
|
1473
|
+
/* @__PURE__ */ jsxs(
|
|
1474
|
+
Button,
|
|
1475
|
+
{
|
|
1476
|
+
size: "sm",
|
|
1477
|
+
variant: isLoadedInPlayground ? "secondary" : "default",
|
|
1478
|
+
onClick: onTryIt,
|
|
1479
|
+
className: "ml-auto h-7 text-xs gap-1.5 px-2.5",
|
|
1480
|
+
children: [
|
|
1481
|
+
/* @__PURE__ */ jsx(Play, { className: "h-3 w-3" }),
|
|
1482
|
+
isLoadedInPlayground ? "Loaded" : "Try it"
|
|
1483
|
+
]
|
|
1484
|
+
}
|
|
1485
|
+
)
|
|
1486
|
+
] }),
|
|
1487
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsx(PathDisplay, { path: endpoint.path }) }),
|
|
1488
|
+
endpoint.description && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: /* @__PURE__ */ jsx(MarkdownMessage, { content: endpoint.description }) })
|
|
1489
|
+
] });
|
|
1490
|
+
}
|
|
1491
|
+
__name(EndpointHeader, "EndpointHeader");
|
|
1492
|
+
function ParamRow({ param }) {
|
|
1493
|
+
return /* @__PURE__ */ jsxs("div", { className: "px-3 py-2.5 bg-background space-y-1", children: [
|
|
1494
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
|
|
1495
|
+
/* @__PURE__ */ jsx("code", { className: "font-mono text-xs font-medium text-foreground", children: param.name }),
|
|
1496
|
+
param.required && /* @__PURE__ */ jsx(
|
|
1497
|
+
"span",
|
|
1498
|
+
{
|
|
1499
|
+
title: "Required",
|
|
1500
|
+
className: "text-[9px] text-destructive font-bold leading-none",
|
|
1501
|
+
children: "*"
|
|
1502
|
+
}
|
|
1503
|
+
),
|
|
1504
|
+
/* @__PURE__ */ jsx("code", { className: "font-mono text-[11px] text-muted-foreground/70", children: param.type })
|
|
1505
|
+
] }),
|
|
1506
|
+
param.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground leading-relaxed break-words", children: param.description })
|
|
1507
|
+
] });
|
|
1508
|
+
}
|
|
1509
|
+
__name(ParamRow, "ParamRow");
|
|
1510
|
+
function ParamGroup({ label, params }) {
|
|
1511
|
+
if (params.length === 0) return null;
|
|
1512
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
1513
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-semibold uppercase tracking-[0.1em] text-muted-foreground/60 px-1", children: label }),
|
|
1514
|
+
/* @__PURE__ */ jsx("div", { className: "divide-y border rounded-md overflow-hidden", children: params.map((p) => /* @__PURE__ */ jsx(ParamRow, { param: p }, `${label}-${p.name}`)) })
|
|
1515
|
+
] });
|
|
1516
|
+
}
|
|
1517
|
+
__name(ParamGroup, "ParamGroup");
|
|
1518
|
+
function Parameters({ pathParams, queryParams }) {
|
|
1519
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1520
|
+
/* @__PURE__ */ jsx(ParamGroup, { label: "Path", params: pathParams }),
|
|
1521
|
+
/* @__PURE__ */ jsx(ParamGroup, { label: "Query", params: queryParams })
|
|
1522
|
+
] });
|
|
1523
|
+
}
|
|
1524
|
+
__name(Parameters, "Parameters");
|
|
1111
1525
|
|
|
1112
|
-
// src/tools/OpenapiViewer/components/DocsLayout/
|
|
1113
|
-
var MAX_DEPTH =
|
|
1526
|
+
// src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/SchemaFields/buildTree.ts
|
|
1527
|
+
var MAX_DEPTH = 5;
|
|
1528
|
+
function mergeAllOf(branches) {
|
|
1529
|
+
const properties = {};
|
|
1530
|
+
const required = [];
|
|
1531
|
+
for (const b of branches) {
|
|
1532
|
+
if (b.properties) Object.assign(properties, b.properties);
|
|
1533
|
+
if (Array.isArray(b.required)) required.push(...b.required);
|
|
1534
|
+
}
|
|
1535
|
+
return { type: "object", properties, required };
|
|
1536
|
+
}
|
|
1537
|
+
__name(mergeAllOf, "mergeAllOf");
|
|
1114
1538
|
function describeType(node) {
|
|
1115
|
-
if (
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1539
|
+
if (node.type === "array") {
|
|
1540
|
+
const itemLabel = node.items ? describeType(node.items).label : "any";
|
|
1541
|
+
return { label: `array<${itemLabel}>`, kind: "array" };
|
|
1542
|
+
}
|
|
1543
|
+
if (node.type === "object" || node.properties) {
|
|
1544
|
+
return { label: "object", kind: "object" };
|
|
1120
1545
|
}
|
|
1546
|
+
const base = node.type || "any";
|
|
1121
1547
|
if (Array.isArray(node.enum) && node.enum.length > 0) {
|
|
1122
|
-
return `${base} enum
|
|
1548
|
+
return { label: `${base} enum`, kind: "primitive" };
|
|
1549
|
+
}
|
|
1550
|
+
if (node.format) {
|
|
1551
|
+
return { label: `${base} (${node.format})`, kind: "primitive" };
|
|
1123
1552
|
}
|
|
1124
|
-
|
|
1125
|
-
return base;
|
|
1553
|
+
return { label: base, kind: "primitive" };
|
|
1126
1554
|
}
|
|
1127
1555
|
__name(describeType, "describeType");
|
|
1128
|
-
function
|
|
1129
|
-
if (
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1556
|
+
function resolveCombinators(node) {
|
|
1557
|
+
if (Array.isArray(node.allOf) && node.allOf.length > 0) {
|
|
1558
|
+
return { ...mergeAllOf(node.allOf), description: node.description };
|
|
1559
|
+
}
|
|
1560
|
+
if (Array.isArray(node.oneOf) && node.oneOf.length > 0) {
|
|
1561
|
+
return { ...node.oneOf[0], description: node.description ?? node.oneOf[0].description };
|
|
1562
|
+
}
|
|
1563
|
+
if (Array.isArray(node.anyOf) && node.anyOf.length > 0) {
|
|
1564
|
+
return { ...node.anyOf[0], description: node.description ?? node.anyOf[0].description };
|
|
1565
|
+
}
|
|
1566
|
+
return node;
|
|
1567
|
+
}
|
|
1568
|
+
__name(resolveCombinators, "resolveCombinators");
|
|
1569
|
+
function buildNode(name, schema, isRequired, depth) {
|
|
1570
|
+
const resolved = resolveCombinators(schema);
|
|
1571
|
+
const { label, kind } = describeType(resolved);
|
|
1572
|
+
const node = {
|
|
1573
|
+
name,
|
|
1574
|
+
type: label,
|
|
1575
|
+
kind,
|
|
1576
|
+
required: isRequired,
|
|
1577
|
+
description: resolved.description
|
|
1578
|
+
};
|
|
1579
|
+
if (Array.isArray(resolved.enum) && resolved.enum.length > 0) {
|
|
1580
|
+
node.enumValues = resolved.enum.map((v) => String(v));
|
|
1581
|
+
}
|
|
1582
|
+
if (depth >= MAX_DEPTH) return node;
|
|
1583
|
+
if (kind === "object" && resolved.properties) {
|
|
1584
|
+
const required = new Set(resolved.required ?? []);
|
|
1585
|
+
node.children = Object.entries(resolved.properties).map(
|
|
1586
|
+
([key, child]) => buildNode(key, child, required.has(key), depth + 1)
|
|
1587
|
+
);
|
|
1588
|
+
} else if (kind === "array" && resolved.items) {
|
|
1589
|
+
node.children = [buildNode("[]", resolved.items, false, depth + 1)];
|
|
1590
|
+
}
|
|
1591
|
+
return node;
|
|
1592
|
+
}
|
|
1593
|
+
__name(buildNode, "buildNode");
|
|
1594
|
+
function buildSchemaTree(schema) {
|
|
1595
|
+
if (!schema) return [];
|
|
1596
|
+
const root = buildNode("", schema, false, 0);
|
|
1597
|
+
if (root.children && root.children.length > 0) return root.children;
|
|
1598
|
+
if (root.kind === "primitive" || !root.children && root.name === "") {
|
|
1599
|
+
return [{ ...root, name: root.name || "(body)" }];
|
|
1600
|
+
}
|
|
1601
|
+
return [];
|
|
1602
|
+
}
|
|
1603
|
+
__name(buildSchemaTree, "buildSchemaTree");
|
|
1604
|
+
function FieldRow({ field, depth, showTreeLine = true }) {
|
|
1605
|
+
const isExpandable = (field.kind === "object" || field.kind === "array") && Array.isArray(field.children) && field.children.length > 0;
|
|
1606
|
+
const [open, setOpen] = useState(depth < 2);
|
|
1607
|
+
const padLeft = showTreeLine ? depth * 14 : 0;
|
|
1608
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-background", children: [
|
|
1609
|
+
/* @__PURE__ */ jsxs(
|
|
1610
|
+
"div",
|
|
1611
|
+
{
|
|
1612
|
+
className: cn(
|
|
1613
|
+
"grid grid-cols-[16px_minmax(0,1fr)] items-baseline gap-2 px-3 py-2",
|
|
1614
|
+
isExpandable && "cursor-pointer hover:bg-muted/30"
|
|
1615
|
+
),
|
|
1616
|
+
style: { paddingLeft: 12 + padLeft },
|
|
1617
|
+
onClick: () => isExpandable && setOpen((v) => !v),
|
|
1618
|
+
role: isExpandable ? "button" : void 0,
|
|
1619
|
+
"aria-expanded": isExpandable ? open : void 0,
|
|
1620
|
+
children: [
|
|
1621
|
+
/* @__PURE__ */ jsx(
|
|
1622
|
+
ChevronRight,
|
|
1623
|
+
{
|
|
1624
|
+
className: cn(
|
|
1625
|
+
"h-3.5 w-3.5 text-muted-foreground/50 shrink-0 transition-transform",
|
|
1626
|
+
!isExpandable && "opacity-0",
|
|
1627
|
+
open && "rotate-90"
|
|
1628
|
+
)
|
|
1629
|
+
}
|
|
1630
|
+
),
|
|
1631
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-1", children: [
|
|
1632
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
|
|
1633
|
+
/* @__PURE__ */ jsx("code", { className: "font-mono text-xs font-medium text-foreground", children: field.name }),
|
|
1634
|
+
field.required && /* @__PURE__ */ jsx(
|
|
1635
|
+
"span",
|
|
1636
|
+
{
|
|
1637
|
+
title: "Required",
|
|
1638
|
+
className: "text-[9px] text-destructive font-bold leading-none",
|
|
1639
|
+
children: "*"
|
|
1640
|
+
}
|
|
1641
|
+
),
|
|
1642
|
+
/* @__PURE__ */ jsx("code", { className: "font-mono text-[11px] text-muted-foreground/70", children: field.type })
|
|
1643
|
+
] }),
|
|
1644
|
+
field.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground leading-relaxed break-words", children: field.description }),
|
|
1645
|
+
field.enumValues && field.enumValues.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 pt-0.5", children: field.enumValues.map((v) => /* @__PURE__ */ jsx(
|
|
1646
|
+
"code",
|
|
1647
|
+
{
|
|
1648
|
+
className: "inline-flex items-center rounded border border-border/60 bg-muted/40 px-1.5 py-px font-mono text-[10px] text-muted-foreground",
|
|
1649
|
+
children: v
|
|
1650
|
+
},
|
|
1651
|
+
v
|
|
1652
|
+
)) })
|
|
1653
|
+
] })
|
|
1654
|
+
]
|
|
1655
|
+
}
|
|
1656
|
+
),
|
|
1657
|
+
isExpandable && open && /* @__PURE__ */ jsx("div", { children: field.children.map((child, i) => /* @__PURE__ */ jsx(
|
|
1658
|
+
FieldRow,
|
|
1659
|
+
{
|
|
1660
|
+
field: child,
|
|
1661
|
+
depth: depth + 1
|
|
1662
|
+
},
|
|
1663
|
+
`${child.name}-${i}`
|
|
1664
|
+
)) })
|
|
1665
|
+
] });
|
|
1666
|
+
}
|
|
1667
|
+
__name(FieldRow, "FieldRow");
|
|
1668
|
+
function SchemaFields({ schema }) {
|
|
1669
|
+
const tree = useMemo(() => buildSchemaTree(schema), [schema]);
|
|
1670
|
+
if (tree.length === 0) return null;
|
|
1671
|
+
return /* @__PURE__ */ jsx("div", { className: "divide-y border rounded-md overflow-hidden", children: tree.map((node, i) => /* @__PURE__ */ jsx(FieldRow, { field: node, depth: 0 }, `${node.name}-${i}`)) });
|
|
1672
|
+
}
|
|
1673
|
+
__name(SchemaFields, "SchemaFields");
|
|
1674
|
+
function RequestBody({ body }) {
|
|
1675
|
+
const typeLabel = body.schema ? body.type === "array" ? `array<${body.schema.items?.type ?? "object"}>` : body.type : body.type;
|
|
1676
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
1677
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
|
|
1678
|
+
/* @__PURE__ */ jsx("code", { className: "font-mono text-[11px] text-muted-foreground/80", children: typeLabel }),
|
|
1679
|
+
body.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: body.description })
|
|
1680
|
+
] }),
|
|
1681
|
+
body.schema && /* @__PURE__ */ jsx(SchemaFields, { schema: body.schema })
|
|
1682
|
+
] });
|
|
1683
|
+
}
|
|
1684
|
+
__name(RequestBody, "RequestBody");
|
|
1685
|
+
var EXAMPLE_JSON_TREE_CONFIG = {
|
|
1686
|
+
maxAutoExpandDepth: 2,
|
|
1687
|
+
maxAutoExpandArrayItems: 5,
|
|
1688
|
+
maxAutoExpandObjectKeys: 8,
|
|
1689
|
+
maxStringLength: 160,
|
|
1690
|
+
collectionLimit: 25,
|
|
1691
|
+
showCollectionInfo: true,
|
|
1692
|
+
showExpandControls: false,
|
|
1693
|
+
showActionButtons: false,
|
|
1694
|
+
preserveKeyOrder: true,
|
|
1695
|
+
className: "border-0 rounded-none"
|
|
1696
|
+
};
|
|
1697
|
+
function ResponseBody({ example, contentType }) {
|
|
1698
|
+
const parsed = useMemo(() => {
|
|
1699
|
+
try {
|
|
1700
|
+
return JSON.parse(example);
|
|
1701
|
+
} catch {
|
|
1702
|
+
return null;
|
|
1133
1703
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1704
|
+
}, [example]);
|
|
1705
|
+
return /* @__PURE__ */ jsxs("div", { className: "border-t bg-muted/20", children: [
|
|
1706
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-1.5 border-b border-border/50", children: [
|
|
1707
|
+
/* @__PURE__ */ jsx("code", { className: "font-mono text-[10px] uppercase tracking-wider text-muted-foreground/70", children: contentType ?? "application/json" }),
|
|
1708
|
+
/* @__PURE__ */ jsx(
|
|
1709
|
+
CopyButton,
|
|
1137
1710
|
{
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1711
|
+
value: example,
|
|
1712
|
+
variant: "ghost",
|
|
1713
|
+
size: "sm",
|
|
1714
|
+
className: "h-6 px-2 text-[10px] text-muted-foreground",
|
|
1715
|
+
children: "Copy"
|
|
1142
1716
|
}
|
|
1143
|
-
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
if (schema.type !== "object" && !schema.properties) {
|
|
1148
|
-
return [
|
|
1717
|
+
)
|
|
1718
|
+
] }),
|
|
1719
|
+
parsed != null ? /* @__PURE__ */ jsx(
|
|
1720
|
+
JsonTree_default,
|
|
1149
1721
|
{
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1722
|
+
title: "",
|
|
1723
|
+
data: parsed,
|
|
1724
|
+
mode: "compact",
|
|
1725
|
+
config: EXAMPLE_JSON_TREE_CONFIG
|
|
1154
1726
|
}
|
|
1155
|
-
]
|
|
1727
|
+
) : /* @__PURE__ */ jsx("pre", { className: "p-3 text-[11px] font-mono text-foreground/70 whitespace-pre-wrap break-all leading-relaxed", children: example })
|
|
1728
|
+
] });
|
|
1729
|
+
}
|
|
1730
|
+
__name(ResponseBody, "ResponseBody");
|
|
1731
|
+
function StatusTag({ code }) {
|
|
1732
|
+
const numeric = Number.parseInt(code, 10);
|
|
1733
|
+
const cls = !Number.isFinite(numeric) ? "bg-muted text-muted-foreground border-border" : numeric >= 500 ? "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/25" : numeric >= 400 ? "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/25" : numeric >= 300 ? "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/25" : "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/25";
|
|
1734
|
+
return /* @__PURE__ */ jsx("span", { className: cn(
|
|
1735
|
+
"inline-flex items-center justify-center rounded border px-2 py-0.5 font-mono text-[11px] font-bold leading-none shrink-0 tabular-nums",
|
|
1736
|
+
cls
|
|
1737
|
+
), children: code });
|
|
1738
|
+
}
|
|
1739
|
+
__name(StatusTag, "StatusTag");
|
|
1740
|
+
function ResponseRow({ response }) {
|
|
1741
|
+
const hasExample = Boolean(response.example);
|
|
1742
|
+
const numeric = Number.parseInt(response.code, 10);
|
|
1743
|
+
const isSuccess = Number.isFinite(numeric) && numeric >= 200 && numeric < 300;
|
|
1744
|
+
const [open, setOpen] = useState(hasExample && isSuccess);
|
|
1745
|
+
if (!hasExample) {
|
|
1746
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-3 py-2 bg-background", children: [
|
|
1747
|
+
/* @__PURE__ */ jsx("div", { className: "w-12 shrink-0 flex justify-start", children: /* @__PURE__ */ jsx(StatusTag, { code: response.code }) }),
|
|
1748
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground leading-relaxed break-words min-w-0", children: response.description })
|
|
1749
|
+
] });
|
|
1156
1750
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1751
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-background", children: [
|
|
1752
|
+
/* @__PURE__ */ jsxs(
|
|
1753
|
+
"button",
|
|
1754
|
+
{
|
|
1755
|
+
type: "button",
|
|
1756
|
+
onClick: () => setOpen((v) => !v),
|
|
1757
|
+
className: "w-full flex items-center gap-3 px-3 py-2 text-left hover:bg-muted/40 cursor-pointer transition-colors",
|
|
1758
|
+
"aria-expanded": open,
|
|
1759
|
+
children: [
|
|
1760
|
+
/* @__PURE__ */ jsx(
|
|
1761
|
+
ChevronRight,
|
|
1762
|
+
{
|
|
1763
|
+
className: cn(
|
|
1764
|
+
"h-3.5 w-3.5 text-muted-foreground/60 transition-transform shrink-0",
|
|
1765
|
+
open && "rotate-90"
|
|
1766
|
+
)
|
|
1767
|
+
}
|
|
1768
|
+
),
|
|
1769
|
+
/* @__PURE__ */ jsx("div", { className: "w-12 shrink-0 flex justify-start", children: /* @__PURE__ */ jsx(StatusTag, { code: response.code }) }),
|
|
1770
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground leading-relaxed break-words min-w-0 flex-1", children: response.description })
|
|
1771
|
+
]
|
|
1772
|
+
}
|
|
1773
|
+
),
|
|
1774
|
+
open && /* @__PURE__ */ jsx(
|
|
1775
|
+
ResponseBody,
|
|
1776
|
+
{
|
|
1777
|
+
example: response.example,
|
|
1778
|
+
contentType: response.contentType
|
|
1779
|
+
}
|
|
1780
|
+
)
|
|
1781
|
+
] });
|
|
1782
|
+
}
|
|
1783
|
+
__name(ResponseRow, "ResponseRow");
|
|
1784
|
+
function Responses({ responses }) {
|
|
1785
|
+
return /* @__PURE__ */ jsx("div", { className: "divide-y border rounded-md overflow-hidden", children: responses.map((r) => /* @__PURE__ */ jsx(ResponseRow, { response: r }, r.code)) });
|
|
1786
|
+
}
|
|
1787
|
+
__name(Responses, "Responses");
|
|
1788
|
+
|
|
1789
|
+
// src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Section/defaults.ts
|
|
1790
|
+
var DEFAULTS_BY_METHOD = {
|
|
1791
|
+
GET: { parameters: true, responses: true },
|
|
1792
|
+
DELETE: { parameters: true, responses: true },
|
|
1793
|
+
POST: { requestBody: true, responses: true },
|
|
1794
|
+
PUT: { requestBody: true, responses: true },
|
|
1795
|
+
PATCH: { requestBody: true, responses: true }
|
|
1796
|
+
};
|
|
1797
|
+
function defaultSectionOpen(method, sectionId) {
|
|
1798
|
+
return DEFAULTS_BY_METHOD[method.toUpperCase()]?.[sectionId] ?? false;
|
|
1799
|
+
}
|
|
1800
|
+
__name(defaultSectionOpen, "defaultSectionOpen");
|
|
1801
|
+
|
|
1802
|
+
// src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/types.ts
|
|
1803
|
+
var ALL_SECTION_IDS = [
|
|
1804
|
+
"parameters",
|
|
1805
|
+
"requestBody",
|
|
1806
|
+
"responses",
|
|
1807
|
+
"codeSamples"
|
|
1808
|
+
];
|
|
1809
|
+
|
|
1810
|
+
// src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/hooks/useSectionHash.ts
|
|
1811
|
+
function parseSectionHash(hash) {
|
|
1812
|
+
const raw = hash.startsWith("#") ? hash.slice(1) : hash;
|
|
1813
|
+
if (!raw.startsWith("section=")) return null;
|
|
1814
|
+
const value = raw.slice("section=".length);
|
|
1815
|
+
const dot = value.lastIndexOf(".");
|
|
1816
|
+
if (dot <= 0 || dot === value.length - 1) return null;
|
|
1817
|
+
const endpointId = value.slice(0, dot);
|
|
1818
|
+
const sectionIdCandidate = value.slice(dot + 1);
|
|
1819
|
+
if (!ALL_SECTION_IDS.includes(sectionIdCandidate)) return null;
|
|
1820
|
+
return { endpointId, sectionId: sectionIdCandidate };
|
|
1821
|
+
}
|
|
1822
|
+
__name(parseSectionHash, "parseSectionHash");
|
|
1823
|
+
function buildSectionHash(endpointId, sectionId) {
|
|
1824
|
+
return `section=${endpointId}.${sectionId}`;
|
|
1825
|
+
}
|
|
1826
|
+
__name(buildSectionHash, "buildSectionHash");
|
|
1827
|
+
function useSectionHashRouter() {
|
|
1828
|
+
const setSectionOpen = useEndpointDocStore((s) => s.setSectionOpen);
|
|
1829
|
+
useEffect(() => {
|
|
1830
|
+
if (typeof window === "undefined") return;
|
|
1831
|
+
function apply() {
|
|
1832
|
+
const parsed = parseSectionHash(window.location.hash);
|
|
1833
|
+
if (!parsed) return;
|
|
1834
|
+
setSectionOpen(parsed.endpointId, parsed.sectionId, true);
|
|
1835
|
+
requestAnimationFrame(() => {
|
|
1836
|
+
const el = document.getElementById(parsed.endpointId);
|
|
1837
|
+
el?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
1178
1838
|
});
|
|
1179
1839
|
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1840
|
+
__name(apply, "apply");
|
|
1841
|
+
apply();
|
|
1842
|
+
window.addEventListener("hashchange", apply);
|
|
1843
|
+
return () => window.removeEventListener("hashchange", apply);
|
|
1844
|
+
}, [setSectionOpen]);
|
|
1182
1845
|
}
|
|
1183
|
-
__name(
|
|
1184
|
-
function
|
|
1185
|
-
const
|
|
1186
|
-
const anchor = endpointAnchor(endpoint, scopedSchemaId);
|
|
1187
|
-
const pathParams = endpoint.parameters?.filter((p) => endpoint.path.includes(`{${p.name}}`)) ?? [];
|
|
1188
|
-
const queryParams = endpoint.parameters?.filter((p) => !endpoint.path.includes(`{${p.name}}`)) ?? [];
|
|
1846
|
+
__name(useSectionHashRouter, "useSectionHashRouter");
|
|
1847
|
+
function SectionHeader({ sectionId, title, badge, open, onToggle }) {
|
|
1848
|
+
const { endpointId } = useEndpointDocContext();
|
|
1189
1849
|
const [copied, setCopied] = useState(false);
|
|
1190
|
-
const
|
|
1850
|
+
const copyHash = /* @__PURE__ */ __name((e) => {
|
|
1851
|
+
e.stopPropagation();
|
|
1191
1852
|
if (typeof window === "undefined") return;
|
|
1192
|
-
const
|
|
1853
|
+
const hash = buildSectionHash(endpointId, sectionId);
|
|
1854
|
+
const url = `${window.location.origin}${window.location.pathname}#${hash}`;
|
|
1193
1855
|
void navigator.clipboard?.writeText(url).then(() => {
|
|
1194
1856
|
setCopied(true);
|
|
1195
1857
|
setTimeout(() => setCopied(false), 1200);
|
|
1196
1858
|
});
|
|
1197
|
-
},
|
|
1198
|
-
const endpointMd = useMemo(() => endpointToMarkdown(endpoint), [endpoint]);
|
|
1859
|
+
}, "copyHash");
|
|
1199
1860
|
return /* @__PURE__ */ jsxs(
|
|
1861
|
+
"div",
|
|
1862
|
+
{
|
|
1863
|
+
className: cn(
|
|
1864
|
+
"group/section w-full flex items-center gap-2 py-1.5 -ml-1 px-1 rounded cursor-pointer",
|
|
1865
|
+
"hover:bg-muted/30 transition-colors"
|
|
1866
|
+
),
|
|
1867
|
+
onClick: onToggle,
|
|
1868
|
+
role: "button",
|
|
1869
|
+
"aria-expanded": open,
|
|
1870
|
+
tabIndex: 0,
|
|
1871
|
+
onKeyDown: (e) => {
|
|
1872
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1873
|
+
e.preventDefault();
|
|
1874
|
+
onToggle();
|
|
1875
|
+
}
|
|
1876
|
+
},
|
|
1877
|
+
children: [
|
|
1878
|
+
/* @__PURE__ */ jsx(
|
|
1879
|
+
ChevronDown,
|
|
1880
|
+
{
|
|
1881
|
+
className: cn(
|
|
1882
|
+
"h-3.5 w-3.5 text-muted-foreground/50 transition-transform shrink-0",
|
|
1883
|
+
!open && "-rotate-90"
|
|
1884
|
+
)
|
|
1885
|
+
}
|
|
1886
|
+
),
|
|
1887
|
+
/* @__PURE__ */ jsx("h4", { className: "text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/80", children: title }),
|
|
1888
|
+
typeof badge === "number" && badge > 0 && /* @__PURE__ */ jsx("span", { className: "font-mono text-[10px] text-muted-foreground/50 tabular-nums", children: badge }),
|
|
1889
|
+
/* @__PURE__ */ jsx(
|
|
1890
|
+
"button",
|
|
1891
|
+
{
|
|
1892
|
+
type: "button",
|
|
1893
|
+
onClick: copyHash,
|
|
1894
|
+
title: "Copy link to this section",
|
|
1895
|
+
className: cn(
|
|
1896
|
+
"ml-auto shrink-0 p-1 rounded text-muted-foreground/40 hover:text-foreground hover:bg-muted transition-all",
|
|
1897
|
+
"opacity-0 group-hover/section:opacity-100 focus-visible:opacity-100",
|
|
1898
|
+
copied && "opacity-100 text-emerald-500"
|
|
1899
|
+
),
|
|
1900
|
+
children: copied ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Link2, { className: "h-3 w-3" })
|
|
1901
|
+
}
|
|
1902
|
+
)
|
|
1903
|
+
]
|
|
1904
|
+
}
|
|
1905
|
+
);
|
|
1906
|
+
}
|
|
1907
|
+
__name(SectionHeader, "SectionHeader");
|
|
1908
|
+
function Section({ id, title, badge, children }) {
|
|
1909
|
+
const { endpointId, method } = useEndpointDocContext();
|
|
1910
|
+
const defaultOpen = defaultSectionOpen(method, id);
|
|
1911
|
+
const open = useIsSectionOpen(endpointId, id, defaultOpen);
|
|
1912
|
+
const toggleSection = useEndpointDocStore((s) => s.toggleSection);
|
|
1913
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2.5", children: [
|
|
1914
|
+
/* @__PURE__ */ jsx(
|
|
1915
|
+
SectionHeader,
|
|
1916
|
+
{
|
|
1917
|
+
sectionId: id,
|
|
1918
|
+
title,
|
|
1919
|
+
badge,
|
|
1920
|
+
open,
|
|
1921
|
+
onToggle: () => toggleSection(endpointId, id)
|
|
1922
|
+
}
|
|
1923
|
+
),
|
|
1924
|
+
open && /* @__PURE__ */ jsx("div", { children })
|
|
1925
|
+
] });
|
|
1926
|
+
}
|
|
1927
|
+
__name(Section, "Section");
|
|
1928
|
+
function EndpointDoc({ endpoint, isLoadedInPlayground, onTryIt, schemaId }) {
|
|
1929
|
+
const scopedSchemaId = schemaId ?? endpoint.schemaId ?? null;
|
|
1930
|
+
const anchor = endpointAnchor(endpoint, scopedSchemaId);
|
|
1931
|
+
const pathParams = endpoint.parameters?.filter((p) => endpoint.path.includes(`{${p.name}}`)) ?? [];
|
|
1932
|
+
const queryParams = endpoint.parameters?.filter((p) => !endpoint.path.includes(`{${p.name}}`)) ?? [];
|
|
1933
|
+
const hasParameters = pathParams.length > 0 || queryParams.length > 0;
|
|
1934
|
+
const hasResponses = (endpoint.responses?.length ?? 0) > 0;
|
|
1935
|
+
const presentSections = [];
|
|
1936
|
+
if (hasParameters) presentSections.push("parameters");
|
|
1937
|
+
if (endpoint.requestBody) presentSections.push("requestBody");
|
|
1938
|
+
presentSections.push("codeSamples");
|
|
1939
|
+
if (hasResponses) presentSections.push("responses");
|
|
1940
|
+
return /* @__PURE__ */ jsx(EndpointDocProvider, { endpointId: anchor, method: endpoint.method, children: /* @__PURE__ */ jsxs(
|
|
1200
1941
|
"section",
|
|
1201
1942
|
{
|
|
1202
1943
|
id: anchor,
|
|
@@ -1204,164 +1945,43 @@ function EndpointDoc({ endpoint, isLoadedInPlayground, onTryIt, schemaId }) {
|
|
|
1204
1945
|
"data-schema-id": scopedSchemaId ?? "",
|
|
1205
1946
|
className: "scroll-mt-24 py-10 first:pt-0",
|
|
1206
1947
|
children: [
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
"button",
|
|
1221
|
-
{
|
|
1222
|
-
type: "button",
|
|
1223
|
-
onClick: copyAnchor,
|
|
1224
|
-
title: "Copy link to this section",
|
|
1225
|
-
className: cn(
|
|
1226
|
-
"shrink-0 p-1 rounded text-muted-foreground/40 hover:text-foreground hover:bg-muted transition-all",
|
|
1227
|
-
"opacity-0 group-hover/header:opacity-100",
|
|
1228
|
-
copied && "opacity-100 text-emerald-500"
|
|
1229
|
-
),
|
|
1230
|
-
children: copied ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5" })
|
|
1231
|
-
}
|
|
1232
|
-
),
|
|
1233
|
-
/* @__PURE__ */ jsx(
|
|
1234
|
-
CopyButton,
|
|
1235
|
-
{
|
|
1236
|
-
value: endpointMd,
|
|
1237
|
-
title: "Copy endpoint as markdown (for AI)",
|
|
1238
|
-
variant: "ghost",
|
|
1239
|
-
size: "icon",
|
|
1240
|
-
iconClassName: "h-3.5 w-3.5",
|
|
1241
|
-
className: cn(
|
|
1242
|
-
"shrink-0 h-6 w-6 text-muted-foreground/40 hover:text-foreground",
|
|
1243
|
-
"opacity-0 group-hover/header:opacity-100 focus-visible:opacity-100"
|
|
1244
|
-
)
|
|
1245
|
-
}
|
|
1246
|
-
)
|
|
1247
|
-
] }),
|
|
1248
|
-
/* @__PURE__ */ jsxs(
|
|
1249
|
-
Button,
|
|
1250
|
-
{
|
|
1251
|
-
size: "sm",
|
|
1252
|
-
variant: isLoadedInPlayground ? "secondary" : "default",
|
|
1253
|
-
onClick: onTryIt,
|
|
1254
|
-
className: "shrink-0 h-8 text-xs gap-1.5 lg:flex hidden",
|
|
1255
|
-
children: [
|
|
1256
|
-
/* @__PURE__ */ jsx(Play, { className: "h-3 w-3" }),
|
|
1257
|
-
isLoadedInPlayground ? "Loaded" : "Try it"
|
|
1258
|
-
]
|
|
1259
|
-
}
|
|
1260
|
-
)
|
|
1261
|
-
] }),
|
|
1262
|
-
endpoint.description && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: /* @__PURE__ */ jsx(MarkdownMessage, { content: endpoint.description }) }),
|
|
1263
|
-
/* @__PURE__ */ jsxs(
|
|
1264
|
-
Button,
|
|
1948
|
+
/* @__PURE__ */ jsx(
|
|
1949
|
+
EndpointHeader,
|
|
1950
|
+
{
|
|
1951
|
+
endpoint,
|
|
1952
|
+
anchor,
|
|
1953
|
+
isLoadedInPlayground,
|
|
1954
|
+
onTryIt,
|
|
1955
|
+
presentSections
|
|
1956
|
+
}
|
|
1957
|
+
),
|
|
1958
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-8 space-y-5", children: [
|
|
1959
|
+
hasParameters && /* @__PURE__ */ jsx(
|
|
1960
|
+
Section,
|
|
1265
1961
|
{
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
children: [
|
|
1271
|
-
/* @__PURE__ */ jsx(Play, { className: "h-3 w-3" }),
|
|
1272
|
-
isLoadedInPlayground ? "Loaded in playground" : "Try it"
|
|
1273
|
-
]
|
|
1962
|
+
id: "parameters",
|
|
1963
|
+
title: "Parameters",
|
|
1964
|
+
badge: pathParams.length + queryParams.length,
|
|
1965
|
+
children: /* @__PURE__ */ jsx(Parameters, { pathParams, queryParams })
|
|
1274
1966
|
}
|
|
1275
|
-
)
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
endpoint.requestBody && /* @__PURE__ */ jsx(RequestBodySection, { body: endpoint.requestBody }),
|
|
1281
|
-
endpoint.responses && endpoint.responses.length > 0 && /* @__PURE__ */ jsx(Subsection, { title: "Responses", children: /* @__PURE__ */ jsx("div", { className: "divide-y border rounded-md overflow-hidden", children: endpoint.responses.map((r) => /* @__PURE__ */ jsxs(
|
|
1282
|
-
"div",
|
|
1967
|
+
),
|
|
1968
|
+
endpoint.requestBody && /* @__PURE__ */ jsx(Section, { id: "requestBody", title: "Request body", children: /* @__PURE__ */ jsx(RequestBody, { body: endpoint.requestBody }) }),
|
|
1969
|
+
/* @__PURE__ */ jsx(Section, { id: "codeSamples", title: "Code samples", children: /* @__PURE__ */ jsx(CodeSamples, { endpoint }) }),
|
|
1970
|
+
hasResponses && /* @__PURE__ */ jsx(
|
|
1971
|
+
Section,
|
|
1283
1972
|
{
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
r.code
|
|
1291
|
-
)) }) })
|
|
1973
|
+
id: "responses",
|
|
1974
|
+
title: "Responses",
|
|
1975
|
+
badge: endpoint.responses.length,
|
|
1976
|
+
children: /* @__PURE__ */ jsx(Responses, { responses: endpoint.responses })
|
|
1977
|
+
}
|
|
1978
|
+
)
|
|
1292
1979
|
] })
|
|
1293
1980
|
]
|
|
1294
1981
|
}
|
|
1295
|
-
);
|
|
1982
|
+
) });
|
|
1296
1983
|
}
|
|
1297
1984
|
__name(EndpointDoc, "EndpointDoc");
|
|
1298
|
-
function RequestBodySection({ body }) {
|
|
1299
|
-
const fields = useMemo(() => schemaToFields(body.schema), [body.schema]);
|
|
1300
|
-
const typeLabel = body.schema ? body.type === "array" ? `array<${body.schema.items?.type ?? "object"}>` : body.type : body.type;
|
|
1301
|
-
return /* @__PURE__ */ jsx(Subsection, { title: "Request body", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1302
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
|
|
1303
|
-
/* @__PURE__ */ jsx("code", { className: "font-mono text-[11px] text-muted-foreground/80", children: typeLabel }),
|
|
1304
|
-
body.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: body.description })
|
|
1305
|
-
] }),
|
|
1306
|
-
fields.length > 0 && /* @__PURE__ */ jsx(FieldsTable, { fields })
|
|
1307
|
-
] }) });
|
|
1308
|
-
}
|
|
1309
|
-
__name(RequestBodySection, "RequestBodySection");
|
|
1310
|
-
function FieldsTable({ fields }) {
|
|
1311
|
-
return /* @__PURE__ */ jsx("div", { className: "divide-y border rounded-md overflow-hidden", children: fields.map((f) => /* @__PURE__ */ jsxs("div", { className: "px-3 py-2.5 bg-background space-y-1", children: [
|
|
1312
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
|
|
1313
|
-
/* @__PURE__ */ jsx("code", { className: "font-mono text-xs font-medium text-foreground", children: f.name }),
|
|
1314
|
-
f.required && /* @__PURE__ */ jsx(
|
|
1315
|
-
"span",
|
|
1316
|
-
{
|
|
1317
|
-
title: "Required",
|
|
1318
|
-
className: "text-[9px] text-destructive font-bold leading-none",
|
|
1319
|
-
children: "*"
|
|
1320
|
-
}
|
|
1321
|
-
),
|
|
1322
|
-
/* @__PURE__ */ jsx("code", { className: "font-mono text-[11px] text-muted-foreground/70", children: f.type })
|
|
1323
|
-
] }),
|
|
1324
|
-
f.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground leading-relaxed break-words", children: f.description })
|
|
1325
|
-
] }, f.name)) });
|
|
1326
|
-
}
|
|
1327
|
-
__name(FieldsTable, "FieldsTable");
|
|
1328
|
-
function Subsection({ title, children }) {
|
|
1329
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-2.5", children: [
|
|
1330
|
-
/* @__PURE__ */ jsx("h4", { className: "text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/70", children: title }),
|
|
1331
|
-
children
|
|
1332
|
-
] });
|
|
1333
|
-
}
|
|
1334
|
-
__name(Subsection, "Subsection");
|
|
1335
|
-
function ParamTable({
|
|
1336
|
-
title,
|
|
1337
|
-
params
|
|
1338
|
-
}) {
|
|
1339
|
-
return /* @__PURE__ */ jsx(Subsection, { title, children: /* @__PURE__ */ jsx("div", { className: "divide-y border rounded-md overflow-hidden", children: params.map((p) => /* @__PURE__ */ jsxs("div", { className: "px-3 py-2.5 bg-background space-y-1", children: [
|
|
1340
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
|
|
1341
|
-
/* @__PURE__ */ jsx("code", { className: "font-mono text-xs font-medium text-foreground", children: p.name }),
|
|
1342
|
-
p.required && /* @__PURE__ */ jsx(
|
|
1343
|
-
"span",
|
|
1344
|
-
{
|
|
1345
|
-
title: "Required",
|
|
1346
|
-
className: "text-[9px] text-destructive font-bold leading-none",
|
|
1347
|
-
children: "*"
|
|
1348
|
-
}
|
|
1349
|
-
),
|
|
1350
|
-
/* @__PURE__ */ jsx("code", { className: "font-mono text-[11px] text-muted-foreground/70", children: p.type })
|
|
1351
|
-
] }),
|
|
1352
|
-
p.description ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground leading-relaxed break-words", children: p.description }) : null
|
|
1353
|
-
] }, p.name)) }) });
|
|
1354
|
-
}
|
|
1355
|
-
__name(ParamTable, "ParamTable");
|
|
1356
|
-
function StatusTag({ code }) {
|
|
1357
|
-
const numeric = Number.parseInt(code, 10);
|
|
1358
|
-
const cls = !Number.isFinite(numeric) ? "bg-muted text-muted-foreground border-border" : numeric >= 500 ? "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/25" : numeric >= 400 ? "bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/25" : numeric >= 300 ? "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/25" : "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/25";
|
|
1359
|
-
return /* @__PURE__ */ jsx("span", { className: cn(
|
|
1360
|
-
"inline-flex items-center justify-center rounded border px-2 py-0.5 font-mono text-[11px] font-bold leading-none shrink-0 tabular-nums",
|
|
1361
|
-
cls
|
|
1362
|
-
), children: code });
|
|
1363
|
-
}
|
|
1364
|
-
__name(StatusTag, "StatusTag");
|
|
1365
1985
|
var readNavbarOffset = /* @__PURE__ */ __name(() => {
|
|
1366
1986
|
if (typeof document === "undefined") return 0;
|
|
1367
1987
|
const raw = getComputedStyle(document.documentElement).getPropertyValue("--navbar-height");
|
|
@@ -1407,10 +2027,11 @@ function buildSchemaSectionVM(entry, selectedVersion, loadedEndpoint) {
|
|
|
1407
2027
|
};
|
|
1408
2028
|
}
|
|
1409
2029
|
__name(buildSchemaSectionVM, "buildSchemaSectionVM");
|
|
1410
|
-
var DocsView =
|
|
2030
|
+
var DocsView = React12.forwardRef(/* @__PURE__ */ __name(function DocsView2(props, ref) {
|
|
1411
2031
|
const scrollRef = useRef(null);
|
|
1412
2032
|
const scrollTargetRef = useRef(null);
|
|
1413
2033
|
const { onActiveChange } = props;
|
|
2034
|
+
useSectionHashRouter();
|
|
1414
2035
|
const ensureScrollTarget = useCallback(() => {
|
|
1415
2036
|
if (scrollTargetRef.current) return scrollTargetRef.current;
|
|
1416
2037
|
if (!scrollRef.current) return null;
|
|
@@ -1431,7 +2052,7 @@ var DocsView = React6.forwardRef(/* @__PURE__ */ __name(function DocsView2(props
|
|
|
1431
2052
|
},
|
|
1432
2053
|
[ensureScrollTarget]
|
|
1433
2054
|
);
|
|
1434
|
-
|
|
2055
|
+
React12.useImperativeHandle(ref, () => ({ scrollToAnchor }), [scrollToAnchor]);
|
|
1435
2056
|
useEffect(() => {
|
|
1436
2057
|
const root = scrollRef.current;
|
|
1437
2058
|
if (!root) return;
|
|
@@ -1535,7 +2156,7 @@ function SectionsBody({
|
|
|
1535
2156
|
return /* @__PURE__ */ jsx("div", { ref: scrollRef, children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-[860px] px-6 md:px-10 lg:px-14 py-12 space-y-16", children: sections.map((section) => /* @__PURE__ */ jsx(SchemaSectionView, { section, onTryEndpoint }, section.schemaId)) }) });
|
|
1536
2157
|
}
|
|
1537
2158
|
__name(SectionsBody, "SectionsBody");
|
|
1538
|
-
var SchemaSectionView =
|
|
2159
|
+
var SchemaSectionView = React12.memo(/* @__PURE__ */ __name(function SchemaSectionView2({
|
|
1539
2160
|
section,
|
|
1540
2161
|
onTryEndpoint
|
|
1541
2162
|
}) {
|
|
@@ -1790,8 +2411,8 @@ function RawJsonField({
|
|
|
1790
2411
|
value,
|
|
1791
2412
|
onChange
|
|
1792
2413
|
}) {
|
|
1793
|
-
const [text, setText] =
|
|
1794
|
-
|
|
2414
|
+
const [text, setText] = React12.useState(() => JSON.stringify(value ?? null, null, 2));
|
|
2415
|
+
React12.useEffect(() => {
|
|
1795
2416
|
setText(JSON.stringify(value ?? null, null, 2));
|
|
1796
2417
|
}, [value]);
|
|
1797
2418
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
@@ -2140,8 +2761,8 @@ function RequestPanel() {
|
|
|
2140
2761
|
__name(RequestPanel, "RequestPanel");
|
|
2141
2762
|
function BodySection({ schema, bodyType, bodyDescription, value, onChange, isJsonValid }) {
|
|
2142
2763
|
const hasSchema = !!schema;
|
|
2143
|
-
const [mode, setMode] =
|
|
2144
|
-
const parsed =
|
|
2764
|
+
const [mode, setMode] = React12.useState(hasSchema ? "form" : "json");
|
|
2765
|
+
const parsed = React12.useMemo(() => {
|
|
2145
2766
|
if (!value) return null;
|
|
2146
2767
|
try {
|
|
2147
2768
|
return JSON.parse(value);
|
|
@@ -2229,6 +2850,65 @@ function ModeButton({
|
|
|
2229
2850
|
);
|
|
2230
2851
|
}
|
|
2231
2852
|
__name(ModeButton, "ModeButton");
|
|
2853
|
+
function looksLikeSpaShell(html) {
|
|
2854
|
+
const bodyMatch = html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
|
|
2855
|
+
const bodyContent = (bodyMatch?.[1] ?? html).replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
2856
|
+
if (bodyContent.length === 0) return true;
|
|
2857
|
+
const singleEmptyContainer = /^<(div|main|section)[^>]*>\s*<\/\1>$/i;
|
|
2858
|
+
if (singleEmptyContainer.test(bodyContent)) return true;
|
|
2859
|
+
return false;
|
|
2860
|
+
}
|
|
2861
|
+
__name(looksLikeSpaShell, "looksLikeSpaShell");
|
|
2862
|
+
function PreviewView({ html }) {
|
|
2863
|
+
const isSpaShell = useMemo(() => looksLikeSpaShell(html), [html]);
|
|
2864
|
+
if (!html) {
|
|
2865
|
+
return /* @__PURE__ */ jsx("div", { className: "py-10 text-center text-xs text-muted-foreground", children: "Empty response body" });
|
|
2866
|
+
}
|
|
2867
|
+
if (isSpaShell) {
|
|
2868
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center gap-3 min-h-[400px]", children: [
|
|
2869
|
+
/* @__PURE__ */ jsx("div", { className: "inline-flex items-center justify-center h-10 w-10 rounded-full bg-muted", children: /* @__PURE__ */ jsx(Info, { className: "h-5 w-5 text-muted-foreground" }) }),
|
|
2870
|
+
/* @__PURE__ */ jsxs("div", { className: "max-w-sm space-y-1.5", children: [
|
|
2871
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "Looks like a single-page app shell" }),
|
|
2872
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground leading-relaxed", children: [
|
|
2873
|
+
"This page renders its content with JavaScript at runtime. Scripts are disabled in the sandbox, so Preview would show a blank page. Switch to ",
|
|
2874
|
+
/* @__PURE__ */ jsx("strong", { children: "Pretty" }),
|
|
2875
|
+
" or",
|
|
2876
|
+
" ",
|
|
2877
|
+
/* @__PURE__ */ jsx("strong", { children: "Raw" }),
|
|
2878
|
+
" to inspect the HTML source."
|
|
2879
|
+
] })
|
|
2880
|
+
] })
|
|
2881
|
+
] });
|
|
2882
|
+
}
|
|
2883
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full min-h-[400px]", children: [
|
|
2884
|
+
/* @__PURE__ */ jsxs("div", { className: "shrink-0 flex items-center gap-1.5 px-3 py-1.5 bg-muted/30 border-b text-[10px] text-muted-foreground/70", children: [
|
|
2885
|
+
/* @__PURE__ */ jsx(ShieldCheck, { className: "h-3 w-3" }),
|
|
2886
|
+
"Sandboxed preview \u2014 scripts, forms and popups are disabled"
|
|
2887
|
+
] }),
|
|
2888
|
+
/* @__PURE__ */ jsx(
|
|
2889
|
+
"div",
|
|
2890
|
+
{
|
|
2891
|
+
className: "flex-1 min-h-[360px] p-2",
|
|
2892
|
+
style: {
|
|
2893
|
+
backgroundColor: "#fff",
|
|
2894
|
+
backgroundImage: "linear-gradient(45deg, #f3f4f6 25%, transparent 25%), linear-gradient(-45deg, #f3f4f6 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #f3f4f6 75%), linear-gradient(-45deg, transparent 75%, #f3f4f6 75%)",
|
|
2895
|
+
backgroundSize: "16px 16px",
|
|
2896
|
+
backgroundPosition: "0 0, 0 8px, 8px -8px, -8px 0px"
|
|
2897
|
+
},
|
|
2898
|
+
children: /* @__PURE__ */ jsx(
|
|
2899
|
+
"iframe",
|
|
2900
|
+
{
|
|
2901
|
+
title: "Response preview",
|
|
2902
|
+
srcDoc: html,
|
|
2903
|
+
sandbox: "",
|
|
2904
|
+
className: "w-full h-full min-h-[360px] bg-white border-0 rounded shadow-sm"
|
|
2905
|
+
}
|
|
2906
|
+
)
|
|
2907
|
+
}
|
|
2908
|
+
)
|
|
2909
|
+
] });
|
|
2910
|
+
}
|
|
2911
|
+
__name(PreviewView, "PreviewView");
|
|
2232
2912
|
var JSON_TREE_CONFIG = {
|
|
2233
2913
|
maxAutoExpandDepth: 2,
|
|
2234
2914
|
maxAutoExpandArrayItems: 10,
|
|
@@ -2241,26 +2921,198 @@ var JSON_TREE_CONFIG = {
|
|
|
2241
2921
|
preserveKeyOrder: true,
|
|
2242
2922
|
className: "border-0 rounded-none"
|
|
2243
2923
|
};
|
|
2244
|
-
function
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2924
|
+
function PrettyView({ treeData, rawText, detected }) {
|
|
2925
|
+
if (detected.kind === "json" && treeData != null) {
|
|
2926
|
+
return /* @__PURE__ */ jsx(JsonTree_default, { title: "Response Body", data: treeData, config: JSON_TREE_CONFIG });
|
|
2927
|
+
}
|
|
2928
|
+
if (!rawText) {
|
|
2929
|
+
return /* @__PURE__ */ jsx("div", { className: "py-10 text-center text-xs text-muted-foreground", children: "Empty response body" });
|
|
2930
|
+
}
|
|
2931
|
+
return /* @__PURE__ */ jsx(
|
|
2932
|
+
PrettyCode_default,
|
|
2933
|
+
{
|
|
2934
|
+
data: rawText,
|
|
2935
|
+
language: detected.prism,
|
|
2936
|
+
variant: "plain",
|
|
2937
|
+
isCompact: true
|
|
2938
|
+
}
|
|
2939
|
+
);
|
|
2940
|
+
}
|
|
2941
|
+
__name(PrettyView, "PrettyView");
|
|
2942
|
+
function RawView({ rawText }) {
|
|
2943
|
+
if (!rawText) {
|
|
2944
|
+
return /* @__PURE__ */ jsx("div", { className: "py-10 text-center text-xs text-muted-foreground", children: "Empty response body" });
|
|
2945
|
+
}
|
|
2946
|
+
return /* @__PURE__ */ jsx("pre", { className: "p-4 text-[11px] font-mono text-foreground/70 whitespace-pre-wrap break-all leading-relaxed", children: rawText });
|
|
2947
|
+
}
|
|
2948
|
+
__name(RawView, "RawView");
|
|
2949
|
+
function StatusBar({ response, rawText, contentType }) {
|
|
2950
|
+
const sizeKb = rawText ? `${(rawText.length / 1024).toFixed(1)} KB` : "";
|
|
2951
|
+
const duration = response.duration != null ? `${response.duration}ms` : "";
|
|
2952
|
+
const hasStatus = response.status != null;
|
|
2953
|
+
const hasCopy = Boolean(rawText);
|
|
2954
|
+
return /* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b px-4 py-2 flex items-center justify-between gap-3 bg-muted/20", children: [
|
|
2955
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
2956
|
+
hasStatus && /* @__PURE__ */ jsx(StatusBadge, { status: response.status }),
|
|
2957
|
+
response.statusText && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground truncate", children: response.statusText }),
|
|
2958
|
+
sizeKb && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/50 tabular-nums shrink-0", children: sizeKb }),
|
|
2959
|
+
duration && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/50 tabular-nums shrink-0", children: duration }),
|
|
2960
|
+
contentType && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/50 font-mono truncate", children: contentType })
|
|
2961
|
+
] }),
|
|
2962
|
+
hasCopy && /* @__PURE__ */ jsx(
|
|
2963
|
+
CopyButton,
|
|
2964
|
+
{
|
|
2965
|
+
value: rawText,
|
|
2966
|
+
variant: "ghost",
|
|
2967
|
+
size: "sm",
|
|
2968
|
+
className: "h-6 px-2 text-[10px] text-muted-foreground shrink-0",
|
|
2969
|
+
children: "Copy"
|
|
2970
|
+
}
|
|
2971
|
+
)
|
|
2972
|
+
] });
|
|
2973
|
+
}
|
|
2974
|
+
__name(StatusBar, "StatusBar");
|
|
2975
|
+
|
|
2976
|
+
// src/tools/OpenapiViewer/components/shared/ResponsePanel/detectContent.ts
|
|
2977
|
+
function normaliseContentType(raw) {
|
|
2978
|
+
if (!raw) return null;
|
|
2979
|
+
const semi = raw.indexOf(";");
|
|
2980
|
+
return (semi === -1 ? raw : raw.slice(0, semi)).trim().toLowerCase();
|
|
2981
|
+
}
|
|
2982
|
+
__name(normaliseContentType, "normaliseContentType");
|
|
2983
|
+
function readContentType(headers) {
|
|
2984
|
+
if (!headers) return null;
|
|
2985
|
+
if (typeof headers.get === "function") {
|
|
2986
|
+
return headers.get("content-type");
|
|
2987
|
+
}
|
|
2988
|
+
if (typeof headers === "object") {
|
|
2989
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
2990
|
+
if (k.toLowerCase() === "content-type") {
|
|
2991
|
+
return typeof v === "string" ? v : null;
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
return null;
|
|
2996
|
+
}
|
|
2997
|
+
__name(readContentType, "readContentType");
|
|
2998
|
+
function kindFromContentType(mime) {
|
|
2999
|
+
if (!mime) return "text";
|
|
3000
|
+
if (mime === "application/json" || mime.endsWith("+json")) return "json";
|
|
3001
|
+
if (mime === "text/html" || mime === "application/xhtml+xml") return "html";
|
|
3002
|
+
if (mime === "application/xml" || mime === "text/xml" || mime.endsWith("+xml")) return "xml";
|
|
3003
|
+
if (mime === "text/css") return "css";
|
|
3004
|
+
if (mime === "application/javascript" || mime === "text/javascript" || mime === "application/x-javascript") return "javascript";
|
|
3005
|
+
return "text";
|
|
3006
|
+
}
|
|
3007
|
+
__name(kindFromContentType, "kindFromContentType");
|
|
3008
|
+
function kindFromBody(body) {
|
|
3009
|
+
const trimmed = body.trimStart();
|
|
3010
|
+
if (!trimmed) return null;
|
|
3011
|
+
if (trimmed.startsWith("<!DOCTYPE") || /^<html[\s>]/i.test(trimmed)) return "html";
|
|
3012
|
+
if (trimmed.startsWith("<?xml")) return "xml";
|
|
3013
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
3014
|
+
try {
|
|
3015
|
+
JSON.parse(trimmed);
|
|
3016
|
+
return "json";
|
|
3017
|
+
} catch {
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
return null;
|
|
3021
|
+
}
|
|
3022
|
+
__name(kindFromBody, "kindFromBody");
|
|
3023
|
+
var PRISM_BY_KIND = {
|
|
3024
|
+
json: "json",
|
|
3025
|
+
// ``markup`` is Prism's HTML/XML grammar — there isn't a separate
|
|
3026
|
+
// ``html`` language. XML piggy-backs on the same tokeniser.
|
|
3027
|
+
html: "markup",
|
|
3028
|
+
xml: "markup",
|
|
3029
|
+
css: "css",
|
|
3030
|
+
javascript: "javascript",
|
|
3031
|
+
text: "markup"
|
|
3032
|
+
};
|
|
3033
|
+
function detectContent(headers, rawBody) {
|
|
3034
|
+
const contentType = normaliseContentType(readContentType(headers));
|
|
3035
|
+
const headerKind = kindFromContentType(contentType);
|
|
3036
|
+
const kind = headerKind === "text" ? kindFromBody(rawBody) ?? "text" : headerKind;
|
|
3037
|
+
return {
|
|
3038
|
+
kind,
|
|
3039
|
+
prism: PRISM_BY_KIND[kind],
|
|
3040
|
+
contentType
|
|
3041
|
+
};
|
|
3042
|
+
}
|
|
3043
|
+
__name(detectContent, "detectContent");
|
|
3044
|
+
|
|
3045
|
+
// src/tools/OpenapiViewer/components/shared/ResponsePanel/useResponseView.ts
|
|
3046
|
+
function useResponseView(data, headers) {
|
|
3047
|
+
return useMemo(() => {
|
|
3048
|
+
if (data == null) {
|
|
3049
|
+
return {
|
|
3050
|
+
treeData: null,
|
|
3051
|
+
rawText: "",
|
|
3052
|
+
detected: detectContent(headers, "")
|
|
3053
|
+
};
|
|
3054
|
+
}
|
|
3055
|
+
if (typeof data === "string") {
|
|
2251
3056
|
try {
|
|
2252
|
-
return {
|
|
3057
|
+
return {
|
|
3058
|
+
treeData: JSON.parse(data),
|
|
3059
|
+
rawText: data,
|
|
3060
|
+
detected: detectContent(headers, data)
|
|
3061
|
+
};
|
|
2253
3062
|
} catch {
|
|
2254
|
-
return {
|
|
3063
|
+
return {
|
|
3064
|
+
treeData: null,
|
|
3065
|
+
rawText: data,
|
|
3066
|
+
detected: detectContent(headers, data)
|
|
3067
|
+
};
|
|
2255
3068
|
}
|
|
2256
3069
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
3070
|
+
const stringified = (() => {
|
|
3071
|
+
try {
|
|
3072
|
+
return JSON.stringify(data, null, 2);
|
|
3073
|
+
} catch {
|
|
3074
|
+
return String(data);
|
|
3075
|
+
}
|
|
3076
|
+
})();
|
|
3077
|
+
return {
|
|
3078
|
+
treeData: data,
|
|
3079
|
+
rawText: stringified,
|
|
3080
|
+
detected: detectContent(headers, stringified)
|
|
3081
|
+
};
|
|
3082
|
+
}, [data, headers]);
|
|
3083
|
+
}
|
|
3084
|
+
__name(useResponseView, "useResponseView");
|
|
3085
|
+
var LABELS = {
|
|
3086
|
+
pretty: "Pretty",
|
|
3087
|
+
raw: "Raw",
|
|
3088
|
+
preview: "Preview"
|
|
3089
|
+
};
|
|
3090
|
+
function ViewTabs({ active, onChange, showPreview }) {
|
|
3091
|
+
const tabs = showPreview ? ["pretty", "raw", "preview"] : ["pretty", "raw"];
|
|
3092
|
+
return /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b px-3 py-1.5 flex items-center gap-1", children: tabs.map((t) => /* @__PURE__ */ jsx(
|
|
3093
|
+
"button",
|
|
3094
|
+
{
|
|
3095
|
+
type: "button",
|
|
3096
|
+
onClick: () => onChange(t),
|
|
3097
|
+
className: cn(
|
|
3098
|
+
"h-6 px-2.5 rounded text-[11px] font-medium transition-colors",
|
|
3099
|
+
active === t ? "bg-muted text-foreground" : "text-muted-foreground/70 hover:text-foreground hover:bg-muted/50"
|
|
3100
|
+
),
|
|
3101
|
+
children: LABELS[t]
|
|
3102
|
+
},
|
|
3103
|
+
t
|
|
3104
|
+
)) });
|
|
3105
|
+
}
|
|
3106
|
+
__name(ViewTabs, "ViewTabs");
|
|
3107
|
+
function ResponsePanel() {
|
|
3108
|
+
const { state } = usePlaygroundContext();
|
|
3109
|
+
const { response, loading, selectedEndpoint } = state;
|
|
3110
|
+
const { treeData, rawText, detected } = useResponseView(response?.data, response?.headers);
|
|
3111
|
+
const showPreview = detected.kind === "html";
|
|
3112
|
+
const [mode, setMode] = useState(showPreview ? "preview" : "pretty");
|
|
3113
|
+
useEffect(() => {
|
|
3114
|
+
setMode(showPreview ? "preview" : "pretty");
|
|
3115
|
+
}, [selectedEndpoint, response, showPreview]);
|
|
2264
3116
|
if (loading) {
|
|
2265
3117
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center h-full gap-2", children: [
|
|
2266
3118
|
/* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }),
|
|
@@ -2269,6 +3121,8 @@ function ResponsePanel() {
|
|
|
2269
3121
|
}
|
|
2270
3122
|
if (!selectedEndpoint) return /* @__PURE__ */ jsx(EmptyState, { icon: Terminal, text: "Response will appear here" });
|
|
2271
3123
|
if (!response) return /* @__PURE__ */ jsx(EmptyState, { icon: Send, text: 'Press "Send Request" to see the response' });
|
|
3124
|
+
const hasError = Boolean(response.error);
|
|
3125
|
+
const hasStatus = response.status != null;
|
|
2272
3126
|
if (hasError && !hasStatus) {
|
|
2273
3127
|
return /* @__PURE__ */ jsx(
|
|
2274
3128
|
EmptyState,
|
|
@@ -2280,17 +3134,14 @@ function ResponsePanel() {
|
|
|
2280
3134
|
);
|
|
2281
3135
|
}
|
|
2282
3136
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2283
|
-
/* @__PURE__ */
|
|
2284
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
2285
|
-
hasStatus && /* @__PURE__ */ jsx(StatusBadge, { status: response.status }),
|
|
2286
|
-
response.statusText && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground truncate", children: response.statusText }),
|
|
2287
|
-
sizeKb && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/50 tabular-nums shrink-0", children: sizeKb }),
|
|
2288
|
-
duration && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/50 tabular-nums shrink-0", children: duration })
|
|
2289
|
-
] }),
|
|
2290
|
-
hasCopy && /* @__PURE__ */ jsx(CopyButton, { value: rawText, variant: "ghost", size: "sm", className: "h-6 px-2 text-[10px] text-muted-foreground shrink-0", children: "Copy" })
|
|
2291
|
-
] }),
|
|
3137
|
+
/* @__PURE__ */ jsx(StatusBar, { response, rawText, contentType: detected.contentType }),
|
|
2292
3138
|
hasError && /* @__PURE__ */ jsx("div", { className: "shrink-0 mx-4 mt-3 rounded border border-destructive/20 bg-destructive/5 px-3 py-2", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: response.error }) }),
|
|
2293
|
-
/* @__PURE__ */ jsx(
|
|
3139
|
+
/* @__PURE__ */ jsx(ViewTabs, { active: mode, onChange: setMode, showPreview }),
|
|
3140
|
+
/* @__PURE__ */ jsxs(ScrollArea, { children: [
|
|
3141
|
+
mode === "pretty" && /* @__PURE__ */ jsx(PrettyView, { treeData, rawText, detected }),
|
|
3142
|
+
mode === "raw" && /* @__PURE__ */ jsx(RawView, { rawText }),
|
|
3143
|
+
mode === "preview" && /* @__PURE__ */ jsx(PreviewView, { html: rawText })
|
|
3144
|
+
] })
|
|
2294
3145
|
] });
|
|
2295
3146
|
}
|
|
2296
3147
|
__name(ResponsePanel, "ResponsePanel");
|
|
@@ -2364,12 +3215,14 @@ function SlideInPlayground({ open, onClose }) {
|
|
|
2364
3215
|
showResponse ? "grid-cols-[minmax(0,1fr)_minmax(0,1fr)]" : "grid-cols-1"
|
|
2365
3216
|
),
|
|
2366
3217
|
children: [
|
|
2367
|
-
/* @__PURE__ */
|
|
3218
|
+
/* @__PURE__ */ jsxs(Panel, { children: [
|
|
3219
|
+
/* @__PURE__ */ jsx(RequestPanel, {}),
|
|
3220
|
+
ep && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t px-4 py-3 bg-background", children: /* @__PURE__ */ jsx(SendButton, {}) })
|
|
3221
|
+
] }),
|
|
2368
3222
|
showResponse && /* @__PURE__ */ jsx(Panel, { children: /* @__PURE__ */ jsx(ResponsePanel, {}) })
|
|
2369
3223
|
]
|
|
2370
3224
|
}
|
|
2371
|
-
)
|
|
2372
|
-
ep && /* @__PURE__ */ jsx(SidePanel.Footer, { className: "px-4 py-3", children: /* @__PURE__ */ jsx(SendButton, {}) })
|
|
3225
|
+
)
|
|
2373
3226
|
] }) });
|
|
2374
3227
|
}
|
|
2375
3228
|
__name(SlideInPlayground, "SlideInPlayground");
|
|
@@ -2379,10 +3232,12 @@ function TryItSheet({ open, onOpenChange }) {
|
|
|
2379
3232
|
return /* @__PURE__ */ jsx(ResponsiveSheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ResponsiveSheetContent, { className: "sm:max-w-xl flex flex-col h-full p-0", children: [
|
|
2380
3233
|
/* @__PURE__ */ jsx(ResponsiveSheetHeader, { className: "px-4 py-3 border-b shrink-0", children: /* @__PURE__ */ jsx(ResponsiveSheetTitle, { className: "text-sm", children: "Playground" }) }),
|
|
2381
3234
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0 flex flex-col divide-y", children: [
|
|
2382
|
-
/* @__PURE__ */
|
|
3235
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0 flex flex-col", children: [
|
|
3236
|
+
/* @__PURE__ */ jsx(RequestPanel, {}),
|
|
3237
|
+
state.selectedEndpoint && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t px-4 py-3 bg-background", children: /* @__PURE__ */ jsx(SendButton, {}) })
|
|
3238
|
+
] }),
|
|
2383
3239
|
showResponse && /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0 flex flex-col", children: /* @__PURE__ */ jsx(ResponsePanel, {}) })
|
|
2384
|
-
] })
|
|
2385
|
-
state.selectedEndpoint && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t px-4 py-3 bg-background/95 backdrop-blur-sm", children: /* @__PURE__ */ jsx(SendButton, {}) })
|
|
3240
|
+
] })
|
|
2386
3241
|
] }) });
|
|
2387
3242
|
}
|
|
2388
3243
|
__name(TryItSheet, "TryItSheet");
|
|
@@ -2598,5 +3453,5 @@ var DocsLayout = /* @__PURE__ */ __name(() => {
|
|
|
2598
3453
|
}, "DocsLayout");
|
|
2599
3454
|
|
|
2600
3455
|
export { DocsLayout };
|
|
2601
|
-
//# sourceMappingURL=DocsLayout-
|
|
2602
|
-
//# sourceMappingURL=DocsLayout-
|
|
3456
|
+
//# sourceMappingURL=DocsLayout-JPXFUKAR.mjs.map
|
|
3457
|
+
//# sourceMappingURL=DocsLayout-JPXFUKAR.mjs.map
|