docs: improvements and fixes to components in API reference (#9410)
- Change layout of parameters for clearer display - Fix schema code blocks being longer than container - switch between showing required to showing optional indicator - Fixed code tabs not having copy / report buttons Closes DOCS-936 Preview: https://api-reference-v2-git-docs-api-ref-comp-improv-medusajs.vercel.app/v2/api/store
This commit is contained in:
@@ -67,6 +67,14 @@ const TagsOperationDescriptionSection = ({
|
||||
workflow={operation["x-workflow"]}
|
||||
/>
|
||||
)}
|
||||
{operation.externalDocs && (
|
||||
<>
|
||||
Related guide:{" "}
|
||||
<Link href={operation.externalDocs.url} target="_blank">
|
||||
{operation.externalDocs.description || "Read More"}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
<Feedback
|
||||
event="survey_api-ref"
|
||||
extraData={{
|
||||
@@ -79,14 +87,6 @@ const TagsOperationDescriptionSection = ({
|
||||
vertical={true}
|
||||
question="Did this API Route run successfully?"
|
||||
/>
|
||||
{operation.externalDocs && (
|
||||
<>
|
||||
Related guide:{" "}
|
||||
<Link href={operation.externalDocs.url} target="_blank">
|
||||
{operation.externalDocs.description || "Read More"}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
{operation.security && (
|
||||
<TagsOperationDescriptionSectionSecurity
|
||||
security={operation.security}
|
||||
|
||||
@@ -16,100 +16,37 @@ type TagOperationParametersDescriptionProps = {
|
||||
const TagOperationParametersDescription = ({
|
||||
schema,
|
||||
}: TagOperationParametersDescriptionProps) => {
|
||||
let typeDescription: React.ReactNode = <></>
|
||||
switch (true) {
|
||||
case schema.type === "object":
|
||||
typeDescription = (
|
||||
<>
|
||||
{schema.type} {schema.title ? `(${schema.title})` : ""}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
</>
|
||||
)
|
||||
break
|
||||
case schema.type === "array":
|
||||
typeDescription = (
|
||||
<>
|
||||
{schema.type === "array" && formatArrayDescription(schema.items)}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
</>
|
||||
)
|
||||
break
|
||||
case schema.anyOf !== undefined:
|
||||
case schema.allOf !== undefined:
|
||||
typeDescription = (
|
||||
<>
|
||||
{formatUnionDescription(schema.allOf)}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
</>
|
||||
)
|
||||
break
|
||||
case schema.oneOf !== undefined:
|
||||
typeDescription = (
|
||||
<>
|
||||
{schema.oneOf?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
{index !== 0 && <> or </>}
|
||||
{item.type !== "array" && <>{item.title || item.type}</>}
|
||||
{item.type === "array" && (
|
||||
<>array{item.items.type ? ` of ${item.items.type}s` : ""}</>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
</>
|
||||
)
|
||||
break
|
||||
default:
|
||||
typeDescription = (
|
||||
<>
|
||||
{!schema.type ? "any" : schema.type}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
{schema.format ? ` <${schema.format}>` : ""}
|
||||
</>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className={clsx("w-2/3 break-words pb-0.5")}>
|
||||
{typeDescription}
|
||||
<div className={clsx("pb-0.5 flex flex-col gap-0.25")}>
|
||||
{schema.default !== undefined && (
|
||||
<>
|
||||
<br />
|
||||
<span>
|
||||
Default:{" "}
|
||||
<InlineCode className="break-words">
|
||||
{JSON.stringify(schema.default)}
|
||||
</InlineCode>
|
||||
</span>
|
||||
</>
|
||||
<span>
|
||||
Default:{" "}
|
||||
<InlineCode className="break-words">
|
||||
{JSON.stringify(schema.default)}
|
||||
</InlineCode>
|
||||
</span>
|
||||
)}
|
||||
{schema.enum && (
|
||||
<>
|
||||
<br />
|
||||
<span>
|
||||
Enum:{" "}
|
||||
{schema.enum.map((value, index) => (
|
||||
<Fragment key={index}>
|
||||
{index !== 0 && <>, </>}
|
||||
<InlineCode key={index}>{JSON.stringify(value)}</InlineCode>
|
||||
</Fragment>
|
||||
))}
|
||||
</span>
|
||||
</>
|
||||
<span>
|
||||
Enum:{" "}
|
||||
{schema.enum.map((value, index) => (
|
||||
<Fragment key={index}>
|
||||
{index !== 0 && <>, </>}
|
||||
<InlineCode key={index}>{JSON.stringify(value)}</InlineCode>
|
||||
</Fragment>
|
||||
))}
|
||||
</span>
|
||||
)}
|
||||
{schema.example !== undefined && (
|
||||
<>
|
||||
<br />
|
||||
<span>
|
||||
Example:{" "}
|
||||
<InlineCode className="break-words">
|
||||
{JSON.stringify(schema.example)}
|
||||
</InlineCode>
|
||||
</span>
|
||||
</>
|
||||
<span>
|
||||
Example:{" "}
|
||||
<InlineCode className="break-words">
|
||||
{JSON.stringify(schema.example)}
|
||||
</InlineCode>
|
||||
</span>
|
||||
)}
|
||||
{schema.description && (
|
||||
<>
|
||||
<br />
|
||||
<MDXContentClient
|
||||
content={capitalize(schema.description)}
|
||||
className={clsx("!mb-0 [&>*]:!mb-0")}
|
||||
@@ -120,33 +57,15 @@ const TagOperationParametersDescription = ({
|
||||
</>
|
||||
)}
|
||||
{schema.externalDocs && (
|
||||
<>
|
||||
<span>
|
||||
Related guide:{" "}
|
||||
<Link href={schema.externalDocs.url} target="_blank">
|
||||
{schema.externalDocs.description || "Read More"}
|
||||
</Link>
|
||||
</>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TagOperationParametersDescription
|
||||
|
||||
function formatArrayDescription(schema?: SchemaObject) {
|
||||
if (!schema) {
|
||||
return "Array"
|
||||
}
|
||||
|
||||
const type =
|
||||
schema.type === "object"
|
||||
? `objects ${schema.title ? `(${schema.title})` : ""}`
|
||||
: `${schema.type || "object"}s`
|
||||
|
||||
return `Array of ${type}`
|
||||
}
|
||||
|
||||
function formatUnionDescription(arr?: SchemaObject[]) {
|
||||
const types = [...new Set(arr?.map((type) => type.type || "object"))]
|
||||
return <>{types.join(" or ")}</>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { SchemaObject } from "@/types/openapi"
|
||||
import { Badge, ExpandableNotice, FeatureFlagNotice } from "docs-ui"
|
||||
import { Fragment } from "react"
|
||||
|
||||
export type TagOperationParametersNameProps = {
|
||||
name: string
|
||||
@@ -12,39 +13,101 @@ const TagOperationParametersName = ({
|
||||
isRequired,
|
||||
schema,
|
||||
}: TagOperationParametersNameProps) => {
|
||||
let typeDescription: React.ReactNode = <></>
|
||||
switch (true) {
|
||||
case schema.type === "object":
|
||||
typeDescription = (
|
||||
<>
|
||||
{schema.type} {schema.title ? `(${schema.title})` : ""}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
</>
|
||||
)
|
||||
break
|
||||
case schema.type === "array":
|
||||
typeDescription = (
|
||||
<>
|
||||
{schema.type === "array" && formatArrayDescription(schema.items)}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
</>
|
||||
)
|
||||
break
|
||||
case schema.anyOf !== undefined:
|
||||
case schema.allOf !== undefined:
|
||||
typeDescription = (
|
||||
<>
|
||||
{formatUnionDescription(schema.allOf)}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
</>
|
||||
)
|
||||
break
|
||||
case schema.oneOf !== undefined:
|
||||
typeDescription = (
|
||||
<>
|
||||
{schema.oneOf?.map((item, index) => (
|
||||
<Fragment key={index}>
|
||||
{index !== 0 && <> or </>}
|
||||
{item.type !== "array" && <>{item.title || item.type}</>}
|
||||
{item.type === "array" && (
|
||||
<>array{item.items.type ? ` of ${item.items.type}s` : ""}</>
|
||||
)}
|
||||
</Fragment>
|
||||
))}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
</>
|
||||
)
|
||||
break
|
||||
default:
|
||||
typeDescription = (
|
||||
<>
|
||||
{!schema.type ? "any" : schema.type}
|
||||
{schema.nullable ? ` or null` : ""}
|
||||
{schema.format ? ` <${schema.format}>` : ""}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="w-1/3 break-words pr-0.5">
|
||||
<span className="inline-flex gap-0.5 items-center">
|
||||
<span className="font-monospace">{name}</span>
|
||||
<span className="text-medusa-fg-muted text-compact-small">
|
||||
{typeDescription}
|
||||
</span>
|
||||
{schema.deprecated && (
|
||||
<Badge variant="orange" className="ml-1">
|
||||
deprecated
|
||||
</Badge>
|
||||
)}
|
||||
{schema["x-expandable"] && (
|
||||
<>
|
||||
<br />
|
||||
<ExpandableNotice type="request" link="#expanding-relations" />
|
||||
</>
|
||||
<ExpandableNotice type="request" link="#expanding-relations" />
|
||||
)}
|
||||
{schema["x-featureFlag"] && (
|
||||
<>
|
||||
<br />
|
||||
<FeatureFlagNotice
|
||||
featureFlag={schema["x-featureFlag"]}
|
||||
type="type"
|
||||
/>
|
||||
</>
|
||||
<FeatureFlagNotice featureFlag={schema["x-featureFlag"]} type="type" />
|
||||
)}
|
||||
{isRequired && (
|
||||
<>
|
||||
<br />
|
||||
<span className="text-medusa-tag-red-text text-compact-x-small">
|
||||
required
|
||||
</span>
|
||||
</>
|
||||
{!isRequired && (
|
||||
<span className="text-medusa-tag-blue-text text-compact-x-small">
|
||||
optional
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default TagOperationParametersName
|
||||
|
||||
function formatArrayDescription(schema?: SchemaObject) {
|
||||
if (!schema) {
|
||||
return "Array"
|
||||
}
|
||||
|
||||
const type =
|
||||
schema.type === "object"
|
||||
? `objects ${schema.title ? `(${schema.title})` : ""}`
|
||||
: `${schema.type || "object"}s`
|
||||
|
||||
return `Array of ${type}`
|
||||
}
|
||||
|
||||
function formatUnionDescription(arr?: SchemaObject[]) {
|
||||
const types = [...new Set(arr?.map((type) => type.type || "object"))]
|
||||
return <>{types.join(" or ")}</>
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ const TagOperationParametersDefault = ({
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"my-0.5 inline-flex justify-between",
|
||||
"my-0.5 inline-flex flex-col justify-between gap-0.25",
|
||||
expandable && "w-[calc(100%-16px)]",
|
||||
!expandable && "w-full pl-1",
|
||||
className
|
||||
|
||||
@@ -101,16 +101,20 @@ const TagOperationParametersObject = ({
|
||||
const content = (
|
||||
<>
|
||||
{sortedProperties.map((property, index) => (
|
||||
<TagOperationParameters
|
||||
schemaObject={{
|
||||
...properties[property],
|
||||
parameterName: property,
|
||||
}}
|
||||
key={index}
|
||||
isRequired={
|
||||
properties[property].isRequired || checkRequired(schema, property)
|
||||
}
|
||||
/>
|
||||
<>
|
||||
{index !== 0 && <hr className="bg-medusa-border-base my-0" />}
|
||||
<TagOperationParameters
|
||||
schemaObject={{
|
||||
...properties[property],
|
||||
parameterName: property,
|
||||
}}
|
||||
key={index}
|
||||
isRequired={
|
||||
properties[property].isRequired ||
|
||||
checkRequired(schema, property)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo } from "react"
|
||||
import { useEffect, useMemo, useRef, useState } from "react"
|
||||
import { SchemaObject } from "../../../../types/openapi"
|
||||
import TagOperationParameters from "../../Operation/Parameters"
|
||||
import {
|
||||
@@ -16,6 +16,8 @@ import useSchemaExample from "../../../../hooks/use-schema-example"
|
||||
import { InView } from "react-intersection-observer"
|
||||
import checkElementInViewport from "../../../../utils/check-element-in-viewport"
|
||||
import { singular } from "pluralize"
|
||||
import useResizeObserver from "@react-hook/resize-observer"
|
||||
import clsx from "clsx"
|
||||
|
||||
export type TagSectionSchemaProps = {
|
||||
schema: SchemaObject
|
||||
@@ -23,6 +25,8 @@ export type TagSectionSchemaProps = {
|
||||
}
|
||||
|
||||
const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => {
|
||||
const paramsRef = useRef<HTMLDivElement>(null)
|
||||
const [maxCodeHeight, setMaxCodeHeight] = useState(0)
|
||||
const { addItems, setActivePath, activePath } = useSidebar()
|
||||
const tagSlugName = useMemo(() => getSectionId([tagName]), [tagName])
|
||||
const formattedName = useMemo(
|
||||
@@ -39,6 +43,9 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => {
|
||||
skipNonRequired: false,
|
||||
},
|
||||
})
|
||||
useResizeObserver(paramsRef, () => {
|
||||
setMaxCodeHeight(paramsRef.current?.clientHeight || 0)
|
||||
})
|
||||
|
||||
const { scrollableElement, scrollToElement } = useScrollController()
|
||||
const root = useMemo(() => {
|
||||
@@ -106,7 +113,7 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => {
|
||||
>
|
||||
<DividedLayout
|
||||
mainContent={
|
||||
<SectionContainer>
|
||||
<SectionContainer ref={paramsRef}>
|
||||
<h2>{formattedName} Object</h2>
|
||||
<h4 className="border-medusa-border-base border-b py-1.5 mt-2">
|
||||
Fields
|
||||
@@ -121,6 +128,11 @@ const TagSectionSchema = ({ schema, tagName }: TagSectionSchemaProps) => {
|
||||
source={examples[0].content}
|
||||
lang="json"
|
||||
title={`The ${formattedName} Object`}
|
||||
className={clsx(maxCodeHeight && "overflow-auto")}
|
||||
style={{
|
||||
// remove padding + extra space
|
||||
maxHeight: maxCodeHeight ? maxCodeHeight - 212 : "unset",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</SectionContainer>
|
||||
|
||||
@@ -74,7 +74,7 @@ const TagSection = ({ tag }: TagSectionProps) => {
|
||||
return isElmWindow(scrollableElement) ? document.body : scrollableElement
|
||||
}, [scrollableElement])
|
||||
const { ref } = useInView({
|
||||
threshold: 0.5,
|
||||
threshold: 0.8,
|
||||
rootMargin: `112px 0px 112px 0px`,
|
||||
root,
|
||||
onChange: (inView) => {
|
||||
|
||||
Reference in New Issue
Block a user