-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RND-2311: enums for server url in openapi block #2452
Changes from 30 commits
4d476a8
7e79e14
e852206
cb454a3
ca4518d
2d15453
d919d2c
adaf0de
69414bd
3b0f5d8
087a783
9573535
e793a17
b87ec84
4f59d18
c338bca
7244a04
d29a7a6
a6adfaa
3d14790
28c59d8
96d5537
768b555
ea4f70e
0b44528
949f25c
f6b75e7
4b9f206
4026fc1
8d1c349
5b93377
ce890c6
cb3c1f9
abf7ec3
f98b7b2
39d8886
586e66d
60a9b95
c1193fd
1ae1715
77d64d0
9437aa2
f6823e9
ac492e0
f65e3f5
f67b143
9b78692
184d616
74392ec
7b02f72
dce39c4
e866080
662df6f
65d7729
2d4ddc9
c7ca921
9675290
95e8772
0ccc503
3ee149d
152aad2
d19e350
5beb2db
3d9aefa
846de0e
d9ee1a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@gitbook/react-openapi': minor | ||
'gitbook': minor | ||
--- | ||
|
||
Allow selection of server url |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
'use client'; | ||
|
||
import { DocumentBlock } from '@gitbook/api'; | ||
import { OpenAPIOperationData } from '@gitbook/react-openapi'; | ||
import { OpenAPIContextProvider } from '@gitbook/react-openapi/client'; | ||
import { useRouter, useSearchParams } from 'next/navigation'; | ||
import * as React from 'react'; | ||
|
||
export default function OpenAPIContext(props: { | ||
children: React.ReactNode; | ||
block: DocumentBlock; | ||
data: OpenAPIOperationData; | ||
}) { | ||
const { block, children, data } = props; | ||
const [isPending, startTransition] = React.useTransition(); | ||
const router = useRouter(); | ||
const searchParams = useSearchParams(); | ||
|
||
return ( | ||
<OpenAPIContextProvider | ||
isPending={isPending} | ||
data={data} | ||
params={ | ||
searchParams.get('block') === block.key | ||
? Object.fromEntries(searchParams.entries()) | ||
: undefined | ||
} | ||
onUpdate={async (params) => { | ||
startTransition(() => { | ||
const queryParams = new URLSearchParams(params ?? ''); | ||
router.replace(`?${queryParams}`, { scroll: false }); | ||
}); | ||
}} | ||
> | ||
{children} | ||
</OpenAPIContextProvider> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { createSearchParamsCache, parseAsString } from 'nuqs/server'; | ||
|
||
export const serverUrlCache = createSearchParamsCache({ | ||
serverUrl: parseAsString, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
'use client'; | ||
|
||
import * as React from 'react'; | ||
import { OpenAPIOperationData } from './fetchOpenAPIOperation'; | ||
import { getServersURL } from './utils'; | ||
|
||
type OpenAPIContextProps = { | ||
isPending?: boolean; | ||
serverUrl?: string; | ||
state?: Record<string, string> | null; | ||
onUpdate: (params: Record<string, string> | null) => void; | ||
}; | ||
BrettJephson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const OpenAPIContext = React.createContext<OpenAPIContextProps | null>(null); | ||
|
||
export function useOpenAPIContext() { | ||
return React.useContext(OpenAPIContext); | ||
} | ||
|
||
export function OpenAPIContextProvider(props: { | ||
children: React.ReactNode; | ||
data: OpenAPIOperationData; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Passing the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've refactored this a bit but could you explain the comment a bit more? The component is a client component that provides a React context, so I'm not sure how it affects the HTML output. But happy to admit it if I'm wrong as still getting a handle on some of the details of server components. |
||
isPending?: boolean; | ||
params?: Record<string, string>; | ||
onUpdate: OpenAPIContextProps['onUpdate']; | ||
}) { | ||
const { children, data, isPending, params, onUpdate } = props; | ||
|
||
const clientState = React.useMemo(() => { | ||
if (!params) { | ||
return null; | ||
} | ||
return parseClientStateModifiers(data, params); | ||
}, [data, params]); | ||
const serverUrl = getServersURL(data.servers, clientState ?? undefined); | ||
|
||
return ( | ||
<OpenAPIContext.Provider | ||
value={{ | ||
isPending, | ||
state: clientState, | ||
serverUrl, | ||
onUpdate, | ||
}} | ||
> | ||
{children} | ||
</OpenAPIContext.Provider> | ||
); | ||
} | ||
|
||
function parseClientStateModifiers(data: OpenAPIOperationData, params: Record<string, string>) { | ||
if (!data) { | ||
return null; | ||
} | ||
const serverQueryParam = params['server']; | ||
const serverIndex = | ||
serverQueryParam && !isNaN(Number(serverQueryParam)) | ||
? Math.max(0, Math.min(Number(serverQueryParam), data.servers.length - 1)) | ||
: 0; | ||
const server = data.servers[serverIndex]; | ||
return server | ||
? Object.keys(server.variables ?? {}).reduce<Record<string, string>>( | ||
(result, key) => { | ||
const selection = params[key]; | ||
if (!isNaN(Number(selection))) { | ||
result[key] = selection; | ||
} | ||
return result; | ||
}, | ||
{ server: `${serverIndex}`, edit: params['edit'] }, | ||
) | ||
: null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we not supposed to have a
onUpdate
here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This component is a wrapper around the actual context provider (which has the onUpdate) so I could keep it as a client component without polluting the rest of the tree which contains server components. I've renamed it and commented as admittedly wasn't very clear.