Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions demo/examples/tests/paramDefaults.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
openapi: 3.0.0
info:
title: Parameter Defaults Demo API
version: 1.0.0
description: |
Validates that `schema.default` values are pre-populated in the API explorer
form for parameters in every location (header, query, path, cookie) and for
the common scalar/enum/boolean schema types.

Regression coverage for: https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/issues/1226

tags:
- name: defaults
description: Parameter default value tests

paths:
/headers:
get:
tags:
- defaults
summary: Header parameter defaults
description: |
Each header below declares a `schema.default`. The right-hand request
form should render those defaults pre-filled and the generated code
snippets should include them.
parameters:
- name: X-Api-Version
in: header
description: Free-form string default.
required: true
schema:
type: string
default: "2025-01-01"
- name: X-Region
in: header
description: Enum default — should appear pre-selected in the dropdown.
schema:
type: string
enum:
- us-east-1
- us-west-2
- eu-central-1
default: us-west-2
- name: X-Trace-Enabled
in: header
description: Boolean default — should appear pre-selected as "true".
schema:
type: boolean
default: true
responses:
"200":
description: OK

/query:
get:
tags:
- defaults
summary: Query parameter defaults
parameters:
- name: limit
in: query
description: Integer default.
schema:
type: integer
default: 25
- name: sort
in: query
description: Enum default.
schema:
type: string
enum:
- asc
- desc
default: desc
responses:
"200":
description: OK

/items/{itemId}:
get:
tags:
- defaults
summary: Path parameter default
description: |
Path defaults are unusual but legal — confirm the form pre-fills the
value rather than leaving the URL placeholder unresolved.
parameters:
- name: itemId
in: path
required: true
schema:
type: string
default: sample-item
responses:
"200":
description: OK

/session:
get:
tags:
- defaults
summary: Cookie parameter default
parameters:
- name: session_id
in: cookie
schema:
type: string
default: anonymous
responses:
"200":
description: OK
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
* ========================================================================== */

import React from "react";
import React, { useEffect } from "react";

import { translate } from "@docusaurus/Translate";
import { ErrorMessage } from "@hookform/error-message";
Expand Down Expand Up @@ -33,10 +33,26 @@ export default function ParamBooleanFormItem({
const {
control,
formState: { errors },
setValue,
} = useFormContext();

const showErrorMessage = errors?.paramBoolean;

useEffect(() => {
if (param.value === undefined) return;
const initial =
typeof param.value === "boolean" ? String(param.value) : param.value;
if (initial === "true" || initial === "false") {
setValue("paramBoolean", initial);
// Boolean defaults arrive in redux as actual booleans; normalize to the
// string form the rest of the form uses.
if (typeof param.value === "boolean") {
dispatch(setParam({ ...param, value: initial }));
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<>
<Controller
Expand All @@ -50,11 +66,12 @@ export default function ParamBooleanFormItem({
: false,
}}
name="paramBoolean"
render={({ field: { onChange } }) => (
render={({ field: { onChange, value } }) => (
<FormSelect
label={label}
type={type}
required={required}
value={value ?? "---"}
options={["---", "true", "false"]}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
const val = e.target.value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
* ========================================================================== */

import React from "react";
import React, { useEffect } from "react";

import { translate } from "@docusaurus/Translate";
import { ErrorMessage } from "@hookform/error-message";
Expand All @@ -32,6 +32,7 @@ export default function ParamSelectFormItem({
const {
control,
formState: { errors },
setValue,
} = useFormContext();

const showErrorMessage = errors?.paramSelect;
Expand All @@ -40,6 +41,16 @@ export default function ParamSelectFormItem({

const options = getSchemaEnum(param.schema) ?? [];

useEffect(() => {
if (
typeof param.value === "string" &&
(options as string[]).includes(param.value)
) {
setValue("paramSelect", param.value);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<>
<Controller
Expand All @@ -53,11 +64,12 @@ export default function ParamSelectFormItem({
: false,
}}
name="paramSelect"
render={({ field: { onChange } }) => (
render={({ field: { onChange, value } }) => (
<FormSelect
label={label}
type={type}
required={required}
value={value ?? "---"}
options={["---", ...(options as string[])]}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
const val = e.target.value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
* LICENSE file in the root directory of this source tree.
* ========================================================================== */

import React from "react";
import React, { useEffect } from "react";

import FormTextInput from "@theme/ApiExplorer/FormTextInput";
import { Param, setParam } from "@theme/ApiExplorer/ParamOptions/slice";
import { useTypedDispatch } from "@theme/ApiItem/hooks";
import { useFormContext } from "react-hook-form";

export interface ParamProps {
param: Param;
Expand All @@ -25,6 +26,15 @@ export default function ParamTextFormItem({
required,
}: ParamProps) {
const dispatch = useTypedDispatch();
const { setValue } = useFormContext();

useEffect(() => {
if (param.value !== undefined && !Array.isArray(param.value)) {
setValue(param.name, param.value);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<FormTextInput
label={label}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,12 @@ export default function ApiItem(props: Props): JSX.Element {
(param: { in: "path" | "query" | "header" | "cookie" }) => {
const paramType = param.in;
const paramsArray: ParameterObject[] = params[paramType];
paramsArray?.push(param as ParameterObject);
const defaultValue = (param as any).schema?.default;
const initialized =
defaultValue !== undefined
? ({ ...param, value: defaultValue } as unknown as ParameterObject)
: (param as ParameterObject);
paramsArray?.push(initialized);
}
);
const auth = createAuth({
Expand Down
Loading