Skip to content

Commit 4a61bae

Browse files
sserrataclaude
andauthored
fix(theme): pre-populate parameter defaults in API explorer form (#1226) (#1448)
Read `schema.default` when initializing the params slice and sync that value into react-hook-form on mount for text, select, and boolean form items so the right-hand request form renders defaults instead of empty inputs. Affected all parameter locations (header, query, path, cookie); headers were the most visible regression. Also adds an OpenAPI test schema covering each location and schema type used by the demo `tests` plugin instance. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 4f556c9 commit 4a61bae

5 files changed

Lines changed: 161 additions & 6 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
openapi: 3.0.0
2+
info:
3+
title: Parameter Defaults Demo API
4+
version: 1.0.0
5+
description: |
6+
Validates that `schema.default` values are pre-populated in the API explorer
7+
form for parameters in every location (header, query, path, cookie) and for
8+
the common scalar/enum/boolean schema types.
9+
10+
Regression coverage for: https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/issues/1226
11+
12+
tags:
13+
- name: defaults
14+
description: Parameter default value tests
15+
16+
paths:
17+
/headers:
18+
get:
19+
tags:
20+
- defaults
21+
summary: Header parameter defaults
22+
description: |
23+
Each header below declares a `schema.default`. The right-hand request
24+
form should render those defaults pre-filled and the generated code
25+
snippets should include them.
26+
parameters:
27+
- name: X-Api-Version
28+
in: header
29+
description: Free-form string default.
30+
required: true
31+
schema:
32+
type: string
33+
default: "2025-01-01"
34+
- name: X-Region
35+
in: header
36+
description: Enum default — should appear pre-selected in the dropdown.
37+
schema:
38+
type: string
39+
enum:
40+
- us-east-1
41+
- us-west-2
42+
- eu-central-1
43+
default: us-west-2
44+
- name: X-Trace-Enabled
45+
in: header
46+
description: Boolean default — should appear pre-selected as "true".
47+
schema:
48+
type: boolean
49+
default: true
50+
responses:
51+
"200":
52+
description: OK
53+
54+
/query:
55+
get:
56+
tags:
57+
- defaults
58+
summary: Query parameter defaults
59+
parameters:
60+
- name: limit
61+
in: query
62+
description: Integer default.
63+
schema:
64+
type: integer
65+
default: 25
66+
- name: sort
67+
in: query
68+
description: Enum default.
69+
schema:
70+
type: string
71+
enum:
72+
- asc
73+
- desc
74+
default: desc
75+
responses:
76+
"200":
77+
description: OK
78+
79+
/items/{itemId}:
80+
get:
81+
tags:
82+
- defaults
83+
summary: Path parameter default
84+
description: |
85+
Path defaults are unusual but legal — confirm the form pre-fills the
86+
value rather than leaving the URL placeholder unresolved.
87+
parameters:
88+
- name: itemId
89+
in: path
90+
required: true
91+
schema:
92+
type: string
93+
default: sample-item
94+
responses:
95+
"200":
96+
description: OK
97+
98+
/session:
99+
get:
100+
tags:
101+
- defaults
102+
summary: Cookie parameter default
103+
parameters:
104+
- name: session_id
105+
in: cookie
106+
schema:
107+
type: string
108+
default: anonymous
109+
responses:
110+
"200":
111+
description: OK

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
* ========================================================================== */
77

8-
import React from "react";
8+
import React, { useEffect } from "react";
99

1010
import { translate } from "@docusaurus/Translate";
1111
import { ErrorMessage } from "@hookform/error-message";
@@ -33,10 +33,26 @@ export default function ParamBooleanFormItem({
3333
const {
3434
control,
3535
formState: { errors },
36+
setValue,
3637
} = useFormContext();
3738

3839
const showErrorMessage = errors?.paramBoolean;
3940

41+
useEffect(() => {
42+
if (param.value === undefined) return;
43+
const initial =
44+
typeof param.value === "boolean" ? String(param.value) : param.value;
45+
if (initial === "true" || initial === "false") {
46+
setValue("paramBoolean", initial);
47+
// Boolean defaults arrive in redux as actual booleans; normalize to the
48+
// string form the rest of the form uses.
49+
if (typeof param.value === "boolean") {
50+
dispatch(setParam({ ...param, value: initial }));
51+
}
52+
}
53+
// eslint-disable-next-line react-hooks/exhaustive-deps
54+
}, []);
55+
4056
return (
4157
<>
4258
<Controller
@@ -50,11 +66,12 @@ export default function ParamBooleanFormItem({
5066
: false,
5167
}}
5268
name="paramBoolean"
53-
render={({ field: { onChange } }) => (
69+
render={({ field: { onChange, value } }) => (
5470
<FormSelect
5571
label={label}
5672
type={type}
5773
required={required}
74+
value={value ?? "---"}
5875
options={["---", "true", "false"]}
5976
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
6077
const val = e.target.value;

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
* ========================================================================== */
77

8-
import React from "react";
8+
import React, { useEffect } from "react";
99

1010
import { translate } from "@docusaurus/Translate";
1111
import { ErrorMessage } from "@hookform/error-message";
@@ -32,6 +32,7 @@ export default function ParamSelectFormItem({
3232
const {
3333
control,
3434
formState: { errors },
35+
setValue,
3536
} = useFormContext();
3637

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

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

44+
useEffect(() => {
45+
if (
46+
typeof param.value === "string" &&
47+
(options as string[]).includes(param.value)
48+
) {
49+
setValue("paramSelect", param.value);
50+
}
51+
// eslint-disable-next-line react-hooks/exhaustive-deps
52+
}, []);
53+
4354
return (
4455
<>
4556
<Controller
@@ -53,11 +64,12 @@ export default function ParamSelectFormItem({
5364
: false,
5465
}}
5566
name="paramSelect"
56-
render={({ field: { onChange } }) => (
67+
render={({ field: { onChange, value } }) => (
5768
<FormSelect
5869
label={label}
5970
type={type}
6071
required={required}
72+
value={value ?? "---"}
6173
options={["---", ...(options as string[])]}
6274
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
6375
const val = e.target.value;

packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
* LICENSE file in the root directory of this source tree.
66
* ========================================================================== */
77

8-
import React from "react";
8+
import React, { useEffect } from "react";
99

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

1415
export interface ParamProps {
1516
param: Param;
@@ -25,6 +26,15 @@ export default function ParamTextFormItem({
2526
required,
2627
}: ParamProps) {
2728
const dispatch = useTypedDispatch();
29+
const { setValue } = useFormContext();
30+
31+
useEffect(() => {
32+
if (param.value !== undefined && !Array.isArray(param.value)) {
33+
setValue(param.name, param.value);
34+
}
35+
// eslint-disable-next-line react-hooks/exhaustive-deps
36+
}, []);
37+
2838
return (
2939
<FormTextInput
3040
label={label}

packages/docusaurus-theme-openapi-docs/src/theme/ApiItem/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,12 @@ export default function ApiItem(props: Props): JSX.Element {
122122
(param: { in: "path" | "query" | "header" | "cookie" }) => {
123123
const paramType = param.in;
124124
const paramsArray: ParameterObject[] = params[paramType];
125-
paramsArray?.push(param as ParameterObject);
125+
const defaultValue = (param as any).schema?.default;
126+
const initialized =
127+
defaultValue !== undefined
128+
? ({ ...param, value: defaultValue } as unknown as ParameterObject)
129+
: (param as ParameterObject);
130+
paramsArray?.push(initialized);
126131
}
127132
);
128133
const auth = createAuth({

0 commit comments

Comments
 (0)