mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-20 09:33:21 +00:00
Translate OpenAPI blocks (#3166)
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@gitbook/react-openapi": patch
|
||||||
|
"gitbook": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Translate OpenAPI blocks
|
||||||
@@ -10,18 +10,18 @@ const testCases: TestsCase[] = [
|
|||||||
{ name: 'OpenAPI', url: '/snyk-api/reference/apps', run: waitForCookiesDialog },
|
{ name: 'OpenAPI', url: '/snyk-api/reference/apps', run: waitForCookiesDialog },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
name: 'Nexthink',
|
// name: 'Nexthink',
|
||||||
contentBaseURL: 'https://docs.nexthink.com',
|
// contentBaseURL: 'https://docs.nexthink.com',
|
||||||
tests: [
|
// tests: [
|
||||||
{
|
// {
|
||||||
name: 'Home',
|
// name: 'Home',
|
||||||
url: '/',
|
// url: '/',
|
||||||
screenshot: { waitForTOCScrolling: false },
|
// screenshot: { waitForTOCScrolling: false },
|
||||||
run: waitForCookiesDialog,
|
// run: waitForCookiesDialog,
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
name: 'asiksupport-stg.dto.kemkes.go.id',
|
name: 'asiksupport-stg.dto.kemkes.go.id',
|
||||||
contentBaseURL: 'https://asiksupport-stg.dto.kemkes.go.id',
|
contentBaseURL: 'https://asiksupport-stg.dto.kemkes.go.id',
|
||||||
@@ -157,11 +157,11 @@ const testCases: TestsCase[] = [
|
|||||||
contentBaseURL: 'https://wiki.redmodding.org',
|
contentBaseURL: 'https://wiki.redmodding.org',
|
||||||
tests: [{ name: 'Home', url: '/' }],
|
tests: [{ name: 'Home', url: '/' }],
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
name: 'docs.cherry-ai.com',
|
// name: 'docs.cherry-ai.com',
|
||||||
contentBaseURL: 'https://docs.cherry-ai.com',
|
// contentBaseURL: 'https://docs.cherry-ai.com',
|
||||||
tests: [{ name: 'Home', url: '/', run: waitForCookiesDialog }],
|
// tests: [{ name: 'Home', url: '/', run: waitForCookiesDialog }],
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
name: 'docs.snyk.io',
|
name: 'docs.snyk.io',
|
||||||
contentBaseURL: 'https://docs.snyk.io',
|
contentBaseURL: 'https://docs.snyk.io',
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ async function OpenAPIOperationBody(props: BlockProps<AnyOpenAPIOperationsBlock>
|
|||||||
return (
|
return (
|
||||||
<BaseOpenAPIOperation
|
<BaseOpenAPIOperation
|
||||||
data={data}
|
data={data}
|
||||||
context={getOpenAPIContext({ props, specUrl })}
|
context={getOpenAPIContext({ props, specUrl, context: context.contentContext })}
|
||||||
className="openapi-block"
|
className="openapi-block"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ async function OpenAPISchemasBody(props: BlockProps<OpenAPISchemasBlock>) {
|
|||||||
<BaseOpenAPISchemas
|
<BaseOpenAPISchemas
|
||||||
schemas={data.schemas}
|
schemas={data.schemas}
|
||||||
grouped={block.data.grouped}
|
grouped={block.data.grouped}
|
||||||
context={getOpenAPIContext({ props, specUrl })}
|
context={getOpenAPIContext({ props, specUrl, context: context.contentContext })}
|
||||||
className="openapi-block"
|
className="openapi-block"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ async function OpenAPIWebhookBody(props: BlockProps<OpenAPIWebhookBlock>) {
|
|||||||
return (
|
return (
|
||||||
<BaseOpenAPIWebhook
|
<BaseOpenAPIWebhook
|
||||||
data={data}
|
data={data}
|
||||||
context={getOpenAPIContext({ props, specUrl })}
|
context={getOpenAPIContext({ props, specUrl, context: context.contentContext })}
|
||||||
className="openapi-block"
|
className="openapi-block"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { JSONDocument } from '@gitbook/api';
|
import type { JSONDocument } from '@gitbook/api';
|
||||||
import { Icon } from '@gitbook/icons';
|
import { Icon } from '@gitbook/icons';
|
||||||
import type { OpenAPIContext } from '@gitbook/react-openapi';
|
import { type OpenAPIContextInput, checkIsValidLocale } from '@gitbook/react-openapi';
|
||||||
|
|
||||||
import { tcls } from '@/lib/tailwind';
|
import { tcls } from '@/lib/tailwind';
|
||||||
|
|
||||||
@@ -11,11 +11,13 @@ import { Heading } from '../Heading';
|
|||||||
|
|
||||||
import './scalar.css';
|
import './scalar.css';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
|
import { DEFAULT_LOCALE, getCustomizationLocale } from '@/intl/server';
|
||||||
import type {
|
import type {
|
||||||
AnyOpenAPIOperationsBlock,
|
AnyOpenAPIOperationsBlock,
|
||||||
OpenAPISchemasBlock,
|
OpenAPISchemasBlock,
|
||||||
OpenAPIWebhookBlock,
|
OpenAPIWebhookBlock,
|
||||||
} from '@/lib/openapi/types';
|
} from '@/lib/openapi/types';
|
||||||
|
import type { GitBookAnyContext } from '@v2/lib/context';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the OpenAPI context to render a block.
|
* Get the OpenAPI context to render a block.
|
||||||
@@ -23,9 +25,17 @@ import type {
|
|||||||
export function getOpenAPIContext(args: {
|
export function getOpenAPIContext(args: {
|
||||||
props: BlockProps<AnyOpenAPIOperationsBlock | OpenAPISchemasBlock | OpenAPIWebhookBlock>;
|
props: BlockProps<AnyOpenAPIOperationsBlock | OpenAPISchemasBlock | OpenAPIWebhookBlock>;
|
||||||
specUrl: string;
|
specUrl: string;
|
||||||
}): OpenAPIContext {
|
context: GitBookAnyContext | undefined;
|
||||||
const { props, specUrl } = args;
|
}): OpenAPIContextInput {
|
||||||
|
const { props, specUrl, context } = args;
|
||||||
const { block } = props;
|
const { block } = props;
|
||||||
|
|
||||||
|
const customization = context && 'customization' in context ? context.customization : null;
|
||||||
|
const customizationLocale = customization
|
||||||
|
? getCustomizationLocale(customization)
|
||||||
|
: DEFAULT_LOCALE;
|
||||||
|
const locale = checkIsValidLocale(customizationLocale) ? customizationLocale : DEFAULT_LOCALE;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
specUrl,
|
specUrl,
|
||||||
icons: {
|
icons: {
|
||||||
@@ -73,5 +83,6 @@ export function getOpenAPIContext(args: {
|
|||||||
defaultInteractiveOpened: props.context.mode === 'print',
|
defaultInteractiveOpened: props.context.mode === 'print',
|
||||||
id: block.meta?.id,
|
id: block.meta?.id,
|
||||||
blockKey: block.key,
|
blockKey: block.key,
|
||||||
|
locale,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -229,19 +229,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-required {
|
.openapi-schema-required {
|
||||||
@apply text-warning-subtle text-[0.813rem];
|
@apply text-warning-subtle text-[0.813rem] lowercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-optional {
|
.openapi-schema-optional {
|
||||||
@apply text-info-subtle text-[0.813rem];
|
@apply text-info-subtle text-[0.813rem] lowercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-readonly {
|
.openapi-schema-readonly {
|
||||||
@apply text-primary-subtle/9 text-[0.813rem];
|
@apply text-primary-subtle/9 text-[0.813rem] lowercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-writeonly {
|
.openapi-schema-writeonly {
|
||||||
@apply text-success dark:text-success-subtle/9 text-[0.813rem];
|
@apply text-success dark:text-success-subtle/9 text-[0.813rem] lowercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-type {
|
.openapi-schema-type {
|
||||||
|
|||||||
@@ -4,17 +4,26 @@ import { type TranslationLanguage, languages } from './translations';
|
|||||||
|
|
||||||
export * from './translate';
|
export * from './translate';
|
||||||
|
|
||||||
|
export const DEFAULT_LOCALE = 'en';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the locale of the customization.
|
||||||
|
*/
|
||||||
|
export function getCustomizationLocale(customization: SiteCustomizationSettings): string {
|
||||||
|
return customization.internationalization.locale;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the translation context for a space to use in the server components.
|
* Create the translation context for a space to use in the server components.
|
||||||
*/
|
*/
|
||||||
export function getSpaceLanguage(customization: SiteCustomizationSettings): TranslationLanguage {
|
export function getSpaceLanguage(customization: SiteCustomizationSettings): TranslationLanguage {
|
||||||
const fallback = languages.en;
|
const fallback = languages[DEFAULT_LOCALE];
|
||||||
|
|
||||||
const { locale } = customization.internationalization;
|
const locale = getCustomizationLocale(customization);
|
||||||
|
|
||||||
let language = fallback;
|
let language = fallback;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (locale !== 'en' && languages[locale]) {
|
if (locale !== DEFAULT_LOCALE && languages[locale]) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
language = languages[locale];
|
language = languages[locale];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ export function InteractiveSection(props: {
|
|||||||
) : null}
|
) : null}
|
||||||
{header}
|
{header}
|
||||||
</SectionHeaderContent>
|
</SectionHeaderContent>
|
||||||
|
{/* biome-ignore lint/a11y/useKeyWithClickEvents: we prevent default here */}
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'openapi-section-header-controls',
|
'openapi-section-header-controls',
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import {
|
|||||||
import { OpenAPICodeSampleBody } from './OpenAPICodeSampleSelector';
|
import { OpenAPICodeSampleBody } from './OpenAPICodeSampleSelector';
|
||||||
import { ScalarApiButton } from './ScalarApiButton';
|
import { ScalarApiButton } from './ScalarApiButton';
|
||||||
import { type CodeSampleGenerator, codeSampleGenerators } from './code-samples';
|
import { type CodeSampleGenerator, codeSampleGenerators } from './code-samples';
|
||||||
|
import { type OpenAPIContext, getOpenAPIClientContext } from './context';
|
||||||
import { generateMediaTypeExamples, generateSchemaExample } from './generateSchemaExample';
|
import { generateMediaTypeExamples, generateSchemaExample } from './generateSchemaExample';
|
||||||
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
||||||
import type { OpenAPIContext, OpenAPIOperationData } from './types';
|
import type { OpenAPIOperationData } from './types';
|
||||||
import { getDefaultServerURL } from './util/server';
|
import { getDefaultServerURL } from './util/server';
|
||||||
import { checkIsReference } from './utils';
|
import { checkIsReference } from './utils';
|
||||||
|
|
||||||
@@ -44,7 +45,12 @@ export function OpenAPICodeSample(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OpenAPICodeSampleBody data={data} items={samples} selectIcon={context.icons.chevronDown} />
|
<OpenAPICodeSampleBody
|
||||||
|
context={getOpenAPIClientContext(context)}
|
||||||
|
data={data}
|
||||||
|
items={samples}
|
||||||
|
selectIcon={context.icons.chevronDown}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +221,14 @@ function OpenAPICodeSampleFooter(props: {
|
|||||||
) : (
|
) : (
|
||||||
<span />
|
<span />
|
||||||
)}
|
)}
|
||||||
{!hideTryItPanel && <ScalarApiButton method={method} path={path} specUrl={specUrl} />}
|
{!hideTryItPanel && (
|
||||||
|
<ScalarApiButton
|
||||||
|
context={getOpenAPIClientContext(context)}
|
||||||
|
method={method}
|
||||||
|
path={path}
|
||||||
|
specUrl={specUrl}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useStore } from 'zustand';
|
|||||||
import { OpenAPIPath } from './OpenAPIPath';
|
import { OpenAPIPath } from './OpenAPIPath';
|
||||||
import { OpenAPISelect, OpenAPISelectItem } from './OpenAPISelect';
|
import { OpenAPISelect, OpenAPISelectItem } from './OpenAPISelect';
|
||||||
import { StaticSection } from './StaticSection';
|
import { StaticSection } from './StaticSection';
|
||||||
|
import type { OpenAPIClientContext } from './context';
|
||||||
import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
|
import { getOrCreateStoreByKey } from './getOrCreateStoreByKey';
|
||||||
import type { OpenAPIOperationData } from './types';
|
import type { OpenAPIOperationData } from './types';
|
||||||
|
|
||||||
@@ -26,12 +27,13 @@ function OpenAPICodeSampleHeader(props: {
|
|||||||
items: CodeSampleItem[];
|
items: CodeSampleItem[];
|
||||||
data: OpenAPIOperationData;
|
data: OpenAPIOperationData;
|
||||||
selectIcon?: React.ReactNode;
|
selectIcon?: React.ReactNode;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
const { data, items, selectIcon } = props;
|
const { data, items, selectIcon, context } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<OpenAPIPath canCopy={false} withServer={false} data={data} />
|
<OpenAPIPath context={context} canCopy={false} withServer={false} data={data} />
|
||||||
{items.length > 1 ? (
|
{items.length > 1 ? (
|
||||||
<OpenAPISelect
|
<OpenAPISelect
|
||||||
icon={selectIcon}
|
icon={selectIcon}
|
||||||
@@ -56,8 +58,9 @@ export function OpenAPICodeSampleBody(props: {
|
|||||||
items: CodeSampleItem[];
|
items: CodeSampleItem[];
|
||||||
data: OpenAPIOperationData;
|
data: OpenAPIOperationData;
|
||||||
selectIcon?: React.ReactNode;
|
selectIcon?: React.ReactNode;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
const { items, data, selectIcon } = props;
|
const { items, data, selectIcon, context } = props;
|
||||||
if (!items[0]) {
|
if (!items[0]) {
|
||||||
throw new Error('No items provided');
|
throw new Error('No items provided');
|
||||||
}
|
}
|
||||||
@@ -72,7 +75,14 @@ export function OpenAPICodeSampleBody(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StaticSection
|
<StaticSection
|
||||||
header={<OpenAPICodeSampleHeader selectIcon={selectIcon} data={data} items={items} />}
|
header={
|
||||||
|
<OpenAPICodeSampleHeader
|
||||||
|
context={context}
|
||||||
|
selectIcon={selectIcon}
|
||||||
|
data={data}
|
||||||
|
items={items}
|
||||||
|
/>
|
||||||
|
}
|
||||||
className="openapi-codesample"
|
className="openapi-codesample"
|
||||||
>
|
>
|
||||||
<div id={selected.key as string} className="openapi-codesample-panel">
|
<div id={selected.key as string} className="openapi-codesample-panel">
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Button, type ButtonProps, Tooltip, TooltipTrigger } from 'react-aria-components';
|
import { Button, type ButtonProps, Tooltip, TooltipTrigger } from 'react-aria-components';
|
||||||
|
import type { OpenAPIClientContext } from './context';
|
||||||
|
import { t } from './translate';
|
||||||
|
|
||||||
export function OpenAPICopyButton(
|
export function OpenAPICopyButton(
|
||||||
props: ButtonProps & {
|
props: ButtonProps & {
|
||||||
value: string;
|
value: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
label?: string;
|
label?: string;
|
||||||
/**
|
/**
|
||||||
* Whether to show a tooltip.
|
* Whether to show a tooltip.
|
||||||
@@ -15,7 +18,7 @@ export function OpenAPICopyButton(
|
|||||||
withTooltip?: boolean;
|
withTooltip?: boolean;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const { value, label, children, onPress, className, withTooltip = true } = props;
|
const { value, label, children, onPress, className, context, withTooltip = true } = props;
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
@@ -60,7 +63,9 @@ export function OpenAPICopyButton(
|
|||||||
offset={4}
|
offset={4}
|
||||||
className="openapi-tooltip"
|
className="openapi-tooltip"
|
||||||
>
|
>
|
||||||
{copied ? 'Copied' : label || 'Copy to clipboard'}
|
{copied
|
||||||
|
? t(context.translation, 'copied')
|
||||||
|
: label || t(context.translation, 'copy_to_clipboard')}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
|
import type { OpenAPIContext, OpenAPIUniversalContext } from './context';
|
||||||
import { json2xml } from './json2xml';
|
import { json2xml } from './json2xml';
|
||||||
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
||||||
import type { OpenAPIContext } from './types';
|
import { t } from './translate';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display an example.
|
* Display an example.
|
||||||
@@ -15,7 +16,7 @@ export function OpenAPIExample(props: {
|
|||||||
const code = stringifyExample({ example, xml: syntax === 'xml' });
|
const code = stringifyExample({ example, xml: syntax === 'xml' });
|
||||||
|
|
||||||
if (code === null) {
|
if (code === null) {
|
||||||
return <OpenAPIEmptyExample />;
|
return <OpenAPIEmptyExample context={context} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.renderCodeBlock({ code, syntax });
|
return context.renderCodeBlock({ code, syntax });
|
||||||
@@ -42,10 +43,13 @@ function stringifyExample(args: { example: OpenAPIV3.ExampleObject; xml: boolean
|
|||||||
/**
|
/**
|
||||||
* Empty response example.
|
* Empty response example.
|
||||||
*/
|
*/
|
||||||
export function OpenAPIEmptyExample() {
|
export function OpenAPIEmptyExample(props: {
|
||||||
|
context: OpenAPIUniversalContext;
|
||||||
|
}) {
|
||||||
|
const { context } = props;
|
||||||
return (
|
return (
|
||||||
<pre className="openapi-example-empty">
|
<pre className="openapi-example-empty">
|
||||||
<p>No Content</p>
|
<p>{t(context.translation, 'no_content')}</p>
|
||||||
</pre>
|
</pre>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import type { Key } from 'react-aria';
|
import type { Key } from 'react-aria';
|
||||||
import { OpenAPIEmptyExample } from './OpenAPIExample';
|
import { OpenAPIEmptyExample } from './OpenAPIExample';
|
||||||
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from './OpenAPISelect';
|
import { OpenAPISelect, OpenAPISelectItem, useSelectState } from './OpenAPISelect';
|
||||||
import { StaticSection } from './StaticSection';
|
import { StaticSection } from './StaticSection';
|
||||||
|
import type { OpenAPIClientContext } from './context';
|
||||||
|
|
||||||
type OpenAPIMediaTypeItem = OpenAPISelectItem & {
|
type OpenAPIMediaTypeItem = OpenAPISelectItem & {
|
||||||
body: React.ReactNode;
|
body: React.ReactNode;
|
||||||
@@ -24,8 +26,9 @@ export function OpenAPIMediaTypeContent(props: {
|
|||||||
items: OpenAPIMediaTypeItem[];
|
items: OpenAPIMediaTypeItem[];
|
||||||
selectIcon?: React.ReactNode;
|
selectIcon?: React.ReactNode;
|
||||||
stateKey: string;
|
stateKey: string;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
const { stateKey, items, selectIcon } = props;
|
const { stateKey, items, selectIcon, context } = props;
|
||||||
const state = useMediaTypesState(stateKey, items[0]?.key);
|
const state = useMediaTypesState(stateKey, items[0]?.key);
|
||||||
|
|
||||||
const examples = items.find((item) => item.key === state.key)?.examples ?? [];
|
const examples = items.find((item) => item.key === state.key)?.examples ?? [];
|
||||||
@@ -48,7 +51,12 @@ export function OpenAPIMediaTypeContent(props: {
|
|||||||
}
|
}
|
||||||
className="openapi-response-media-types-examples"
|
className="openapi-response-media-types-examples"
|
||||||
>
|
>
|
||||||
<OpenAPIMediaTypeBody stateKey={stateKey} items={items} examples={examples} />
|
<OpenAPIMediaTypeBody
|
||||||
|
context={context}
|
||||||
|
stateKey={stateKey}
|
||||||
|
items={items}
|
||||||
|
examples={examples}
|
||||||
|
/>
|
||||||
</StaticSection>
|
</StaticSection>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -100,8 +108,9 @@ function OpenAPIMediaTypeBody(props: {
|
|||||||
items: OpenAPIMediaTypeItem[];
|
items: OpenAPIMediaTypeItem[];
|
||||||
examples?: OpenAPIMediaTypeItem[];
|
examples?: OpenAPIMediaTypeItem[];
|
||||||
stateKey: string;
|
stateKey: string;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
const { stateKey, items, examples } = props;
|
const { stateKey, items, examples, context } = props;
|
||||||
const state = useMediaTypesState(stateKey, items[0]?.key);
|
const state = useMediaTypesState(stateKey, items[0]?.key);
|
||||||
|
|
||||||
const selectedItem = items.find((item) => item.key === state.key) ?? items[0];
|
const selectedItem = items.find((item) => item.key === state.key) ?? items[0];
|
||||||
@@ -120,7 +129,7 @@ function OpenAPIMediaTypeBody(props: {
|
|||||||
examples.find((example) => example.key === exampleState.key) ?? examples[0];
|
examples.find((example) => example.key === exampleState.key) ?? examples[0];
|
||||||
|
|
||||||
if (!selectedExample) {
|
if (!selectedExample) {
|
||||||
return <OpenAPIEmptyExample />;
|
return <OpenAPIEmptyExample context={context} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectedExample.body;
|
return selectedExample.body;
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { OpenAPICodeSample } from './OpenAPICodeSample';
|
|||||||
import { OpenAPIResponseExample } from './OpenAPIResponseExample';
|
import { OpenAPIResponseExample } from './OpenAPIResponseExample';
|
||||||
import { OpenAPIColumnSpec } from './common/OpenAPIColumnSpec';
|
import { OpenAPIColumnSpec } from './common/OpenAPIColumnSpec';
|
||||||
import { OpenAPISummary } from './common/OpenAPISummary';
|
import { OpenAPISummary } from './common/OpenAPISummary';
|
||||||
import type { OpenAPIContext, OpenAPIOperationData } from './types';
|
import { type OpenAPIContextInput, resolveOpenAPIContext } from './context';
|
||||||
|
import type { OpenAPIOperationData } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display an interactive OpenAPI operation.
|
* Display an interactive OpenAPI operation.
|
||||||
@@ -11,9 +12,11 @@ import type { OpenAPIContext, OpenAPIOperationData } from './types';
|
|||||||
export function OpenAPIOperation(props: {
|
export function OpenAPIOperation(props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
data: OpenAPIOperationData;
|
data: OpenAPIOperationData;
|
||||||
context: OpenAPIContext;
|
context: OpenAPIContextInput;
|
||||||
}) {
|
}) {
|
||||||
const { className, data, context } = props;
|
const { className, data, context: contextInput } = props;
|
||||||
|
|
||||||
|
const context = resolveOpenAPIContext(contextInput);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('openapi-operation', className)}>
|
<div className={clsx('openapi-operation', className)}>
|
||||||
@@ -22,8 +25,8 @@ export function OpenAPIOperation(props: {
|
|||||||
<OpenAPIColumnSpec data={data} context={context} />
|
<OpenAPIColumnSpec data={data} context={context} />
|
||||||
<div className="openapi-column-preview">
|
<div className="openapi-column-preview">
|
||||||
<div className="openapi-column-preview-body">
|
<div className="openapi-column-preview-body">
|
||||||
<OpenAPICodeSample {...props} />
|
<OpenAPICodeSample data={data} context={context} />
|
||||||
<OpenAPIResponseExample {...props} />
|
<OpenAPIResponseExample data={data} context={context} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
|
import { Markdown } from './Markdown';
|
||||||
|
import type { OpenAPIContext } from './context';
|
||||||
|
import { resolveDescription } from './utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the description of an OpenAPI operation.
|
||||||
|
*/
|
||||||
|
export function OpenAPIOperationDescription(props: {
|
||||||
|
operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
|
||||||
|
context: OpenAPIContext;
|
||||||
|
}) {
|
||||||
|
const { operation } = props;
|
||||||
|
if (operation['x-gitbook-description-document']) {
|
||||||
|
return (
|
||||||
|
<div className="openapi-intro">
|
||||||
|
{props.context.renderDocument({
|
||||||
|
document: operation['x-gitbook-description-document'],
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const description = resolveDescription(operation);
|
||||||
|
if (!description) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="openapi-intro">
|
||||||
|
<Markdown className="openapi-description" source={description} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import type { OpenAPIStability } from '@gitbook/openapi-parser';
|
||||||
|
import type { OpenAPIContext } from './context';
|
||||||
|
import { t } from './translate';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the stability of an OpenAPI operation.
|
||||||
|
*/
|
||||||
|
export function OpenAPIOperationStability(props: {
|
||||||
|
stability: OpenAPIStability;
|
||||||
|
context: OpenAPIContext;
|
||||||
|
}) {
|
||||||
|
const { stability, context } = props;
|
||||||
|
|
||||||
|
const stabilityLabel = getStabilityLabel(stability, context);
|
||||||
|
|
||||||
|
if (!stabilityLabel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`openapi-stability openapi-stability-${stability}`}>{stabilityLabel}</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the stability label for the given stability level.
|
||||||
|
*/
|
||||||
|
function getStabilityLabel(stability: OpenAPIStability, context: OpenAPIContext) {
|
||||||
|
switch (stability) {
|
||||||
|
case 'experimental':
|
||||||
|
return t(context.translation, 'stability_experimental');
|
||||||
|
case 'alpha':
|
||||||
|
return t(context.translation, 'stability_alpha');
|
||||||
|
case 'beta':
|
||||||
|
return t(context.translation, 'stability_beta');
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { OpenAPICopyButton } from './OpenAPICopyButton';
|
import { OpenAPICopyButton } from './OpenAPICopyButton';
|
||||||
|
import { type OpenAPIUniversalContext, getOpenAPIClientContext } from './context';
|
||||||
import type { OpenAPIOperationData } from './types';
|
import type { OpenAPIOperationData } from './types';
|
||||||
import { getDefaultServerURL } from './util/server';
|
import { getDefaultServerURL } from './util/server';
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@ import { getDefaultServerURL } from './util/server';
|
|||||||
*/
|
*/
|
||||||
export function OpenAPIPath(props: {
|
export function OpenAPIPath(props: {
|
||||||
data: OpenAPIOperationData;
|
data: OpenAPIOperationData;
|
||||||
|
context: OpenAPIUniversalContext;
|
||||||
/** Whether to show the server URL.
|
/** Whether to show the server URL.
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
@@ -17,7 +19,7 @@ export function OpenAPIPath(props: {
|
|||||||
*/
|
*/
|
||||||
canCopy?: boolean;
|
canCopy?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { data, withServer = true, canCopy = true } = props;
|
const { data, context, withServer = true, canCopy = true } = props;
|
||||||
const { method, path, operation } = data;
|
const { method, path, operation } = data;
|
||||||
|
|
||||||
const server = getDefaultServerURL(data.servers);
|
const server = getDefaultServerURL(data.servers);
|
||||||
@@ -41,6 +43,7 @@ export function OpenAPIPath(props: {
|
|||||||
className="openapi-path-title"
|
className="openapi-path-title"
|
||||||
data-deprecated={operation.deprecated}
|
data-deprecated={operation.deprecated}
|
||||||
isDisabled={!canCopy}
|
isDisabled={!canCopy}
|
||||||
|
context={getOpenAPIClientContext(context)}
|
||||||
>
|
>
|
||||||
{element}
|
{element}
|
||||||
</OpenAPICopyButton>
|
</OpenAPICopyButton>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import { InteractiveSection } from './InteractiveSection';
|
import { InteractiveSection } from './InteractiveSection';
|
||||||
import { OpenAPIRootSchema } from './OpenAPISchemaServer';
|
import { OpenAPIRootSchema } from './OpenAPISchemaServer';
|
||||||
import type { OpenAPIClientContext, OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
import type { OpenAPIClientContext } from './context';
|
||||||
|
import { t } from './translate';
|
||||||
|
import type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
||||||
import { checkIsReference, createStateKey } from './utils';
|
import { checkIsReference, createStateKey } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,11 +20,9 @@ export function OpenAPIRequestBody(props: {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const header = 'name' in data ? 'Payload' : 'Body';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InteractiveSection
|
<InteractiveSection
|
||||||
header={header}
|
header={t(context.translation, 'name' in data ? 'payload' : 'body')}
|
||||||
className="openapi-requestbody"
|
className="openapi-requestbody"
|
||||||
stateKey={createStateKey('request-body-media-type', context.blockKey)}
|
stateKey={createStateKey('request-body-media-type', context.blockKey)}
|
||||||
selectIcon={context.icons.chevronDown}
|
selectIcon={context.icons.chevronDown}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
||||||
import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
|
import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
|
||||||
import type { OpenAPIClientContext } from './types';
|
import type { OpenAPIClientContext } from './context';
|
||||||
import { parameterToProperty, resolveDescription } from './utils';
|
import { parameterToProperty, resolveDescription } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { Markdown } from './Markdown';
|
|||||||
import { OpenAPIEmptyExample, OpenAPIExample } from './OpenAPIExample';
|
import { OpenAPIEmptyExample, OpenAPIExample } from './OpenAPIExample';
|
||||||
import { OpenAPIMediaTypeContent } from './OpenAPIMediaType';
|
import { OpenAPIMediaTypeContent } from './OpenAPIMediaType';
|
||||||
import { OpenAPIResponseExampleContent } from './OpenAPIResponseExampleContent';
|
import { OpenAPIResponseExampleContent } from './OpenAPIResponseExampleContent';
|
||||||
import type { OpenAPIContext, OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
import { type OpenAPIContext, getOpenAPIClientContext } from './context';
|
||||||
|
import type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
||||||
import { getExampleFromReference, getExamples } from './util/example';
|
import { getExampleFromReference, getExamples } from './util/example';
|
||||||
import { createStateKey, getStatusCodeDefaultLabel } from './utils';
|
import { createStateKey, getStatusCodeDefaultLabel } from './utils';
|
||||||
import { checkIsReference, resolveDescription } from './utils';
|
import { checkIsReference, resolveDescription } from './utils';
|
||||||
@@ -45,7 +46,7 @@ export function OpenAPIResponseExample(props: {
|
|||||||
const label = description ? (
|
const label = description ? (
|
||||||
<Markdown source={description} />
|
<Markdown source={description} />
|
||||||
) : (
|
) : (
|
||||||
getStatusCodeDefaultLabel(key)
|
getStatusCodeDefaultLabel(key, context)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (checkIsReference(responseObject)) {
|
if (checkIsReference(responseObject)) {
|
||||||
@@ -55,7 +56,7 @@ export function OpenAPIResponseExample(props: {
|
|||||||
statusCode: key,
|
statusCode: key,
|
||||||
body: (
|
body: (
|
||||||
<OpenAPIExample
|
<OpenAPIExample
|
||||||
example={getExampleFromReference(responseObject)}
|
example={getExampleFromReference(responseObject, context)}
|
||||||
context={context}
|
context={context}
|
||||||
syntax="json"
|
syntax="json"
|
||||||
/>
|
/>
|
||||||
@@ -68,7 +69,7 @@ export function OpenAPIResponseExample(props: {
|
|||||||
key: key,
|
key: key,
|
||||||
label,
|
label,
|
||||||
statusCode: key,
|
statusCode: key,
|
||||||
body: <OpenAPIEmptyExample />,
|
body: <OpenAPIEmptyExample context={context} />,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +128,7 @@ function OpenAPIResponse(props: {
|
|||||||
selectIcon={context.icons.chevronDown}
|
selectIcon={context.icons.chevronDown}
|
||||||
stateKey={createStateKey('response-media-types', context.blockKey)}
|
stateKey={createStateKey('response-media-types', context.blockKey)}
|
||||||
items={tabs}
|
items={tabs}
|
||||||
|
context={getOpenAPIClientContext(context)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import { OpenAPIDisclosureGroup } from './OpenAPIDisclosureGroup';
|
|||||||
import { OpenAPIResponse } from './OpenAPIResponse';
|
import { OpenAPIResponse } from './OpenAPIResponse';
|
||||||
import { useResponseExamplesState } from './OpenAPIResponseExampleContent';
|
import { useResponseExamplesState } from './OpenAPIResponseExampleContent';
|
||||||
import { StaticSection } from './StaticSection';
|
import { StaticSection } from './StaticSection';
|
||||||
import type { OpenAPIClientContext } from './types';
|
import type { OpenAPIClientContext } from './context';
|
||||||
|
import { t } from './translate';
|
||||||
import { createStateKey, getStatusCodeClassName, getStatusCodeDefaultLabel } from './utils';
|
import { createStateKey, getStatusCodeClassName, getStatusCodeDefaultLabel } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,7 +77,7 @@ export function OpenAPIResponses(props: {
|
|||||||
className="openapi-response-description"
|
className="openapi-response-description"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
getStatusCodeDefaultLabel(statusCode)
|
getStatusCodeDefaultLabel(statusCode, context)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
@@ -88,7 +89,7 @@ export function OpenAPIResponses(props: {
|
|||||||
const state = useResponseExamplesState(context.blockKey, groups[0]?.key);
|
const state = useResponseExamplesState(context.blockKey, groups[0]?.key);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StaticSection header="Responses" className="openapi-responses">
|
<StaticSection header={t(context.translation, 'responses')} className="openapi-responses">
|
||||||
<OpenAPIDisclosureGroup
|
<OpenAPIDisclosureGroup
|
||||||
icon={context.icons.chevronRight}
|
icon={context.icons.chevronRight}
|
||||||
expandedKeys={state.key ? new Set([state.key]) : new Set()}
|
expandedKeys={state.key ? new Set([state.key]) : new Set()}
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ import { Markdown } from './Markdown';
|
|||||||
import { OpenAPICopyButton } from './OpenAPICopyButton';
|
import { OpenAPICopyButton } from './OpenAPICopyButton';
|
||||||
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
||||||
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
||||||
|
import type { OpenAPIClientContext } from './context';
|
||||||
import { retrocycle } from './decycle';
|
import { retrocycle } from './decycle';
|
||||||
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
||||||
import type { OpenAPIClientContext } from './types';
|
import { tString } from './translate';
|
||||||
import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
|
import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
|
||||||
|
|
||||||
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
|
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
|
||||||
@@ -40,7 +41,7 @@ function OpenAPISchemaProperty(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={id} className={clsx('openapi-schema', className)}>
|
<div id={id} className={clsx('openapi-schema', className)}>
|
||||||
<OpenAPISchemaPresentation property={property} />
|
<OpenAPISchemaPresentation context={context} property={property} />
|
||||||
{(() => {
|
{(() => {
|
||||||
const circularRefId = parentCircularRefs.get(schema);
|
const circularRefId = parentCircularRefs.get(schema);
|
||||||
// Avoid recursing infinitely, and instead render a link to the parent schema
|
// Avoid recursing infinitely, and instead render a link to the parent schema
|
||||||
@@ -56,7 +57,9 @@ function OpenAPISchemaProperty(props: {
|
|||||||
return (
|
return (
|
||||||
<OpenAPIDisclosure
|
<OpenAPIDisclosure
|
||||||
icon={context.icons.plus}
|
icon={context.icons.plus}
|
||||||
label={(isExpanded) => getDisclosureLabel(schema, isExpanded)}
|
label={(isExpanded) =>
|
||||||
|
getDisclosureLabel({ schema, isExpanded, context })
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
properties={properties}
|
properties={properties}
|
||||||
@@ -213,7 +216,7 @@ function OpenAPISchemaAlternative(props: {
|
|||||||
) : null}
|
) : null}
|
||||||
<OpenAPIDisclosure
|
<OpenAPIDisclosure
|
||||||
icon={context.icons.plus}
|
icon={context.icons.plus}
|
||||||
label={(isExpanded) => getDisclosureLabel(schema, isExpanded)}
|
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
||||||
>
|
>
|
||||||
{properties?.length ? (
|
{properties?.length ? (
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
@@ -252,8 +255,9 @@ function OpenAPISchemaCircularRef(props: { id: string; schema: OpenAPIV3.SchemaO
|
|||||||
*/
|
*/
|
||||||
function OpenAPISchemaEnum(props: {
|
function OpenAPISchemaEnum(props: {
|
||||||
schema: OpenAPIV3.SchemaObject & OpenAPICustomOperationProperties;
|
schema: OpenAPIV3.SchemaObject & OpenAPICustomOperationProperties;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
const { schema } = props;
|
const { schema, context } = props;
|
||||||
|
|
||||||
const enumValues = (() => {
|
const enumValues = (() => {
|
||||||
// Render x-gitbook-enum first, as it has a different format
|
// Render x-gitbook-enum first, as it has a different format
|
||||||
@@ -296,6 +300,7 @@ function OpenAPISchemaEnum(props: {
|
|||||||
value={item.value}
|
value={item.value}
|
||||||
label={item.description}
|
label={item.description}
|
||||||
withTooltip={!!item.description}
|
withTooltip={!!item.description}
|
||||||
|
context={context}
|
||||||
>
|
>
|
||||||
<code>{`${item.value}`}</code>
|
<code>{`${item.value}`}</code>
|
||||||
</OpenAPICopyButton>
|
</OpenAPICopyButton>
|
||||||
@@ -308,9 +313,13 @@ function OpenAPISchemaEnum(props: {
|
|||||||
/**
|
/**
|
||||||
* Render the top row of a schema. e.g: name, type, and required status.
|
* Render the top row of a schema. e.g: name, type, and required status.
|
||||||
*/
|
*/
|
||||||
function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry }) {
|
function OpenAPISchemaPresentation(props: {
|
||||||
|
property: OpenAPISchemaPropertyEntry;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
|
}) {
|
||||||
const {
|
const {
|
||||||
property: { schema, propertyName, required },
|
property: { schema, propertyName, required },
|
||||||
|
context,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const description = resolveDescription(schema);
|
const description = resolveDescription(schema);
|
||||||
@@ -323,6 +332,7 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
|
|||||||
type={getSchemaTitle(schema)}
|
type={getSchemaTitle(schema)}
|
||||||
propertyName={propertyName}
|
propertyName={propertyName}
|
||||||
required={required}
|
required={required}
|
||||||
|
context={context}
|
||||||
/>
|
/>
|
||||||
{typeof schema['x-deprecated-sunset'] === 'string' ? (
|
{typeof schema['x-deprecated-sunset'] === 'string' ? (
|
||||||
<div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
|
<div className="openapi-deprecated-sunset openapi-schema-description openapi-markdown">
|
||||||
@@ -355,7 +365,7 @@ function OpenAPISchemaPresentation(props: { property: OpenAPISchemaPropertyEntry
|
|||||||
Pattern: <code>{schema.pattern}</code>
|
Pattern: <code>{schema.pattern}</code>
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
<OpenAPISchemaEnum schema={schema} />
|
<OpenAPISchemaEnum schema={schema} context={context} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -592,21 +602,26 @@ function getSchemaTitle(schema: OpenAPIV3.SchemaObject): string {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisclosureLabel(schema: OpenAPIV3.SchemaObject, isExpanded: boolean) {
|
function getDisclosureLabel(props: {
|
||||||
|
schema: OpenAPIV3.SchemaObject;
|
||||||
|
isExpanded: boolean;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
|
}) {
|
||||||
|
const { schema, isExpanded, context } = props;
|
||||||
let label: string;
|
let label: string;
|
||||||
if (schema.type === 'array' && !!schema.items) {
|
if (schema.type === 'array' && !!schema.items) {
|
||||||
if (schema.items.oneOf) {
|
if (schema.items.oneOf) {
|
||||||
label = 'available items';
|
label = tString(context.translation, 'available_items').toLowerCase();
|
||||||
}
|
}
|
||||||
// Fallback to "child attributes" for enums and objects
|
// Fallback to "child attributes" for enums and objects
|
||||||
else if (schema.items.enum || schema.items.type === 'object') {
|
else if (schema.items.enum || schema.items.type === 'object') {
|
||||||
label = 'child attributes';
|
label = tString(context.translation, 'child_attributes').toLowerCase();
|
||||||
} else {
|
} else {
|
||||||
label = schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
|
label = schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
label = schema.title || 'child attributes';
|
label = schema.title || tString(context.translation, 'child_attributes').toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${isExpanded ? 'Hide' : 'Show'} ${label}`;
|
return `${isExpanded ? tString(context.translation, 'hide') : tString(context.translation, 'show')} ${label}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
|
import type { OpenAPIClientContext } from './context';
|
||||||
|
import { t, tString } from './translate';
|
||||||
|
|
||||||
interface OpenAPISchemaNameProps {
|
interface OpenAPISchemaNameProps {
|
||||||
schema?: OpenAPIV3.SchemaObject;
|
schema?: OpenAPIV3.SchemaObject;
|
||||||
propertyName?: string | React.JSX.Element;
|
propertyName?: string | React.JSX.Element;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
type?: string;
|
type?: string;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,9 +16,9 @@ interface OpenAPISchemaNameProps {
|
|||||||
* It includes the property name, type, required and deprecated status.
|
* It includes the property name, type, required and deprecated status.
|
||||||
*/
|
*/
|
||||||
export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
||||||
const { schema, type, propertyName, required } = props;
|
const { schema, type, propertyName, required, context } = props;
|
||||||
|
|
||||||
const additionalItems = schema && getAdditionalItems(schema);
|
const additionalItems = schema && getAdditionalItems(schema, context);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="openapi-schema-name">
|
<span className="openapi-schema-name">
|
||||||
@@ -30,33 +33,45 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
|||||||
<span className="openapi-schema-type">{additionalItems}</span>
|
<span className="openapi-schema-type">{additionalItems}</span>
|
||||||
) : null}
|
) : null}
|
||||||
</span>
|
</span>
|
||||||
{schema?.readOnly ? <span className="openapi-schema-readonly">read-only</span> : null}
|
{schema?.readOnly ? (
|
||||||
|
<span className="openapi-schema-readonly">
|
||||||
|
{t(context.translation, 'read_only')}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
{schema?.writeOnly ? (
|
{schema?.writeOnly ? (
|
||||||
<span className="openapi-schema-writeonly">write-only</span>
|
<span className="openapi-schema-writeonly">
|
||||||
|
{t(context.translation, 'write_only')}
|
||||||
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
{required ? (
|
{required ? (
|
||||||
<span className="openapi-schema-required">required</span>
|
<span className="openapi-schema-required">
|
||||||
|
{t(context.translation, 'required')}
|
||||||
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="openapi-schema-optional">optional</span>
|
<span className="openapi-schema-optional">
|
||||||
|
{t(context.translation, 'optional')}
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
{schema?.deprecated ? <span className="openapi-deprecated">Deprecated</span> : null}
|
{schema?.deprecated ? (
|
||||||
|
<span className="openapi-deprecated">{t(context.translation, 'deprecated')}</span>
|
||||||
|
) : null}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAdditionalItems(schema: OpenAPIV3.SchemaObject): string {
|
function getAdditionalItems(schema: OpenAPIV3.SchemaObject, context: OpenAPIClientContext): string {
|
||||||
let additionalItems = '';
|
let additionalItems = '';
|
||||||
|
|
||||||
if (schema.minimum || schema.minLength || schema.minItems) {
|
if (schema.minimum || schema.minLength || schema.minItems) {
|
||||||
additionalItems += ` · min: ${schema.minimum || schema.minLength || schema.minItems}`;
|
additionalItems += ` · ${tString(context.translation, 'min').toLowerCase()}: ${schema.minimum || schema.minLength || schema.minItems}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.maximum || schema.maxLength || schema.maxItems) {
|
if (schema.maximum || schema.maxLength || schema.maxItems) {
|
||||||
additionalItems += ` · max: ${schema.maximum || schema.maxLength || schema.maxItems}`;
|
additionalItems += ` · ${tString(context.translation, 'max').toLowerCase()}: ${schema.maximum || schema.maxLength || schema.maxItems}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.nullable) {
|
if (schema.nullable) {
|
||||||
additionalItems = ' | nullable';
|
additionalItems = ` | ${tString(context.translation, 'nullable').toLowerCase()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return additionalItems;
|
return additionalItems;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import {
|
|||||||
OpenAPISchemaPropertiesFromServer,
|
OpenAPISchemaPropertiesFromServer,
|
||||||
type OpenAPISchemaPropertyEntry,
|
type OpenAPISchemaPropertyEntry,
|
||||||
} from './OpenAPISchema';
|
} from './OpenAPISchema';
|
||||||
|
import type { OpenAPIClientContext } from './context';
|
||||||
import { decycle } from './decycle';
|
import { decycle } from './decycle';
|
||||||
import type { OpenAPIClientContext } from './types';
|
|
||||||
|
|
||||||
export function OpenAPISchemaProperties(props: {
|
export function OpenAPISchemaProperties(props: {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { InteractiveSection } from './InteractiveSection';
|
import { InteractiveSection } from './InteractiveSection';
|
||||||
import { Markdown } from './Markdown';
|
import { Markdown } from './Markdown';
|
||||||
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
||||||
import type {
|
import type { OpenAPIClientContext } from './context';
|
||||||
OpenAPIClientContext,
|
import { t } from './translate';
|
||||||
OpenAPIOperationData,
|
import type { OpenAPIOperationData, OpenAPISecurityWithRequired } from './types';
|
||||||
OpenAPISecurityWithRequired,
|
|
||||||
} from './types';
|
|
||||||
import { createStateKey, resolveDescription } from './utils';
|
import { createStateKey, resolveDescription } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,7 +21,7 @@ export function OpenAPISecurities(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<InteractiveSection
|
<InteractiveSection
|
||||||
header="Authorizations"
|
header={t(context.translation, 'authorizations')}
|
||||||
stateKey={createStateKey('securities', context.blockKey)}
|
stateKey={createStateKey('securities', context.blockKey)}
|
||||||
toggeable
|
toggeable
|
||||||
defaultOpened={false}
|
defaultOpened={false}
|
||||||
@@ -38,7 +36,7 @@ export function OpenAPISecurities(props: {
|
|||||||
body: (
|
body: (
|
||||||
<div className="openapi-schema">
|
<div className="openapi-schema">
|
||||||
<div className="openapi-schema-presentation">
|
<div className="openapi-schema-presentation">
|
||||||
{getLabelForType(security)}
|
{getLabelForType(security, context)}
|
||||||
|
|
||||||
{description ? (
|
{description ? (
|
||||||
<Markdown
|
<Markdown
|
||||||
@@ -55,11 +53,12 @@ export function OpenAPISecurities(props: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLabelForType(security: OpenAPISecurityWithRequired) {
|
function getLabelForType(security: OpenAPISecurityWithRequired, context: OpenAPIClientContext) {
|
||||||
switch (security.type) {
|
switch (security.type) {
|
||||||
case 'apiKey':
|
case 'apiKey':
|
||||||
return (
|
return (
|
||||||
<OpenAPISchemaName
|
<OpenAPISchemaName
|
||||||
|
context={context}
|
||||||
propertyName={security.name ?? 'apiKey'}
|
propertyName={security.name ?? 'apiKey'}
|
||||||
type="string"
|
type="string"
|
||||||
required={security.required}
|
required={security.required}
|
||||||
@@ -69,6 +68,7 @@ function getLabelForType(security: OpenAPISecurityWithRequired) {
|
|||||||
if (security.scheme === 'basic') {
|
if (security.scheme === 'basic') {
|
||||||
return (
|
return (
|
||||||
<OpenAPISchemaName
|
<OpenAPISchemaName
|
||||||
|
context={context}
|
||||||
propertyName="Authorization"
|
propertyName="Authorization"
|
||||||
type="string"
|
type="string"
|
||||||
required={security.required}
|
required={security.required}
|
||||||
@@ -81,6 +81,7 @@ function getLabelForType(security: OpenAPISecurityWithRequired) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<OpenAPISchemaName
|
<OpenAPISchemaName
|
||||||
|
context={context}
|
||||||
propertyName="Authorization"
|
propertyName="Authorization"
|
||||||
type="string"
|
type="string"
|
||||||
required={security.required}
|
required={security.required}
|
||||||
@@ -96,11 +97,29 @@ function getLabelForType(security: OpenAPISecurityWithRequired) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <OpenAPISchemaName propertyName="HTTP" required={security.required} />;
|
return (
|
||||||
|
<OpenAPISchemaName
|
||||||
|
context={context}
|
||||||
|
propertyName="HTTP"
|
||||||
|
required={security.required}
|
||||||
|
/>
|
||||||
|
);
|
||||||
case 'oauth2':
|
case 'oauth2':
|
||||||
return <OpenAPISchemaName propertyName="OAuth2" required={security.required} />;
|
return (
|
||||||
|
<OpenAPISchemaName
|
||||||
|
context={context}
|
||||||
|
propertyName="OAuth2"
|
||||||
|
required={security.required}
|
||||||
|
/>
|
||||||
|
);
|
||||||
case 'openIdConnect':
|
case 'openIdConnect':
|
||||||
return <OpenAPISchemaName propertyName="OpenID Connect" required={security.required} />;
|
return (
|
||||||
|
<OpenAPISchemaName
|
||||||
|
context={context}
|
||||||
|
propertyName="OpenID Connect"
|
||||||
|
required={security.required}
|
||||||
|
/>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return security.type;
|
return security.type;
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import { OpenAPIResponses } from './OpenAPIResponses';
|
|||||||
import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
|
import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
|
||||||
import { OpenAPISecurities } from './OpenAPISecurities';
|
import { OpenAPISecurities } from './OpenAPISecurities';
|
||||||
import { StaticSection } from './StaticSection';
|
import { StaticSection } from './StaticSection';
|
||||||
import type { OpenAPIClientContext, OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
import type { OpenAPIClientContext } from './context';
|
||||||
|
import { tString } from './translate';
|
||||||
|
import type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
||||||
import { parameterToProperty } from './utils';
|
import { parameterToProperty } from './utils';
|
||||||
|
|
||||||
export function OpenAPISpec(props: {
|
export function OpenAPISpec(props: {
|
||||||
@@ -17,7 +19,7 @@ export function OpenAPISpec(props: {
|
|||||||
const { operation } = data;
|
const { operation } = data;
|
||||||
|
|
||||||
const parameters = operation.parameters ?? [];
|
const parameters = operation.parameters ?? [];
|
||||||
const parameterGroups = groupParameters(parameters);
|
const parameterGroups = groupParameters(parameters, context);
|
||||||
|
|
||||||
const securities = 'securities' in data ? data.securities : [];
|
const securities = 'securities' in data ? data.securities : [];
|
||||||
|
|
||||||
@@ -61,7 +63,10 @@ export function OpenAPISpec(props: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function groupParameters(parameters: OpenAPI.Parameters): Array<{
|
function groupParameters(
|
||||||
|
parameters: OpenAPI.Parameters,
|
||||||
|
context: OpenAPIClientContext
|
||||||
|
): Array<{
|
||||||
key: string;
|
key: string;
|
||||||
label: string;
|
label: string;
|
||||||
parameters: OpenAPI.Parameters;
|
parameters: OpenAPI.Parameters;
|
||||||
@@ -78,7 +83,7 @@ function groupParameters(parameters: OpenAPI.Parameters): Array<{
|
|||||||
.filter((parameter) => parameter.in)
|
.filter((parameter) => parameter.in)
|
||||||
.forEach((parameter) => {
|
.forEach((parameter) => {
|
||||||
const key = parameter.in;
|
const key = parameter.in;
|
||||||
const label = getParameterGroupName(parameter.in);
|
const label = getParameterGroupName(parameter.in, context);
|
||||||
const group = groups.find((group) => group.key === key);
|
const group = groups.find((group) => group.key === key);
|
||||||
if (group) {
|
if (group) {
|
||||||
group.parameters.push(parameter);
|
group.parameters.push(parameter);
|
||||||
@@ -96,14 +101,14 @@ function groupParameters(parameters: OpenAPI.Parameters): Array<{
|
|||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getParameterGroupName(paramIn: string): string {
|
function getParameterGroupName(paramIn: string, context: OpenAPIClientContext): string {
|
||||||
switch (paramIn) {
|
switch (paramIn) {
|
||||||
case 'path':
|
case 'path':
|
||||||
return 'Path parameters';
|
return tString(context.translation, 'path_parameters');
|
||||||
case 'query':
|
case 'query':
|
||||||
return 'Query parameters';
|
return tString(context.translation, 'query_parameters');
|
||||||
case 'header':
|
case 'header':
|
||||||
return 'Header parameters';
|
return tString(context.translation, 'header_parameters');
|
||||||
default:
|
default:
|
||||||
return paramIn;
|
return paramIn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import clsx from 'clsx';
|
|||||||
import { OpenAPIWebhookExample } from './OpenAPIWebhookExample';
|
import { OpenAPIWebhookExample } from './OpenAPIWebhookExample';
|
||||||
import { OpenAPIColumnSpec } from './common/OpenAPIColumnSpec';
|
import { OpenAPIColumnSpec } from './common/OpenAPIColumnSpec';
|
||||||
import { OpenAPISummary } from './common/OpenAPISummary';
|
import { OpenAPISummary } from './common/OpenAPISummary';
|
||||||
import type { OpenAPIContext, OpenAPIWebhookData } from './types';
|
import { type OpenAPIContextInput, resolveOpenAPIContext } from './context';
|
||||||
|
import type { OpenAPIWebhookData } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display an interactive OpenAPI webhook.
|
* Display an interactive OpenAPI webhook.
|
||||||
@@ -10,9 +11,11 @@ import type { OpenAPIContext, OpenAPIWebhookData } from './types';
|
|||||||
export function OpenAPIWebhook(props: {
|
export function OpenAPIWebhook(props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
data: OpenAPIWebhookData;
|
data: OpenAPIWebhookData;
|
||||||
context: OpenAPIContext;
|
context: OpenAPIContextInput;
|
||||||
}) {
|
}) {
|
||||||
const { className, data, context } = props;
|
const { className, data, context: contextInput } = props;
|
||||||
|
|
||||||
|
const context = resolveOpenAPIContext(contextInput);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('openapi-webhook', className)}>
|
<div className={clsx('openapi-webhook', className)}>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import { OpenAPIEmptyExample } from './OpenAPIExample';
|
import { OpenAPIEmptyExample } from './OpenAPIExample';
|
||||||
import { OpenAPIMediaTypeContent } from './OpenAPIMediaType';
|
import { OpenAPIMediaTypeContent } from './OpenAPIMediaType';
|
||||||
import type { OpenAPIContext } from './types';
|
import { type OpenAPIContext, getOpenAPIClientContext } from './context';
|
||||||
import type { OpenAPIWebhookData } from './types';
|
import type { OpenAPIWebhookData } from './types';
|
||||||
import { getExamples } from './util/example';
|
import { getExamples } from './util/example';
|
||||||
import { createStateKey } from './utils';
|
import { createStateKey } from './utils';
|
||||||
@@ -27,7 +27,7 @@ export function OpenAPIWebhookExample(props: {
|
|||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
label: key,
|
label: key,
|
||||||
body: <OpenAPIEmptyExample />,
|
body: <OpenAPIEmptyExample context={context} />,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ export function OpenAPIWebhookExample(props: {
|
|||||||
selectIcon={context.icons.chevronDown}
|
selectIcon={context.icons.chevronDown}
|
||||||
stateKey={createStateKey('request-body-media-type', context.blockKey)}
|
stateKey={createStateKey('request-body-media-type', context.blockKey)}
|
||||||
items={items}
|
items={items}
|
||||||
|
context={getOpenAPIClientContext(context)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import { createPortal } from 'react-dom';
|
|||||||
|
|
||||||
import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
||||||
import { useOpenAPIOperationContext } from './OpenAPIOperationContext';
|
import { useOpenAPIOperationContext } from './OpenAPIOperationContext';
|
||||||
|
import type { OpenAPIClientContext } from './context';
|
||||||
|
import { t } from './translate';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Button which launches the Scalar API Client
|
* Button which launches the Scalar API Client
|
||||||
@@ -14,8 +16,9 @@ export function ScalarApiButton(props: {
|
|||||||
method: OpenAPIV3_1.HttpMethods;
|
method: OpenAPIV3_1.HttpMethods;
|
||||||
path: string;
|
path: string;
|
||||||
specUrl: string;
|
specUrl: string;
|
||||||
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
const { method, path, specUrl } = props;
|
const { method, path, specUrl, context } = props;
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const controllerRef = useRef<ScalarModalControllerRef>(null);
|
const controllerRef = useRef<ScalarModalControllerRef>(null);
|
||||||
return (
|
return (
|
||||||
@@ -27,7 +30,7 @@ export function ScalarApiButton(props: {
|
|||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Test it
|
{t(context.translation, 'test_it')}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 12" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 12" fill="currentColor">
|
||||||
<path
|
<path
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { OpenAPISpec } from '../OpenAPISpec';
|
import { OpenAPISpec } from '../OpenAPISpec';
|
||||||
import { getOpenAPIClientContext } from '../context';
|
import { type OpenAPIContext, getOpenAPIClientContext } from '../context';
|
||||||
import type { OpenAPIContext, OpenAPIOperationData, OpenAPIWebhookData } from '../types';
|
import { t } from '../translate';
|
||||||
|
import type { OpenAPIOperationData, OpenAPIWebhookData } from '../types';
|
||||||
import { OpenAPIOperationDescription } from './OpenAPIOperationDescription';
|
import { OpenAPIOperationDescription } from './OpenAPIOperationDescription';
|
||||||
|
|
||||||
export function OpenAPIColumnSpec(props: {
|
export function OpenAPIColumnSpec(props: {
|
||||||
@@ -16,11 +17,11 @@ export function OpenAPIColumnSpec(props: {
|
|||||||
<div className="openapi-column-spec">
|
<div className="openapi-column-spec">
|
||||||
{operation['x-deprecated-sunset'] ? (
|
{operation['x-deprecated-sunset'] ? (
|
||||||
<div className="openapi-deprecated-sunset openapi-description openapi-markdown">
|
<div className="openapi-deprecated-sunset openapi-description openapi-markdown">
|
||||||
This operation is deprecated and will be sunset on{' '}
|
{t(context.translation, 'deprecated_and_sunset_on', [
|
||||||
<span className="openapi-deprecated-sunset-date">
|
<span key="date" className="openapi-deprecated-sunset-date">
|
||||||
{operation['x-deprecated-sunset']}
|
{operation['x-deprecated-sunset']}
|
||||||
</span>
|
</span>,
|
||||||
{'.'}
|
])}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<OpenAPIOperationDescription operation={operation} context={context} />
|
<OpenAPIOperationDescription operation={operation} context={context} />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import { Markdown } from '../Markdown';
|
import { Markdown } from '../Markdown';
|
||||||
import type { OpenAPIContext } from '../types';
|
import type { OpenAPIContext } from '../context';
|
||||||
import { resolveDescription } from '../utils';
|
import { resolveDescription } from '../utils';
|
||||||
|
|
||||||
export function OpenAPIOperationDescription(props: {
|
export function OpenAPIOperationDescription(props: {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { OpenAPIPath } from '../OpenAPIPath';
|
import { OpenAPIPath } from '../OpenAPIPath';
|
||||||
import type { OpenAPIContext, OpenAPIOperationData, OpenAPIWebhookData } from '../types';
|
import type { OpenAPIContext } from '../context';
|
||||||
|
import type { OpenAPIOperationData, OpenAPIWebhookData } from '../types';
|
||||||
import { OpenAPIStability } from './OpenAPIStability';
|
import { OpenAPIStability } from './OpenAPIStability';
|
||||||
|
|
||||||
export function OpenAPISummary(props: {
|
export function OpenAPISummary(props: {
|
||||||
@@ -38,7 +39,7 @@ export function OpenAPISummary(props: {
|
|||||||
title,
|
title,
|
||||||
})
|
})
|
||||||
: null}
|
: null}
|
||||||
{'path' in data ? <OpenAPIPath data={data} /> : null}
|
{'path' in data ? <OpenAPIPath data={data} context={context} /> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
|
import { type Translation, type TranslationLocale, translations } from './translations';
|
||||||
|
|
||||||
export interface OpenAPIClientContext {
|
export interface OpenAPIClientContext {
|
||||||
|
/**
|
||||||
|
* The translation language to use.
|
||||||
|
*/
|
||||||
|
translation: Translation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Icons used in the block.
|
* Icons used in the block.
|
||||||
*/
|
*/
|
||||||
@@ -23,9 +30,14 @@ export interface OpenAPIClientContext {
|
|||||||
* Optional id attached to the heading and used as an anchor.
|
* Optional id attached to the heading and used as an anchor.
|
||||||
*/
|
*/
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the context as a client context.
|
||||||
|
*/
|
||||||
|
$$isClientContext$$: true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OpenAPIContext extends OpenAPIClientContext {
|
export interface OpenAPIContext extends Omit<OpenAPIClientContext, '$$isClientContext$$'> {
|
||||||
/**
|
/**
|
||||||
* Render a code block.
|
* Render a code block.
|
||||||
*/
|
*/
|
||||||
@@ -51,14 +63,37 @@ export interface OpenAPIContext extends OpenAPIClientContext {
|
|||||||
specUrl: string;
|
specUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type OpenAPIUniversalContext = OpenAPIClientContext | OpenAPIContext;
|
||||||
|
|
||||||
|
export interface OpenAPIContextInput extends Omit<OpenAPIContext, 'translation'> {
|
||||||
|
/**
|
||||||
|
* The translation language to use.
|
||||||
|
* @default 'en'
|
||||||
|
*/
|
||||||
|
locale?: TranslationLocale | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve OpenAPI context from the input.
|
||||||
|
*/
|
||||||
|
export function resolveOpenAPIContext(context: OpenAPIContextInput): OpenAPIContext {
|
||||||
|
const { locale, ...rest } = context;
|
||||||
|
return {
|
||||||
|
...rest,
|
||||||
|
translation: translations[locale ?? 'en'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the client context from the OpenAPI context.
|
* Get the client context from the OpenAPI context.
|
||||||
*/
|
*/
|
||||||
export function getOpenAPIClientContext(context: OpenAPIContext): OpenAPIClientContext {
|
export function getOpenAPIClientContext(context: OpenAPIUniversalContext): OpenAPIClientContext {
|
||||||
return {
|
return {
|
||||||
|
translation: context.translation,
|
||||||
icons: context.icons,
|
icons: context.icons,
|
||||||
defaultInteractiveOpened: context.defaultInteractiveOpened,
|
defaultInteractiveOpened: context.defaultInteractiveOpened,
|
||||||
blockKey: context.blockKey,
|
blockKey: context.blockKey,
|
||||||
id: context.id,
|
id: context.id,
|
||||||
|
$$isClientContext$$: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ export * from './OpenAPIWebhook';
|
|||||||
export * from './OpenAPIOperationContext';
|
export * from './OpenAPIOperationContext';
|
||||||
export * from './resolveOpenAPIOperation';
|
export * from './resolveOpenAPIOperation';
|
||||||
export * from './resolveOpenAPIWebhook';
|
export * from './resolveOpenAPIWebhook';
|
||||||
export type { OpenAPIOperationData, OpenAPIContext, OpenAPIWebhookData } from './types';
|
export type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
||||||
|
export type { OpenAPIContextInput } from './context';
|
||||||
|
export { checkIsValidLocale } from './translations';
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ import { OpenAPIDisclosure } from '../OpenAPIDisclosure';
|
|||||||
import { OpenAPIExample } from '../OpenAPIExample';
|
import { OpenAPIExample } from '../OpenAPIExample';
|
||||||
import { OpenAPIRootSchema } from '../OpenAPISchemaServer';
|
import { OpenAPIRootSchema } from '../OpenAPISchemaServer';
|
||||||
import { Section, SectionBody, StaticSection } from '../StaticSection';
|
import { Section, SectionBody, StaticSection } from '../StaticSection';
|
||||||
import { getOpenAPIClientContext } from '../context';
|
import {
|
||||||
import type { OpenAPIContext } from '../types';
|
type OpenAPIContextInput,
|
||||||
|
getOpenAPIClientContext,
|
||||||
|
resolveOpenAPIContext,
|
||||||
|
} from '../context';
|
||||||
|
import { t } from '../translate';
|
||||||
import { getExampleFromSchema } from '../util/example';
|
import { getExampleFromSchema } from '../util/example';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,13 +18,13 @@ import { getExampleFromSchema } from '../util/example';
|
|||||||
export function OpenAPISchemas(props: {
|
export function OpenAPISchemas(props: {
|
||||||
className?: string;
|
className?: string;
|
||||||
schemas: OpenAPISchema[];
|
schemas: OpenAPISchema[];
|
||||||
context: OpenAPIContext;
|
context: OpenAPIContextInput;
|
||||||
/**
|
/**
|
||||||
* Whether to show the schema directly if there is only one.
|
* Whether to show the schema directly if there is only one.
|
||||||
*/
|
*/
|
||||||
grouped?: boolean;
|
grouped?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { schemas, context, grouped, className } = props;
|
const { schemas, context: contextInput, grouped, className } = props;
|
||||||
|
|
||||||
const firstSchema = schemas[0];
|
const firstSchema = schemas[0];
|
||||||
|
|
||||||
@@ -28,6 +32,7 @@ export function OpenAPISchemas(props: {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const context = resolveOpenAPIContext(contextInput);
|
||||||
const clientContext = getOpenAPIClientContext(context);
|
const clientContext = getOpenAPIClientContext(context);
|
||||||
|
|
||||||
// If there is only one model and we are not grouping, we show it directly.
|
// If there is only one model and we are not grouping, we show it directly.
|
||||||
@@ -38,11 +43,16 @@ export function OpenAPISchemas(props: {
|
|||||||
<div className="openapi-summary" id={context.id}>
|
<div className="openapi-summary" id={context.id}>
|
||||||
{context.renderHeading({
|
{context.renderHeading({
|
||||||
title,
|
title,
|
||||||
|
deprecated: Boolean(firstSchema.schema.deprecated),
|
||||||
|
stability: firstSchema.schema['x-stability'],
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="openapi-columns">
|
<div className="openapi-columns">
|
||||||
<div className="openapi-column-spec">
|
<div className="openapi-column-spec">
|
||||||
<StaticSection className="openapi-parameters" header="Attributes">
|
<StaticSection
|
||||||
|
className="openapi-parameters"
|
||||||
|
header={t(context.translation, 'attributes')}
|
||||||
|
>
|
||||||
<OpenAPIRootSchema
|
<OpenAPIRootSchema
|
||||||
schema={firstSchema.schema}
|
schema={firstSchema.schema}
|
||||||
context={clientContext}
|
context={clientContext}
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import type { Translation, TranslationKey } from './translations';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate a string.
|
||||||
|
*/
|
||||||
|
export function t(
|
||||||
|
translation: Translation,
|
||||||
|
id: TranslationKey,
|
||||||
|
...args: React.ReactNode[]
|
||||||
|
): React.ReactNode {
|
||||||
|
const string = translation[id];
|
||||||
|
if (!string) {
|
||||||
|
throw new Error(`Translation not found for "${id}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we are going to replace the arguments
|
||||||
|
// but we want to return a string as long as it's possible
|
||||||
|
// (eg. if there isn't any argument that is a ReactNode)
|
||||||
|
const parts: React.ReactNode[] = [];
|
||||||
|
let currentStringToReplace: string = string;
|
||||||
|
|
||||||
|
args.forEach((arg, i) => {
|
||||||
|
if (typeof arg === 'string') {
|
||||||
|
currentStringToReplace = currentStringToReplace.replace(`\${${i + 1}}`, arg);
|
||||||
|
} else {
|
||||||
|
const [partToPush, partToReplace] = currentStringToReplace.split(`\${${i + 1}}`);
|
||||||
|
if (partToPush === undefined || partToReplace === undefined) {
|
||||||
|
throw new Error(`Invalid translation "${id}"`);
|
||||||
|
}
|
||||||
|
parts.push(<React.Fragment key={`string-${i}`}>{partToPush}</React.Fragment>);
|
||||||
|
parts.push(<React.Fragment key={`arg-${i}`}>{arg}</React.Fragment>);
|
||||||
|
currentStringToReplace = partToReplace;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!parts.length) {
|
||||||
|
return currentStringToReplace;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{parts}
|
||||||
|
{currentStringToReplace}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version of `t` that returns a string.
|
||||||
|
*/
|
||||||
|
export function tString(
|
||||||
|
translation: Translation,
|
||||||
|
id: TranslationKey,
|
||||||
|
...args: React.ReactNode[]
|
||||||
|
): string {
|
||||||
|
const result = t(translation, id, ...args);
|
||||||
|
return reactToString(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reactToString(el: React.ReactNode): string {
|
||||||
|
if (typeof el === 'string' || typeof el === 'number' || typeof el === 'boolean') {
|
||||||
|
return `${el}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el === null || el === undefined) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(el)) {
|
||||||
|
return el.map(reactToString).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof el === 'object' && 'props' in el) {
|
||||||
|
return el.props.children.map(reactToString).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unsupported type ${typeof el}`);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const de = {
|
||||||
|
required: 'Erforderlich',
|
||||||
|
deprecated: 'Veraltet',
|
||||||
|
deprecated_and_sunset_on: 'Diese Operation ist veraltet und wird am ${1} eingestellt.',
|
||||||
|
stability_experimental: 'Experimentell',
|
||||||
|
stability_alpha: 'Alpha',
|
||||||
|
stability_beta: 'Beta',
|
||||||
|
copy_to_clipboard: 'In die Zwischenablage kopieren',
|
||||||
|
copied: 'Kopiert',
|
||||||
|
no_content: 'Kein Inhalt',
|
||||||
|
unresolved_reference: 'Nicht aufgelöste Referenz',
|
||||||
|
circular_reference: 'Zirkuläre Referenz',
|
||||||
|
read_only: 'Nur lesen',
|
||||||
|
write_only: 'Nur schreiben',
|
||||||
|
optional: 'Optional',
|
||||||
|
min: 'Min',
|
||||||
|
max: 'Max',
|
||||||
|
nullable: 'Nullfähig',
|
||||||
|
body: 'Rumpf',
|
||||||
|
payload: 'Nutzlast',
|
||||||
|
headers: 'Kopfzeilen',
|
||||||
|
authorizations: 'Autorisierungen',
|
||||||
|
responses: 'Antworten',
|
||||||
|
path_parameters: 'Pfadparameter',
|
||||||
|
query_parameters: 'Abfrageparameter',
|
||||||
|
header_parameters: 'Header-Parameter',
|
||||||
|
attributes: 'Attribute',
|
||||||
|
test_it: 'Teste es',
|
||||||
|
information: 'Information',
|
||||||
|
success: 'Erfolg',
|
||||||
|
redirect: 'Umleitung',
|
||||||
|
error: 'Fehler',
|
||||||
|
show: 'Anzeigen',
|
||||||
|
hide: 'Verstecken',
|
||||||
|
available_items: 'Verfügbare Elemente',
|
||||||
|
child_attributes: 'Unterattribute',
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const en = {
|
||||||
|
required: 'Required',
|
||||||
|
deprecated: 'Deprecated',
|
||||||
|
deprecated_and_sunset_on: 'This operation is deprecated and will be sunset on ${1}.',
|
||||||
|
stability_experimental: 'Experimental',
|
||||||
|
stability_alpha: 'Alpha',
|
||||||
|
stability_beta: 'Beta',
|
||||||
|
copy_to_clipboard: 'Copy to clipboard',
|
||||||
|
copied: 'Copied',
|
||||||
|
no_content: 'No content',
|
||||||
|
unresolved_reference: 'Unresolved reference',
|
||||||
|
circular_reference: 'Circular reference',
|
||||||
|
read_only: 'Read-only',
|
||||||
|
write_only: 'Write-only',
|
||||||
|
optional: 'Optional',
|
||||||
|
min: 'Min',
|
||||||
|
max: 'Max',
|
||||||
|
nullable: 'Nullable',
|
||||||
|
body: 'Body',
|
||||||
|
payload: 'Payload',
|
||||||
|
headers: 'Headers',
|
||||||
|
authorizations: 'Authorizations',
|
||||||
|
responses: 'Responses',
|
||||||
|
path_parameters: 'Path parameters',
|
||||||
|
query_parameters: 'Query parameters',
|
||||||
|
header_parameters: 'Header parameters',
|
||||||
|
attributes: 'Attributes',
|
||||||
|
test_it: 'Test it',
|
||||||
|
information: 'Information',
|
||||||
|
success: 'Success',
|
||||||
|
redirect: 'Redirect',
|
||||||
|
error: 'Error',
|
||||||
|
show: 'Show',
|
||||||
|
hide: 'Hide',
|
||||||
|
available_items: 'Available items',
|
||||||
|
child_attributes: 'Child attributes',
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const es = {
|
||||||
|
required: 'Requerido',
|
||||||
|
deprecated: 'Obsoleto',
|
||||||
|
deprecated_and_sunset_on: 'Esta operación está obsoleta y se retirará el ${1}.',
|
||||||
|
stability_experimental: 'Experimental',
|
||||||
|
stability_alpha: 'Alfa',
|
||||||
|
stability_beta: 'Beta',
|
||||||
|
copy_to_clipboard: 'Copiar al portapapeles',
|
||||||
|
copied: 'Copiado',
|
||||||
|
no_content: 'Sin contenido',
|
||||||
|
unresolved_reference: 'Referencia no resuelta',
|
||||||
|
circular_reference: 'Referencia circular',
|
||||||
|
read_only: 'Solo lectura',
|
||||||
|
write_only: 'Solo escritura',
|
||||||
|
optional: 'Opcional',
|
||||||
|
min: 'Mín',
|
||||||
|
max: 'Máx',
|
||||||
|
nullable: 'Nulo',
|
||||||
|
body: 'Cuerpo',
|
||||||
|
payload: 'Caga útil',
|
||||||
|
headers: 'Encabezados',
|
||||||
|
authorizations: 'Autorizaciones',
|
||||||
|
responses: 'Respuestas',
|
||||||
|
path_parameters: 'Parámetros de ruta',
|
||||||
|
query_parameters: 'Parámetros de consulta',
|
||||||
|
header_parameters: 'Parámetros de encabezado',
|
||||||
|
attributes: 'Atributos',
|
||||||
|
test_it: 'Pruébalo',
|
||||||
|
information: 'Información',
|
||||||
|
success: 'Éxito',
|
||||||
|
redirect: 'Redirección',
|
||||||
|
error: 'Error',
|
||||||
|
show: 'Mostrar',
|
||||||
|
hide: 'Ocultar',
|
||||||
|
available_items: 'Elementos disponibles',
|
||||||
|
child_attributes: 'Atributos secundarios',
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const fr = {
|
||||||
|
required: 'Requis',
|
||||||
|
deprecated: 'Obsolète',
|
||||||
|
deprecated_and_sunset_on: 'Cette opération est obsolète et sera supprimée le ${1}.',
|
||||||
|
stability_experimental: 'Expérimental',
|
||||||
|
stability_alpha: 'Alpha',
|
||||||
|
stability_beta: 'Bêta',
|
||||||
|
copy_to_clipboard: 'Copier dans le presse-papiers',
|
||||||
|
copied: 'Copié',
|
||||||
|
no_content: 'Aucun contenu',
|
||||||
|
unresolved_reference: 'Référence non résolue',
|
||||||
|
circular_reference: 'Référence circulaire',
|
||||||
|
read_only: 'Lecture seule',
|
||||||
|
write_only: 'Écriture seule',
|
||||||
|
optional: 'Optionnel',
|
||||||
|
min: 'Min',
|
||||||
|
max: 'Max',
|
||||||
|
nullable: 'Nullable',
|
||||||
|
body: 'Corps',
|
||||||
|
payload: 'Charge utile',
|
||||||
|
headers: 'En-têtes',
|
||||||
|
authorizations: 'Autorisations',
|
||||||
|
responses: 'Réponses',
|
||||||
|
path_parameters: 'Paramètres de chemin',
|
||||||
|
query_parameters: 'Paramètres de requête',
|
||||||
|
header_parameters: 'Paramètres d’en-tête',
|
||||||
|
attributes: 'Attributs',
|
||||||
|
test_it: 'Tester',
|
||||||
|
information: 'Information',
|
||||||
|
success: 'Succès',
|
||||||
|
redirect: 'Redirection',
|
||||||
|
error: 'Erreur',
|
||||||
|
show: 'Afficher',
|
||||||
|
hide: 'Masquer',
|
||||||
|
available_items: 'Éléments disponibles',
|
||||||
|
child_attributes: 'Attributs enfants',
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { de } from './de';
|
||||||
|
import { en } from './en';
|
||||||
|
import { es } from './es';
|
||||||
|
import { fr } from './fr';
|
||||||
|
import { ja } from './ja';
|
||||||
|
import { nl } from './nl';
|
||||||
|
import { no } from './no';
|
||||||
|
import { pt_br } from './pt-br';
|
||||||
|
import type { Translation } from './types';
|
||||||
|
import { zh } from './zh';
|
||||||
|
|
||||||
|
export * from './types';
|
||||||
|
|
||||||
|
export const translations = {
|
||||||
|
en,
|
||||||
|
de,
|
||||||
|
es,
|
||||||
|
fr,
|
||||||
|
ja,
|
||||||
|
nl,
|
||||||
|
no,
|
||||||
|
'pt-br': pt_br,
|
||||||
|
zh,
|
||||||
|
} satisfies Record<string, Translation>;
|
||||||
|
|
||||||
|
export type TranslationLocale = keyof typeof translations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the locale is valid.
|
||||||
|
*/
|
||||||
|
export function checkIsValidLocale(locale: string): locale is TranslationLocale {
|
||||||
|
return Object.prototype.hasOwnProperty.call(translations, locale);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const ja = {
|
||||||
|
required: '必須',
|
||||||
|
deprecated: '非推奨',
|
||||||
|
deprecated_and_sunset_on: 'この操作は非推奨であり、${1}に廃止されます。',
|
||||||
|
stability_experimental: '実験的',
|
||||||
|
stability_alpha: 'アルファ',
|
||||||
|
stability_beta: 'ベータ',
|
||||||
|
copy_to_clipboard: 'クリップボードにコピー',
|
||||||
|
copied: 'コピー済み',
|
||||||
|
no_content: 'コンテンツなし',
|
||||||
|
unresolved_reference: '未解決の参照',
|
||||||
|
circular_reference: '循環参照',
|
||||||
|
read_only: '読み取り専用',
|
||||||
|
write_only: '書き込み専用',
|
||||||
|
optional: 'オプション',
|
||||||
|
min: '最小',
|
||||||
|
max: '最大',
|
||||||
|
nullable: 'ヌル許容',
|
||||||
|
body: '本文',
|
||||||
|
payload: 'ペイロード',
|
||||||
|
headers: 'ヘッダー',
|
||||||
|
authorizations: '認可',
|
||||||
|
responses: 'レスポンス',
|
||||||
|
path_parameters: 'パスパラメータ',
|
||||||
|
query_parameters: 'クエリパラメータ',
|
||||||
|
header_parameters: 'ヘッダーパラメータ',
|
||||||
|
attributes: '属性',
|
||||||
|
test_it: 'テストする',
|
||||||
|
information: '情報',
|
||||||
|
success: '成功',
|
||||||
|
redirect: 'リダイレクト',
|
||||||
|
error: 'エラー',
|
||||||
|
show: '表示',
|
||||||
|
hide: '非表示',
|
||||||
|
available_items: '利用可能なアイテム',
|
||||||
|
child_attributes: '子属性',
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const nl = {
|
||||||
|
required: 'Vereist',
|
||||||
|
deprecated: 'Verouderd',
|
||||||
|
deprecated_and_sunset_on: 'Deze bewerking is verouderd en wordt op ${1} beëindigd.',
|
||||||
|
stability_experimental: 'Experimenteel',
|
||||||
|
stability_alpha: 'Alfa',
|
||||||
|
stability_beta: 'Bèta',
|
||||||
|
copy_to_clipboard: 'Kopiëren naar klembord',
|
||||||
|
copied: 'Gekopieerd',
|
||||||
|
no_content: 'Geen inhoud',
|
||||||
|
unresolved_reference: 'Onopgeloste verwijzing',
|
||||||
|
circular_reference: 'Circulaire verwijzing',
|
||||||
|
read_only: 'Alleen lezen',
|
||||||
|
write_only: 'Alleen schrijven',
|
||||||
|
optional: 'Optioneel',
|
||||||
|
min: 'Min',
|
||||||
|
max: 'Max',
|
||||||
|
nullable: 'Null toegestaan',
|
||||||
|
body: 'Body',
|
||||||
|
payload: 'Payload',
|
||||||
|
headers: 'Headers',
|
||||||
|
authorizations: 'Autorisaties',
|
||||||
|
responses: 'Reacties',
|
||||||
|
path_parameters: 'Padparameters',
|
||||||
|
query_parameters: 'Queryparameters',
|
||||||
|
header_parameters: 'Headerparameters',
|
||||||
|
attributes: 'Attributen',
|
||||||
|
test_it: 'Test het',
|
||||||
|
information: 'Informatie',
|
||||||
|
success: 'Succes',
|
||||||
|
redirect: 'Omleiding',
|
||||||
|
error: 'Fout',
|
||||||
|
show: 'Toon',
|
||||||
|
hide: 'Verbergen',
|
||||||
|
available_items: 'Beschikbare items',
|
||||||
|
child_attributes: 'Kindattributen',
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const no = {
|
||||||
|
required: 'Påkrevd',
|
||||||
|
deprecated: 'Foreldet',
|
||||||
|
deprecated_and_sunset_on: 'Denne operasjonen er foreldet og vil bli avviklet den ${1}.',
|
||||||
|
stability_experimental: 'Eksperimentell',
|
||||||
|
stability_alpha: 'Alfa',
|
||||||
|
stability_beta: 'Beta',
|
||||||
|
copy_to_clipboard: 'Kopier til utklippstavle',
|
||||||
|
copied: 'Kopiert',
|
||||||
|
no_content: 'Ingen innhold',
|
||||||
|
unresolved_reference: 'Uavklart referanse',
|
||||||
|
circular_reference: 'Sirkulær referanse',
|
||||||
|
read_only: 'Skrivebeskyttet',
|
||||||
|
write_only: 'Kun skriving',
|
||||||
|
optional: 'Valgfri',
|
||||||
|
min: 'Min',
|
||||||
|
max: 'Maks',
|
||||||
|
nullable: 'Kan være null',
|
||||||
|
body: 'Brødtekst',
|
||||||
|
payload: 'Nyttelast',
|
||||||
|
headers: 'Overskrifter',
|
||||||
|
authorizations: 'Autorisasjoner',
|
||||||
|
responses: 'Responser',
|
||||||
|
path_parameters: 'Sti-parametere',
|
||||||
|
query_parameters: 'Forespørselsparametere',
|
||||||
|
header_parameters: 'Header-parametere',
|
||||||
|
attributes: 'Attributter',
|
||||||
|
test_it: 'Test det',
|
||||||
|
information: 'Informasjon',
|
||||||
|
success: 'Suksess',
|
||||||
|
redirect: 'Viderekobling',
|
||||||
|
error: 'Feil',
|
||||||
|
show: 'Vis',
|
||||||
|
hide: 'Skjul',
|
||||||
|
available_items: 'Tilgjengelige elementer',
|
||||||
|
child_attributes: 'Barneattributter',
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const pt_br = {
|
||||||
|
required: 'Obrigatório',
|
||||||
|
deprecated: 'Obsoleto',
|
||||||
|
deprecated_and_sunset_on: 'Esta operação está obsoleta e será descontinuada em ${1}.',
|
||||||
|
stability_experimental: 'Experimental',
|
||||||
|
stability_alpha: 'Alfa',
|
||||||
|
stability_beta: 'Beta',
|
||||||
|
copy_to_clipboard: 'Copiar para a área de transferência',
|
||||||
|
copied: 'Copiado',
|
||||||
|
no_content: 'Sem conteúdo',
|
||||||
|
unresolved_reference: 'Referência não resolvida',
|
||||||
|
circular_reference: 'Referência circular',
|
||||||
|
read_only: 'Somente leitura',
|
||||||
|
write_only: 'Somente escrita',
|
||||||
|
optional: 'Opcional',
|
||||||
|
min: 'Mín',
|
||||||
|
max: 'Máx',
|
||||||
|
nullable: 'Nulo',
|
||||||
|
body: 'Corpo',
|
||||||
|
payload: 'Carga útil',
|
||||||
|
headers: 'Cabeçalhos',
|
||||||
|
authorizations: 'Autorizações',
|
||||||
|
responses: 'Respostas',
|
||||||
|
path_parameters: 'Parâmetros de rota',
|
||||||
|
query_parameters: 'Parâmetros de consulta',
|
||||||
|
header_parameters: 'Parâmetros de cabeçalho',
|
||||||
|
attributes: 'Atributos',
|
||||||
|
test_it: 'Testar',
|
||||||
|
information: 'Informação',
|
||||||
|
success: 'Sucesso',
|
||||||
|
redirect: 'Redirecionamento',
|
||||||
|
error: 'Erro',
|
||||||
|
show: 'Mostrar',
|
||||||
|
hide: 'Ocultar',
|
||||||
|
available_items: 'Itens disponíveis',
|
||||||
|
child_attributes: 'Atributos filhos',
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import type { en } from './en';
|
||||||
|
|
||||||
|
export type TranslationKey = keyof typeof en;
|
||||||
|
|
||||||
|
export type Translation = {
|
||||||
|
[key in TranslationKey]: string;
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
export const zh = {
|
||||||
|
required: '必填',
|
||||||
|
deprecated: '已弃用',
|
||||||
|
deprecated_and_sunset_on: '此操作已弃用,将于 ${1} 停止使用。',
|
||||||
|
stability_experimental: '实验性',
|
||||||
|
stability_alpha: 'Alpha',
|
||||||
|
stability_beta: 'Beta',
|
||||||
|
copy_to_clipboard: '复制到剪贴板',
|
||||||
|
copied: '已复制',
|
||||||
|
no_content: '无内容',
|
||||||
|
unresolved_reference: '未解析的引用',
|
||||||
|
circular_reference: '循环引用',
|
||||||
|
read_only: '只读',
|
||||||
|
write_only: '只写',
|
||||||
|
optional: '可选',
|
||||||
|
min: '最小值',
|
||||||
|
max: '最大值',
|
||||||
|
nullable: '可为 null',
|
||||||
|
body: '请求体',
|
||||||
|
payload: '有效载荷',
|
||||||
|
headers: '头部信息',
|
||||||
|
authorizations: '授权',
|
||||||
|
responses: '响应',
|
||||||
|
path_parameters: '路径参数',
|
||||||
|
query_parameters: '查询参数',
|
||||||
|
header_parameters: '头参数',
|
||||||
|
attributes: '属性',
|
||||||
|
test_it: '测试一下',
|
||||||
|
information: '信息',
|
||||||
|
success: '成功',
|
||||||
|
redirect: '重定向',
|
||||||
|
error: '错误',
|
||||||
|
show: '显示',
|
||||||
|
hide: '隐藏',
|
||||||
|
available_items: '可用项',
|
||||||
|
child_attributes: '子属性',
|
||||||
|
};
|
||||||
@@ -4,59 +4,6 @@ import type {
|
|||||||
OpenAPIV3,
|
OpenAPIV3,
|
||||||
} from '@gitbook/openapi-parser';
|
} from '@gitbook/openapi-parser';
|
||||||
|
|
||||||
export interface OpenAPIClientContext {
|
|
||||||
/**
|
|
||||||
* Icons used in the block.
|
|
||||||
*/
|
|
||||||
icons: {
|
|
||||||
chevronDown: React.ReactNode;
|
|
||||||
chevronRight: React.ReactNode;
|
|
||||||
plus: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Force all sections to be opened by default.
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
defaultInteractiveOpened?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The key of the block
|
|
||||||
*/
|
|
||||||
blockKey?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optional id attached to the heading and used as an anchor.
|
|
||||||
*/
|
|
||||||
id?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OpenAPIContext extends OpenAPIClientContext {
|
|
||||||
/**
|
|
||||||
* Render a code block.
|
|
||||||
*/
|
|
||||||
renderCodeBlock: (props: { code: string; syntax: string }) => React.ReactNode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the heading of the operation.
|
|
||||||
*/
|
|
||||||
renderHeading: (props: {
|
|
||||||
deprecated?: boolean;
|
|
||||||
title: string;
|
|
||||||
stability?: string;
|
|
||||||
}) => React.ReactNode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the document of the operation.
|
|
||||||
*/
|
|
||||||
renderDocument: (props: { document: object }) => React.ReactNode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specification URL.
|
|
||||||
*/
|
|
||||||
specUrl: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject & { required?: boolean };
|
export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject & { required?: boolean };
|
||||||
|
|
||||||
export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
|
export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import { OpenAPIExample } from '../OpenAPIExample';
|
import { OpenAPIExample } from '../OpenAPIExample';
|
||||||
|
import type { OpenAPIContext } from '../context';
|
||||||
import { generateSchemaExample } from '../generateSchemaExample';
|
import { generateSchemaExample } from '../generateSchemaExample';
|
||||||
import type { OpenAPIContext } from '../types';
|
import { tString } from '../translate';
|
||||||
import { checkIsReference } from '../utils';
|
import { checkIsReference } from '../utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an example from a reference object.
|
* Generate an example from a reference object.
|
||||||
*/
|
*/
|
||||||
export function getExampleFromReference(ref: OpenAPIV3.ReferenceObject): OpenAPIV3.ExampleObject {
|
export function getExampleFromReference(
|
||||||
return { summary: 'Unresolved reference', value: { $ref: ref.$ref } };
|
ref: OpenAPIV3.ReferenceObject,
|
||||||
|
context: OpenAPIContext
|
||||||
|
): OpenAPIV3.ExampleObject {
|
||||||
|
return {
|
||||||
|
summary: tString(context.translation, 'unresolved_reference'),
|
||||||
|
value: { $ref: ref.$ref },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,13 +24,16 @@ export function getExampleFromReference(ref: OpenAPIV3.ReferenceObject): OpenAPI
|
|||||||
export function getExamplesFromMediaTypeObject(args: {
|
export function getExamplesFromMediaTypeObject(args: {
|
||||||
mediaType: string;
|
mediaType: string;
|
||||||
mediaTypeObject: OpenAPIV3.MediaTypeObject;
|
mediaTypeObject: OpenAPIV3.MediaTypeObject;
|
||||||
|
context: OpenAPIContext;
|
||||||
}): { key: string; example: OpenAPIV3.ExampleObject }[] {
|
}): { key: string; example: OpenAPIV3.ExampleObject }[] {
|
||||||
const { mediaTypeObject, mediaType } = args;
|
const { mediaTypeObject, mediaType, context } = args;
|
||||||
if (mediaTypeObject.examples) {
|
if (mediaTypeObject.examples) {
|
||||||
return Object.entries(mediaTypeObject.examples).map(([key, example]) => {
|
return Object.entries(mediaTypeObject.examples).map(([key, example]) => {
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
example: checkIsReference(example) ? getExampleFromReference(example) : example,
|
example: checkIsReference(example)
|
||||||
|
? getExampleFromReference(example, context)
|
||||||
|
: example,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -88,8 +98,8 @@ export function getExamples(props: {
|
|||||||
mediaType: string;
|
mediaType: string;
|
||||||
context: OpenAPIContext;
|
context: OpenAPIContext;
|
||||||
}) {
|
}) {
|
||||||
const { mediaTypeObject, mediaType } = props;
|
const { mediaTypeObject, mediaType, context } = props;
|
||||||
const examples = getExamplesFromMediaTypeObject({ mediaTypeObject, mediaType });
|
const examples = getExamplesFromMediaTypeObject({ mediaTypeObject, mediaType, context });
|
||||||
const syntax = getSyntaxFromMediaType(mediaType);
|
const syntax = getSyntaxFromMediaType(mediaType);
|
||||||
|
|
||||||
return examples.map((example) => {
|
return examples.map((example) => {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { AnyObject, OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
import type { AnyObject, OpenAPIV3, OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
||||||
|
import type { OpenAPIUniversalContext } from './context';
|
||||||
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
import { stringifyOpenAPI } from './stringifyOpenAPI';
|
||||||
|
import { tString } from './translate';
|
||||||
|
|
||||||
export function checkIsReference(input: unknown): input is OpenAPIV3.ReferenceObject {
|
export function checkIsReference(input: unknown): input is OpenAPIV3.ReferenceObject {
|
||||||
return typeof input === 'object' && !!input && '$ref' in input;
|
return typeof input === 'object' && !!input && '$ref' in input;
|
||||||
@@ -182,18 +184,21 @@ export function getStatusCodeClassName(statusCode: number | string): string {
|
|||||||
* 3xx: Redirect
|
* 3xx: Redirect
|
||||||
* 4xx, 5xx: Error
|
* 4xx, 5xx: Error
|
||||||
*/
|
*/
|
||||||
export function getStatusCodeDefaultLabel(statusCode: number | string): string {
|
export function getStatusCodeDefaultLabel(
|
||||||
|
statusCode: number | string,
|
||||||
|
context: OpenAPIUniversalContext
|
||||||
|
): string {
|
||||||
const category = getStatusCodeCategory(statusCode);
|
const category = getStatusCodeCategory(statusCode);
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case 1:
|
case 1:
|
||||||
return 'Information';
|
return tString(context.translation, 'information');
|
||||||
case 2:
|
case 2:
|
||||||
return 'Success';
|
return tString(context.translation, 'success');
|
||||||
case 3:
|
case 3:
|
||||||
return 'Redirect';
|
return tString(context.translation, 'redirect');
|
||||||
case 4:
|
case 4:
|
||||||
case 5:
|
case 5:
|
||||||
return 'Error';
|
return tString(context.translation, 'error');
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user