Formatting

This commit is contained in:
Brett Jephson
2024-09-20 11:41:38 +01:00
parent f67b143851
commit 9b78692124
10 changed files with 127 additions and 60 deletions
@@ -55,16 +55,16 @@ async function OpenAPIBody(props: BlockProps<DocumentBlockSwagger>) {
chevronDown: <Icon icon="chevron-down" />,
chevronRight: <Icon icon="chevron-right" />,
edit: <Icon icon="edit" />,
clear: <Icon icon="x" />
clear: <Icon icon="x" />,
},
CodeBlock: PlainCodeBlock,
defaultInteractiveOpened: context.mode === 'print',
id: block.meta?.id,
blockKey: block.key
blockKey: block.key,
}}
className="openapi-block"
/>
</OpenAPIContext>
</OpenAPIContext>
);
}
@@ -1,21 +1,38 @@
'use client'
'use client';
import { DocumentBlock } from "@gitbook/api";
import { OpenAPIOperationData } from "@gitbook/react-openapi";
import {OpenAPIContextProvider} from "@gitbook/react-openapi/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 }) {
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>
}
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>
);
}
@@ -370,7 +370,9 @@
@apply p-0.5 inline-flex text-dark/6 dark:text-light/6 hover:opacity-8;
}
.openapi-edit-button { @apply p-0.5 ml-4 size-4; }
.openapi-edit-button {
@apply p-0.5 ml-4 size-4;
}
.openapi-edit-button > * {
@apply size-full;
@@ -1,34 +1,52 @@
'use client'
'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; }
type OpenAPIContextProps = {
isPending?: boolean;
serverUrl?: string;
state?: Record<string, string> | null;
onUpdate: (params: Record<string, string> | null) => void;
};
const OpenAPIContext = React.createContext<OpenAPIContextProps | null>(null);
export function useOpenAPIContext() {
return React.useContext(OpenAPIContext);
}
export function OpenAPIContextProvider(props: { children: React.ReactNode; data: OpenAPIOperationData; isPending?: boolean; params?: Record<string, string>; onUpdate: OpenAPIContextProps['onUpdate']; }) {
export function OpenAPIContextProvider(props: {
children: React.ReactNode;
data: OpenAPIOperationData;
isPending?: boolean;
params?: Record<string, string>;
onUpdate: OpenAPIContextProps['onUpdate'];
}) {
const { children, data, isPending, params, onUpdate } = props;
const clientState = React.useMemo(() => {
if (!params) { return null; }
if (!params) {
return null;
}
return parseClientStateModifiers(data, params);
}, [data, params]);
const serverUrl = getServersURL(data.servers, clientState ?? undefined)
const serverUrl = getServersURL(data.servers, clientState ?? undefined);
return <OpenAPIContext.Provider value={{
isPending,
state: clientState,
serverUrl,
onUpdate
}}>{children}</OpenAPIContext.Provider>
return (
<OpenAPIContext.Provider
value={{
isPending,
state: clientState,
serverUrl,
onUpdate,
}}
>
{children}
</OpenAPIContext.Provider>
);
}
function parseClientStateModifiers(data: OpenAPIOperationData, params: Record<string, string>) {
if (!data) {
return null;
@@ -39,14 +57,16 @@ function parseClientStateModifiers(data: OpenAPIOperationData, params: Record<st
? 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;
}
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;
}
@@ -18,11 +18,11 @@ export function OpenAPIServerURL(props: {
}) {
const { path, servers, context } = props;
const ctx = useOpenAPIContext();
const serverIndex = !isNaN(Number(ctx?.state?.server)) ? Number(ctx?.state?.server) : 0;
const server = servers[serverIndex];
const parts = parseServerURL(server?.url ?? '');
console.log({ ctxState: ctx?.state })
console.log({ ctxState: ctx?.state });
return (
<ServerURLForm context={context} servers={servers} serverIndex={serverIndex}>
@@ -21,7 +21,7 @@ export function ServerURLForm(props: {
if (index !== serverIndex) {
update({
server: `${index}` ?? '0',
...(ctx?.state?.edit ? { edit: 'true' } : undefined)
...(ctx?.state?.edit ? { edit: 'true' } : undefined),
});
}
}
@@ -37,12 +37,14 @@ export function ServerURLForm(props: {
update({
server: `${formData.get('server')}` ?? '0',
...variables,
...(ctx?.state?.edit ? { edit: 'true' } : undefined)
...(ctx?.state?.edit ? { edit: 'true' } : undefined),
});
}
function update(variables?: Record<string, string>) {
if (!context.blockKey) { return; }
if (!context.blockKey) {
return;
}
ctx?.onUpdate({
block: context.blockKey,
...variables,
@@ -51,22 +53,42 @@ export function ServerURLForm(props: {
const isEditable = servers.length > 1 || server.variables;
return (
<form ref={formRef} onSubmit={e => { e.preventDefault(); updateServerVariables(new FormData(e.currentTarget)); }} className="contents">
<form
ref={formRef}
onSubmit={(e) => {
e.preventDefault();
updateServerVariables(new FormData(e.currentTarget));
}}
className="contents"
>
<fieldset disabled={ctx?.isPending} className="contents">
<input type="hidden" name="block" value={context.blockKey} />
{children}
{ctx?.state?.edit && servers.length > 1 ? (
<ServerSelector
servers={servers}
currentIndex={serverIndex}
onChange={switchServer}
servers={servers}
currentIndex={serverIndex}
onChange={switchServer}
/>
) : null}
{ isEditable ? <button className='openapi-edit-button ml-2' onClick={() => {
const state = { ...ctx?.state };
delete state.edit;
update({ server: `${serverIndex}`, ...state, ...(ctx?.state?.edit ? undefined : { edit: 'true' }) });
}} title={ctx?.state?.edit ? undefined : "Try different server options"} aria-label={ctx?.state?.edit ? "Clear" : "Edit"}>{ctx?.state?.edit ? context.icons.clear : context.icons.edit}</button> : null}
{isEditable ? (
<button
className="openapi-edit-button ml-2"
onClick={() => {
const state = { ...ctx?.state };
delete state.edit;
update({
server: `${serverIndex}`,
...state,
...(ctx?.state?.edit ? undefined : { edit: 'true' }),
});
}}
title={ctx?.state?.edit ? undefined : 'Try different server options'}
aria-label={ctx?.state?.edit ? 'Clear' : 'Edit'}
>
{ctx?.state?.edit ? context.icons.clear : context.icons.edit}
</button>
) : null}
</fieldset>
</form>
);
@@ -16,7 +16,13 @@ export function OpenAPIServerURLVariable(props: {
if (variable.enum && variable.enum.length > 0) {
if (!selectable) {
return <span className={classNames('openapi-url-var')}>{!isNaN(Number(selectionIndex)) ? variable.enum[Number(selectionIndex)] : variable.default}</span>;
return (
<span className={classNames('openapi-url-var')}>
{!isNaN(Number(selectionIndex))
? variable.enum[Number(selectionIndex)]
: variable.default}
</span>
);
}
return (
@@ -57,7 +57,7 @@ export function ScalarApiButton(props: {
/**
* Wrap the rendering with a context to open the scalar modal.
*/
export function ScalarApiClient(props: { children: React.ReactNode; }) {
export function ScalarApiClient(props: { children: React.ReactNode }) {
const { children } = props;
const ctx = useOpenAPIContext();
+1 -1
View File
@@ -1,2 +1,2 @@
'use client';
export {OpenAPIContextProvider} from './OpenAPIContextProvider';
export { OpenAPIContextProvider } from './OpenAPIContextProvider';
+3 -3
View File
@@ -12,7 +12,6 @@ export function createStateKey(key: string, scope?: string) {
return scope ? `${scope}_${key}` : key;
}
/**
* Get the default URL for the server.
*/
@@ -20,7 +19,8 @@ export function getServersURL(
servers: OpenAPIV3.ServerObject[],
selectors?: Record<string, string>,
): string {
const serverIndex = selectors && !isNaN(Number(selectors.server)) ? Number(selectors.server) : 0;
const serverIndex =
selectors && !isNaN(Number(selectors.server)) ? Number(selectors.server) : 0;
const server = servers[serverIndex];
const parts = parseServerURL(server?.url ?? '');
@@ -48,4 +48,4 @@ export function parseServerURL(url: string) {
}
}
return result;
}
}