@kingsleyweb/bun-ui 0.0.0-stage → 3.0.0-rc.2
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/LICENSE +21 -0
- package/README.md +80 -2
- package/app/docs/App.tsx +72 -0
- package/app/docs/api/client.ts +303 -0
- package/app/docs/api/contract.ts +24 -0
- package/app/docs/api/docs.ts +38 -0
- package/app/docs/api/errors.ts +144 -0
- package/app/docs/boot.tsx +58 -0
- package/app/docs/components/Badge.tsx +65 -0
- package/app/docs/components/Button.tsx +37 -0
- package/app/docs/components/Card.tsx +41 -0
- package/app/docs/components/ConfirmDialog.tsx +173 -0
- package/app/docs/components/CopyButton.tsx +68 -0
- package/app/docs/components/Dialog.tsx +230 -0
- package/app/docs/components/EmptyState.tsx +34 -0
- package/app/docs/components/ErrorView.tsx +70 -0
- package/app/docs/components/Field.tsx +93 -0
- package/app/docs/components/JsonEditor.tsx +151 -0
- package/app/docs/components/JsonView.tsx +338 -0
- package/app/docs/components/KeyValue.tsx +63 -0
- package/app/docs/components/ProblemBanner.tsx +116 -0
- package/app/docs/components/ScreenErrorBoundary.tsx +141 -0
- package/app/docs/components/Spinner.tsx +33 -0
- package/app/docs/components/Table.tsx +33 -0
- package/app/docs/components/Tabs.tsx +226 -0
- package/app/docs/components/classNames.ts +4 -0
- package/app/docs/components/components.css +691 -0
- package/app/docs/components/copy.ts +89 -0
- package/app/docs/components/fieldContext.ts +29 -0
- package/app/docs/components/inputValues.ts +142 -0
- package/app/docs/components/inputs.tsx +387 -0
- package/app/docs/components/jsonParse.ts +338 -0
- package/app/docs/components/listKeys.ts +30 -0
- package/app/docs/config.ts +86 -0
- package/app/docs/context.ts +33 -0
- package/app/docs/embed.ts +74 -0
- package/app/docs/env.d.ts +2 -0
- package/app/docs/format.ts +9 -0
- package/app/docs/hooks/useUrlTab.ts +16 -0
- package/app/docs/main.tsx +11 -0
- package/app/docs/queryClient.ts +54 -0
- package/app/docs/router.tsx +194 -0
- package/app/docs/routing.ts +194 -0
- package/app/docs/screens/docs/document.ts +27 -0
- package/app/docs/screens/docs/http/OperationView.tsx +407 -0
- package/app/docs/screens/docs/http/Sidebar.tsx +190 -0
- package/app/docs/screens/docs/http/TryItPanel.tsx +603 -0
- package/app/docs/screens/docs/http/http.css +405 -0
- package/app/docs/screens/docs/http/index.tsx +395 -0
- package/app/docs/screens/docs/http/model.ts +604 -0
- package/app/docs/screens/docs/http/tryIt.ts +455 -0
- package/app/docs/screens/docs/permissions.ts +6 -0
- package/app/docs/screens/docs/schema/Prose.tsx +43 -0
- package/app/docs/screens/docs/schema/SchemaTree.tsx +319 -0
- package/app/docs/screens/docs/schema/index.ts +30 -0
- package/app/docs/screens/docs/schema/resolve.ts +466 -0
- package/app/docs/screens/docs/schema/schema.css +137 -0
- package/app/docs/screens/docs/schema/skeleton.ts +92 -0
- package/app/docs/screens/docs/viewer.tsx +154 -0
- package/app/docs/screens/docs/ws/InlineText.tsx +25 -0
- package/app/docs/screens/docs/ws/PayloadSchema.tsx +39 -0
- package/app/docs/screens/docs/ws/format.ts +82 -0
- package/app/docs/screens/docs/ws/index.tsx +286 -0
- package/app/docs/screens/docs/ws/items.tsx +786 -0
- package/app/docs/screens/docs/ws/model.ts +1178 -0
- package/app/docs/screens/docs/ws/panels.tsx +440 -0
- package/app/docs/screens/docs/ws/ws.css +231 -0
- package/app/docs/shortcuts.ts +94 -0
- package/app/docs/styles/base.css +847 -0
- package/app/docs/styles/tokens.css +143 -0
- package/app/docs/theme.ts +56 -0
- package/app/kit/unauthorized.ts +222 -0
- package/dist/docs/assets/main-0rchxtv5.js +18 -0
- package/dist/docs/assets/main-0rchxtv5.js.map +99 -0
- package/dist/docs/assets/main-cqgyvs86.css +1 -0
- package/dist/docs/manifest.json +26 -0
- package/dist/jobs/assets/AddFlowDialog-h6xkgx9b.js +6 -0
- package/dist/jobs/assets/AddFlowDialog-h6xkgx9b.js.map +11 -0
- package/dist/jobs/assets/AddFlowDialog-n7gtc84v.css +1 -0
- package/dist/jobs/assets/added-cbwsxv3e.js +4 -0
- package/dist/jobs/assets/added-cbwsxv3e.js.map +11 -0
- package/dist/jobs/assets/bodies-yyw5hmrp.js +6 -0
- package/dist/jobs/assets/bodies-yyw5hmrp.js.map +10 -0
- package/dist/jobs/assets/channel-tgkvqm8y.js +4 -0
- package/dist/jobs/assets/channel-tgkvqm8y.js.map +10 -0
- package/dist/jobs/assets/channelChecks-s4yz4yhw.js +4 -0
- package/dist/jobs/assets/channelChecks-s4yz4yhw.js.map +10 -0
- package/dist/jobs/assets/index-02427smp.css +1 -0
- package/dist/jobs/assets/index-09z2cjft.js +4 -0
- package/dist/jobs/assets/index-09z2cjft.js.map +16 -0
- package/dist/jobs/assets/index-18bn0gvy.css +1 -0
- package/dist/jobs/assets/index-47pxmyxn.js +4 -0
- package/dist/jobs/assets/index-47pxmyxn.js.map +10 -0
- package/dist/jobs/assets/index-4e55z986.js +4 -0
- package/dist/jobs/assets/index-4e55z986.js.map +11 -0
- package/dist/jobs/assets/index-5c933424.js +4 -0
- package/dist/jobs/assets/index-5c933424.js.map +18 -0
- package/dist/jobs/assets/index-5kbyqspm.css +1 -0
- package/dist/jobs/assets/index-5ng37hk6.css +1 -0
- package/dist/jobs/assets/index-5w8w7fvc.css +1 -0
- package/dist/jobs/assets/index-71qs5qyx.css +1 -0
- package/dist/jobs/assets/index-btpg4r8b.css +1 -0
- package/dist/jobs/assets/index-d5r5n0mm.js +4 -0
- package/dist/jobs/assets/index-d5r5n0mm.js.map +23 -0
- package/dist/jobs/assets/index-e0yy2skq.css +1 -0
- package/dist/jobs/assets/index-hs60b25v.js +10 -0
- package/dist/jobs/assets/index-hs60b25v.js.map +62 -0
- package/dist/jobs/assets/index-k2smrr70.js +4 -0
- package/dist/jobs/assets/index-k2smrr70.js.map +9 -0
- package/dist/jobs/assets/index-q24jw3w9.js +4 -0
- package/dist/jobs/assets/index-q24jw3w9.js.map +32 -0
- package/dist/jobs/assets/index-qfb80xen.css +1 -0
- package/dist/jobs/assets/index-rtynx6wj.js +4 -0
- package/dist/jobs/assets/index-rtynx6wj.js.map +10 -0
- package/dist/jobs/assets/live-6k7s6358.js +4 -0
- package/dist/jobs/assets/live-6k7s6358.js.map +10 -0
- package/dist/jobs/assets/main-0jmeh6mq.js +6 -0
- package/dist/jobs/assets/main-0jmeh6mq.js.map +12 -0
- package/dist/jobs/assets/main-3yj6bv90.js +5 -0
- package/dist/jobs/assets/main-3yj6bv90.js.map +10 -0
- package/dist/jobs/assets/main-4g69fn3x.js +5 -0
- package/dist/jobs/assets/main-4g69fn3x.js.map +10 -0
- package/dist/jobs/assets/main-4gte3eqq.js +5 -0
- package/dist/jobs/assets/main-4gte3eqq.js.map +10 -0
- package/dist/jobs/assets/main-4j1fcevh.js +5 -0
- package/dist/jobs/assets/main-4j1fcevh.js.map +10 -0
- package/dist/jobs/assets/main-54qwkz28.css +1 -0
- package/dist/jobs/assets/main-5grjvsy7.js +5 -0
- package/dist/jobs/assets/main-5grjvsy7.js.map +11 -0
- package/dist/jobs/assets/main-5zbx60gq.js +5 -0
- package/dist/jobs/assets/main-5zbx60gq.js.map +11 -0
- package/dist/jobs/assets/main-9prgjhg4.js +5 -0
- package/dist/jobs/assets/main-9prgjhg4.js.map +10 -0
- package/dist/jobs/assets/main-a250ffk7.js +17 -0
- package/dist/jobs/assets/main-a250ffk7.js.map +115 -0
- package/dist/jobs/assets/main-d6ge7w08.js +5 -0
- package/dist/jobs/assets/main-d6ge7w08.js.map +10 -0
- package/dist/jobs/assets/main-gngzht43.js +5 -0
- package/dist/jobs/assets/main-gngzht43.js.map +10 -0
- package/dist/jobs/assets/main-hg0hrg8j.js +5 -0
- package/dist/jobs/assets/main-hg0hrg8j.js.map +10 -0
- package/dist/jobs/assets/main-hm1ng3yg.js +5 -0
- package/dist/jobs/assets/main-hm1ng3yg.js.map +12 -0
- package/dist/jobs/assets/main-jkvd92z9.js +5 -0
- package/dist/jobs/assets/main-jkvd92z9.js.map +10 -0
- package/dist/jobs/assets/main-jv5xqd13.js +5 -0
- package/dist/jobs/assets/main-jv5xqd13.js.map +21 -0
- package/dist/jobs/assets/main-jxre7w93.js +5 -0
- package/dist/jobs/assets/main-jxre7w93.js.map +23 -0
- package/dist/jobs/assets/main-kwmqkjfx.js +5 -0
- package/dist/jobs/assets/main-kwmqkjfx.js.map +11 -0
- package/dist/jobs/assets/main-n9cf6bxm.js +5 -0
- package/dist/jobs/assets/main-n9cf6bxm.js.map +11 -0
- package/dist/jobs/assets/main-pegp0ygb.js +5 -0
- package/dist/jobs/assets/main-pegp0ygb.js.map +10 -0
- package/dist/jobs/assets/main-qr573853.js +5 -0
- package/dist/jobs/assets/main-qr573853.js.map +12 -0
- package/dist/jobs/assets/main-rq97rdr4.js +4 -0
- package/dist/jobs/assets/main-rq97rdr4.js.map +22 -0
- package/dist/jobs/assets/main-szjdmydc.js +5 -0
- package/dist/jobs/assets/main-szjdmydc.js.map +13 -0
- package/dist/jobs/assets/main-tnbhrm9n.js +7 -0
- package/dist/jobs/assets/main-tnbhrm9n.js.map +11 -0
- package/dist/jobs/assets/main-ts19j4n0.js +5 -0
- package/dist/jobs/assets/main-ts19j4n0.js.map +25 -0
- package/dist/jobs/assets/main-w93x1dzs.js +5 -0
- package/dist/jobs/assets/main-w93x1dzs.js.map +10 -0
- package/dist/jobs/assets/sections-0ksdxs8m.css +1 -0
- package/dist/jobs/assets/sections-0y7w4fb4.js +4 -0
- package/dist/jobs/assets/sections-0y7w4fb4.js.map +10 -0
- package/dist/jobs/assets/sse-mn0t0fh7.js +5 -0
- package/dist/jobs/assets/sse-mn0t0fh7.js.map +11 -0
- package/dist/jobs/assets/sseChecks-t7tcm7ra.js +4 -0
- package/dist/jobs/assets/sseChecks-t7tcm7ra.js.map +10 -0
- package/dist/jobs/assets/validation-ysjfy072.js +4 -0
- package/dist/jobs/assets/validation-ysjfy072.js.map +9 -0
- package/dist/jobs/manifest.json +511 -0
- package/dts/docs/assets.d.ts +144 -0
- package/dts/docs/assets.d.ts.map +1 -0
- package/dts/docs/browser/config.d.ts +61 -0
- package/dts/docs/browser/config.d.ts.map +1 -0
- package/dts/docs/browser/index.d.ts +12 -0
- package/dts/docs/browser/index.d.ts.map +1 -0
- package/dts/docs/docsUi.d.ts +42 -0
- package/dts/docs/docsUi.d.ts.map +1 -0
- package/dts/docs/hosted.d.ts +22 -0
- package/dts/docs/hosted.d.ts.map +1 -0
- package/dts/docs/index.d.ts +18 -0
- package/dts/docs/index.d.ts.map +1 -0
- package/dts/docs/shell.d.ts +57 -0
- package/dts/docs/shell.d.ts.map +1 -0
- package/dts/docs/types.d.ts +137 -0
- package/dts/docs/types.d.ts.map +1 -0
- package/dts/index.d.ts +21 -0
- package/dts/index.d.ts.map +1 -0
- package/dts/jobs/assets.d.ts +157 -0
- package/dts/jobs/assets.d.ts.map +1 -0
- package/dts/jobs/browser/config.d.ts +67 -0
- package/dts/jobs/browser/config.d.ts.map +1 -0
- package/dts/jobs/browser/index.d.ts +10 -0
- package/dts/jobs/browser/index.d.ts.map +1 -0
- package/dts/jobs/browser/unauthorized.d.ts +9 -0
- package/dts/jobs/browser/unauthorized.d.ts.map +1 -0
- package/dts/jobs/index.d.ts +24 -0
- package/dts/jobs/index.d.ts.map +1 -0
- package/dts/jobs/jobsUi.d.ts +63 -0
- package/dts/jobs/jobsUi.d.ts.map +1 -0
- package/dts/jobs/shell.d.ts +77 -0
- package/dts/jobs/shell.d.ts.map +1 -0
- package/dts/jobs/types.d.ts +146 -0
- package/dts/jobs/types.d.ts.map +1 -0
- package/dts/kit/browser/shared.d.ts +10 -0
- package/dts/kit/browser/shared.d.ts.map +1 -0
- package/dts/kit/browser/unauthorized.d.ts +74 -0
- package/dts/kit/browser/unauthorized.d.ts.map +1 -0
- package/dts/kit/unauthorized.d.ts +47 -0
- package/dts/kit/unauthorized.d.ts.map +1 -0
- package/guides/docs.md +170 -0
- package/guides/jobs.md +1120 -0
- package/lib/docs/assets.ts +427 -0
- package/lib/docs/browser/config.ts +66 -0
- package/lib/docs/browser/index.ts +24 -0
- package/lib/docs/docsUi.ts +623 -0
- package/lib/docs/hosted.ts +31 -0
- package/lib/docs/index.ts +37 -0
- package/lib/docs/shell.ts +156 -0
- package/lib/docs/types.ts +149 -0
- package/lib/index.ts +27 -0
- package/lib/jobs/assets.ts +448 -0
- package/lib/jobs/browser/config.ts +65 -0
- package/lib/jobs/browser/index.ts +9 -0
- package/lib/jobs/browser/unauthorized.ts +11 -0
- package/lib/jobs/index.ts +41 -0
- package/lib/jobs/jobsUi.ts +709 -0
- package/lib/jobs/shell.ts +205 -0
- package/lib/jobs/types.ts +162 -0
- package/lib/kit/browser/shared.ts +11 -0
- package/lib/kit/browser/unauthorized.ts +114 -0
- package/lib/kit/unauthorized.ts +222 -0
- package/package.json +198 -4
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/** The HTTP API reference (OpenAPI 3.1): `/http` and `/http/:operationId` under the mount. */
|
|
2
|
+
import type { DocsClient } from "../../../api/client";
|
|
3
|
+
import type { SpecDocument } from "../../../api/docs";
|
|
4
|
+
import type { PermissionProbe } from "../permissions";
|
|
5
|
+
import type { DocInfo, DocSection, DocTagGroup } from "./model";
|
|
6
|
+
import { useMemo, useState } from "react";
|
|
7
|
+
import { createDocsClient } from "../../../api/client";
|
|
8
|
+
import { Badge } from "../../../components/Badge";
|
|
9
|
+
import { Card } from "../../../components/Card";
|
|
10
|
+
import { CopyButton } from "../../../components/CopyButton";
|
|
11
|
+
import { Dialog } from "../../../components/Dialog";
|
|
12
|
+
import { EmptyState } from "../../../components/EmptyState";
|
|
13
|
+
import {
|
|
14
|
+
DocsClientContext,
|
|
15
|
+
useDocsFetch,
|
|
16
|
+
useDocsUiConfig,
|
|
17
|
+
} from "../../../context";
|
|
18
|
+
import { Link } from "../../../router";
|
|
19
|
+
import { useParams, useQueryParam } from "../../../routing";
|
|
20
|
+
import { Prose } from "../schema/Prose";
|
|
21
|
+
import { refName } from "../schema/resolve";
|
|
22
|
+
import { SchemaTree } from "../schema/SchemaTree";
|
|
23
|
+
import {
|
|
24
|
+
componentSchemaNames,
|
|
25
|
+
filterGroups,
|
|
26
|
+
groupBySection,
|
|
27
|
+
keyedSections,
|
|
28
|
+
groupByTag,
|
|
29
|
+
listOperations,
|
|
30
|
+
readInfo,
|
|
31
|
+
resolveServerUrl,
|
|
32
|
+
} from "./model";
|
|
33
|
+
import { OperationView } from "./OperationView";
|
|
34
|
+
import { Sidebar } from "./Sidebar";
|
|
35
|
+
import "./http.css";
|
|
36
|
+
|
|
37
|
+
/** The app path of an operation, keeping a search; `base` is the docs section's path within the host app ("" for a standalone viewer). */
|
|
38
|
+
function operationHref(operationId: string, query: string, base = ""): string {
|
|
39
|
+
const search = query ? `?q=${encodeURIComponent(query)}` : "";
|
|
40
|
+
return `${base}/http/${encodeURIComponent(operationId)}${search}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The document's title, version, description and servers. */
|
|
44
|
+
function InfoHeader({
|
|
45
|
+
info,
|
|
46
|
+
serverBase,
|
|
47
|
+
}: {
|
|
48
|
+
/** The header. */
|
|
49
|
+
info: DocInfo;
|
|
50
|
+
/** The resolved URL requests are sent to. */
|
|
51
|
+
serverBase: string;
|
|
52
|
+
}) {
|
|
53
|
+
const config = useDocsUiConfig();
|
|
54
|
+
const origin = typeof window === "undefined" ? "" : window.location.origin;
|
|
55
|
+
return (
|
|
56
|
+
<Card className="http-info">
|
|
57
|
+
<div className="http-info-line">
|
|
58
|
+
<Badge tone="accent">{`OpenAPI ${info.openapi}`}</Badge>
|
|
59
|
+
{info.version && <Badge tone="neutral">{`v${info.version}`}</Badge>}
|
|
60
|
+
</div>
|
|
61
|
+
{info.description && (
|
|
62
|
+
<div className="http-description">
|
|
63
|
+
<Prose text={info.description} />
|
|
64
|
+
</div>
|
|
65
|
+
)}
|
|
66
|
+
<dl
|
|
67
|
+
className="http-servers"
|
|
68
|
+
data-testid="http-servers"
|
|
69
|
+
>
|
|
70
|
+
{info.servers.map((server) => {
|
|
71
|
+
const resolved = resolveServerUrl(
|
|
72
|
+
server.url,
|
|
73
|
+
config.documentUrl,
|
|
74
|
+
origin,
|
|
75
|
+
);
|
|
76
|
+
return (
|
|
77
|
+
<div key={server.url}>
|
|
78
|
+
<dt>
|
|
79
|
+
Server <code>{server.url}</code>
|
|
80
|
+
{server.description ? ` (${server.description})` : ""}
|
|
81
|
+
</dt>
|
|
82
|
+
<dd>
|
|
83
|
+
<code data-testid="http-server-url">{resolved}</code>
|
|
84
|
+
<CopyButton
|
|
85
|
+
text={resolved}
|
|
86
|
+
ariaLabel="Copy the server URL"
|
|
87
|
+
/>
|
|
88
|
+
</dd>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
})}
|
|
92
|
+
<div>
|
|
93
|
+
<dt>Requests are sent to</dt>
|
|
94
|
+
<dd>
|
|
95
|
+
<code data-testid="http-request-base">{serverBase}</code>
|
|
96
|
+
</dd>
|
|
97
|
+
</div>
|
|
98
|
+
</dl>
|
|
99
|
+
<p className="http-muted">Paths below are relative to the server.</p>
|
|
100
|
+
</Card>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** One tag's description and its operations' links, on the landing view. */
|
|
105
|
+
function OverviewTag({
|
|
106
|
+
group,
|
|
107
|
+
query,
|
|
108
|
+
pathBase,
|
|
109
|
+
}: {
|
|
110
|
+
/** The tag and its operations. */
|
|
111
|
+
group: DocTagGroup;
|
|
112
|
+
/** The search, kept on links. */
|
|
113
|
+
query: string;
|
|
114
|
+
/** The docs section's path within the host app. */
|
|
115
|
+
pathBase: string;
|
|
116
|
+
}) {
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
{group.description && <p className="http-muted">{group.description}</p>}
|
|
120
|
+
<ul className="http-overview-ops">
|
|
121
|
+
{group.operations.map((operation) => (
|
|
122
|
+
<li key={operation.id}>
|
|
123
|
+
<Link to={operationHref(operation.id, query, pathBase)}>
|
|
124
|
+
<code>{operation.method}</code> {operation.path}
|
|
125
|
+
</Link>
|
|
126
|
+
{operation.summary && (
|
|
127
|
+
<span className="http-muted">{` ${operation.summary}`}</span>
|
|
128
|
+
)}
|
|
129
|
+
</li>
|
|
130
|
+
))}
|
|
131
|
+
</ul>
|
|
132
|
+
</>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The landing view: tags (in their sections, when the document has them) with their operations, and the component schemas. */
|
|
137
|
+
function Overview({
|
|
138
|
+
doc,
|
|
139
|
+
groups,
|
|
140
|
+
sections,
|
|
141
|
+
query,
|
|
142
|
+
onRef,
|
|
143
|
+
pathBase,
|
|
144
|
+
}: {
|
|
145
|
+
/** The document. */
|
|
146
|
+
doc: SpecDocument;
|
|
147
|
+
/** Every tag group (unfiltered). */
|
|
148
|
+
groups: readonly DocTagGroup[];
|
|
149
|
+
/** The document's sections over them (`x-tagGroups`), when it declares any: one card each, its tags inside. */
|
|
150
|
+
sections: readonly DocSection[] | undefined;
|
|
151
|
+
/** The search, kept on links. */
|
|
152
|
+
query: string;
|
|
153
|
+
/** Opens a component schema. */
|
|
154
|
+
onRef: (ref: string, name: string) => void;
|
|
155
|
+
/** The docs section's path within the host app. */
|
|
156
|
+
pathBase: string;
|
|
157
|
+
}) {
|
|
158
|
+
const names = componentSchemaNames(doc);
|
|
159
|
+
return (
|
|
160
|
+
<div className="http-overview">
|
|
161
|
+
{sections === undefined
|
|
162
|
+
? groups.map((group) => (
|
|
163
|
+
<Card
|
|
164
|
+
key={group.name}
|
|
165
|
+
title={group.name}
|
|
166
|
+
>
|
|
167
|
+
<OverviewTag
|
|
168
|
+
group={group}
|
|
169
|
+
query={query}
|
|
170
|
+
pathBase={pathBase}
|
|
171
|
+
/>
|
|
172
|
+
</Card>
|
|
173
|
+
))
|
|
174
|
+
: keyedSections(sections).map(({ key, section }) => (
|
|
175
|
+
<Card
|
|
176
|
+
key={key}
|
|
177
|
+
title={section.name}
|
|
178
|
+
className="http-overview-section"
|
|
179
|
+
>
|
|
180
|
+
{section.tags.map((group) => (
|
|
181
|
+
<section
|
|
182
|
+
key={group.name}
|
|
183
|
+
className="http-overview-tag"
|
|
184
|
+
aria-label={group.name}
|
|
185
|
+
>
|
|
186
|
+
<h3 className="http-overview-tag-name">{group.name}</h3>
|
|
187
|
+
<OverviewTag
|
|
188
|
+
group={group}
|
|
189
|
+
query={query}
|
|
190
|
+
pathBase={pathBase}
|
|
191
|
+
/>
|
|
192
|
+
</section>
|
|
193
|
+
))}
|
|
194
|
+
</Card>
|
|
195
|
+
))}
|
|
196
|
+
{names.length > 0 && (
|
|
197
|
+
<Card title="Schemas">
|
|
198
|
+
<ul
|
|
199
|
+
className="http-components"
|
|
200
|
+
data-testid="http-components"
|
|
201
|
+
>
|
|
202
|
+
{names.map((name) => (
|
|
203
|
+
<li
|
|
204
|
+
key={name}
|
|
205
|
+
id={`schema-${name}`}
|
|
206
|
+
>
|
|
207
|
+
<button
|
|
208
|
+
type="button"
|
|
209
|
+
className="schema-ref schema-ref-link"
|
|
210
|
+
onClick={() => onRef(`#/components/schemas/${name}`, name)}
|
|
211
|
+
>
|
|
212
|
+
{name}
|
|
213
|
+
</button>
|
|
214
|
+
</li>
|
|
215
|
+
))}
|
|
216
|
+
</ul>
|
|
217
|
+
</Card>
|
|
218
|
+
)}
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** The side panel showing one component schema; a `$ref` inside it replaces it. */
|
|
224
|
+
function SchemaPanel({
|
|
225
|
+
doc,
|
|
226
|
+
refValue,
|
|
227
|
+
onClose,
|
|
228
|
+
onRef,
|
|
229
|
+
}: {
|
|
230
|
+
/** The document. */
|
|
231
|
+
doc: SpecDocument;
|
|
232
|
+
/** The component shown, or `null` when closed. */
|
|
233
|
+
refValue: string | null;
|
|
234
|
+
/** Closes it. */
|
|
235
|
+
onClose: () => void;
|
|
236
|
+
/** Shows another component. */
|
|
237
|
+
onRef: (ref: string, name: string) => void;
|
|
238
|
+
}) {
|
|
239
|
+
return (
|
|
240
|
+
<Dialog
|
|
241
|
+
open={refValue !== null}
|
|
242
|
+
onClose={onClose}
|
|
243
|
+
title={refValue === null ? "" : refName(refValue)}
|
|
244
|
+
description={refValue ?? undefined}
|
|
245
|
+
size="lg"
|
|
246
|
+
className="http-schema-panel"
|
|
247
|
+
>
|
|
248
|
+
{refValue !== null && (
|
|
249
|
+
<SchemaTree
|
|
250
|
+
key={refValue}
|
|
251
|
+
schema={{ $ref: refValue }}
|
|
252
|
+
root={doc}
|
|
253
|
+
depth={2}
|
|
254
|
+
onRef={onRef}
|
|
255
|
+
label={`Schema ${refName(refValue)}`}
|
|
256
|
+
/>
|
|
257
|
+
)}
|
|
258
|
+
</Dialog>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Props of {@link HttpReference}. */
|
|
263
|
+
export interface HttpReferenceProps {
|
|
264
|
+
/** The OpenAPI document. */
|
|
265
|
+
doc: SpecDocument;
|
|
266
|
+
/** The extension prefixes to read; defaults to the configured ones. */
|
|
267
|
+
extensions?: readonly string[];
|
|
268
|
+
/** The client the try-it panel sends with. Default: built on the document's resolved first server. */
|
|
269
|
+
client?: DocsClient;
|
|
270
|
+
/** Answers "does the caller hold this permission" (the have/lack badge and the try-it gate). */
|
|
271
|
+
probe?: PermissionProbe;
|
|
272
|
+
/** Whether the API is read-only. Defaults to `false`. */
|
|
273
|
+
readOnly?: boolean;
|
|
274
|
+
/** After a successful mutation (the host refreshes what it shows). */
|
|
275
|
+
onChanged?: () => void;
|
|
276
|
+
/** The docs section's path within the host app ("" for a standalone viewer). */
|
|
277
|
+
pathBase?: string;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** The loaded reference: sidebar, info or operation, and the schema panel. */
|
|
281
|
+
export function HttpReference({
|
|
282
|
+
doc,
|
|
283
|
+
extensions,
|
|
284
|
+
client: clientOverride,
|
|
285
|
+
probe,
|
|
286
|
+
readOnly = false,
|
|
287
|
+
onChanged,
|
|
288
|
+
pathBase = "",
|
|
289
|
+
}: HttpReferenceProps) {
|
|
290
|
+
const config = useDocsUiConfig();
|
|
291
|
+
const prefixes = extensions ?? config.extensions;
|
|
292
|
+
const { operationId } = useParams<{ operationId?: string }>();
|
|
293
|
+
const [query, setQuery] = useQueryParam("q");
|
|
294
|
+
const [panel, setPanel] = useState<string | null>(null);
|
|
295
|
+
const info = useMemo(() => readInfo(doc), [doc]);
|
|
296
|
+
const operations = useMemo(
|
|
297
|
+
() => listOperations(doc, { extensions: prefixes }),
|
|
298
|
+
[doc, prefixes],
|
|
299
|
+
);
|
|
300
|
+
const groups = useMemo(() => groupByTag(doc, operations), [doc, operations]);
|
|
301
|
+
const visible = useMemo(() => filterGroups(groups, query), [groups, query]);
|
|
302
|
+
// `undefined` without `x-tagGroups`: the sidebar is then one level, as before.
|
|
303
|
+
const sections = useMemo(() => groupBySection(doc, groups), [doc, groups]);
|
|
304
|
+
const visibleSections = useMemo(
|
|
305
|
+
() => groupBySection(doc, visible),
|
|
306
|
+
[doc, visible],
|
|
307
|
+
);
|
|
308
|
+
const selected =
|
|
309
|
+
operationId === undefined
|
|
310
|
+
? undefined
|
|
311
|
+
: operations.find((operation) => operation.id === operationId);
|
|
312
|
+
const openRef = (ref: string) => setPanel(ref);
|
|
313
|
+
|
|
314
|
+
// The try-it panel and the snippets send to the document's first server,
|
|
315
|
+
// resolved against the origin the document was fetched from.
|
|
316
|
+
const origin = typeof window === "undefined" ? "" : window.location.origin;
|
|
317
|
+
const serverBase = resolveServerUrl(
|
|
318
|
+
info.servers[0]?.url ?? "/",
|
|
319
|
+
config.documentUrl,
|
|
320
|
+
origin,
|
|
321
|
+
);
|
|
322
|
+
const fetcher = useDocsFetch();
|
|
323
|
+
const client = useMemo(
|
|
324
|
+
() =>
|
|
325
|
+
clientOverride ??
|
|
326
|
+
createDocsClient({
|
|
327
|
+
base: serverBase,
|
|
328
|
+
csrfHeader: config.csrfHeader,
|
|
329
|
+
fetch: fetcher,
|
|
330
|
+
}),
|
|
331
|
+
[clientOverride, serverBase, config.csrfHeader, fetcher],
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
return (
|
|
335
|
+
<div
|
|
336
|
+
className="screen http-docs"
|
|
337
|
+
data-testid="http-docs"
|
|
338
|
+
>
|
|
339
|
+
<div className="http-docs-title">
|
|
340
|
+
<h1 className="screen-title">{info.title}</h1>
|
|
341
|
+
</div>
|
|
342
|
+
<div className="http-docs-layout">
|
|
343
|
+
<Sidebar
|
|
344
|
+
groups={visible}
|
|
345
|
+
sections={visibleSections}
|
|
346
|
+
query={query}
|
|
347
|
+
onQuery={(next) => setQuery(next)}
|
|
348
|
+
hrefOf={(id) => operationHref(id, query, pathBase)}
|
|
349
|
+
/>
|
|
350
|
+
<div className="http-docs-main">
|
|
351
|
+
{operationId === undefined ? (
|
|
352
|
+
<>
|
|
353
|
+
<InfoHeader
|
|
354
|
+
info={info}
|
|
355
|
+
serverBase={serverBase}
|
|
356
|
+
/>
|
|
357
|
+
<Overview
|
|
358
|
+
doc={doc}
|
|
359
|
+
groups={groups}
|
|
360
|
+
sections={sections}
|
|
361
|
+
query={query}
|
|
362
|
+
onRef={openRef}
|
|
363
|
+
pathBase={pathBase}
|
|
364
|
+
/>
|
|
365
|
+
</>
|
|
366
|
+
) : selected ? (
|
|
367
|
+
<DocsClientContext value={client}>
|
|
368
|
+
<OperationView
|
|
369
|
+
key={selected.id}
|
|
370
|
+
operation={selected}
|
|
371
|
+
root={doc}
|
|
372
|
+
onRef={openRef}
|
|
373
|
+
probe={probe}
|
|
374
|
+
readOnly={readOnly}
|
|
375
|
+
onChanged={onChanged}
|
|
376
|
+
/>
|
|
377
|
+
</DocsClientContext>
|
|
378
|
+
) : (
|
|
379
|
+
<EmptyState
|
|
380
|
+
title="No such operation"
|
|
381
|
+
description={`This document has no operation "${operationId}".`}
|
|
382
|
+
action={<Link to={`${pathBase}/http`}>All operations</Link>}
|
|
383
|
+
/>
|
|
384
|
+
)}
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
<SchemaPanel
|
|
388
|
+
doc={doc}
|
|
389
|
+
refValue={panel}
|
|
390
|
+
onClose={() => setPanel(null)}
|
|
391
|
+
onRef={openRef}
|
|
392
|
+
/>
|
|
393
|
+
</div>
|
|
394
|
+
);
|
|
395
|
+
}
|