Skip to content

Commit 717c394

Browse files
authored
Merge pull request #157 from kshern/feature/add-array-proptype
Add an array input field to the ToolsTab using DynamicJsonForm.
2 parents e28a64c + 8267e51 commit 717c394

File tree

2 files changed

+111
-29
lines changed

2 files changed

+111
-29
lines changed

client/src/components/DynamicJsonForm.tsx

Lines changed: 103 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -215,23 +215,112 @@ const DynamicJsonForm = ({
215215
return;
216216
}
217217

218-
const newValue = {
219-
...(typeof value === "object" && value !== null && !Array.isArray(value)
220-
? value
221-
: {}),
222-
} as JsonObject;
223-
let current: JsonObject = newValue;
218+
const updateArray = (
219+
array: JsonValue[],
220+
path: string[],
221+
value: JsonValue,
222+
): JsonValue[] => {
223+
const [index, ...restPath] = path;
224+
const arrayIndex = Number(index);
224225

225-
for (let i = 0; i < path.length - 1; i++) {
226-
const key = path[i];
227-
if (!(key in current)) {
228-
current[key] = {};
226+
// Validate array index
227+
if (isNaN(arrayIndex)) {
228+
console.error(`Invalid array index: ${index}`);
229+
return array;
230+
}
231+
232+
// Check array bounds
233+
if (arrayIndex < 0) {
234+
console.error(`Array index out of bounds: ${arrayIndex} < 0`);
235+
return array;
236+
}
237+
238+
const newArray = [...array];
239+
240+
if (restPath.length === 0) {
241+
newArray[arrayIndex] = value;
242+
} else {
243+
// Ensure index position exists
244+
if (arrayIndex >= array.length) {
245+
console.warn(`Extending array to index ${arrayIndex}`);
246+
newArray.length = arrayIndex + 1;
247+
newArray.fill(null, array.length, arrayIndex);
248+
}
249+
newArray[arrayIndex] = updateValue(
250+
newArray[arrayIndex],
251+
restPath,
252+
value,
253+
);
254+
}
255+
return newArray;
256+
};
257+
258+
const updateObject = (
259+
obj: JsonObject,
260+
path: string[],
261+
value: JsonValue,
262+
): JsonObject => {
263+
const [key, ...restPath] = path;
264+
265+
// Validate object key
266+
if (typeof key !== "string") {
267+
console.error(`Invalid object key: ${key}`);
268+
return obj;
229269
}
230-
current = current[key] as JsonObject;
231-
}
232270

233-
current[path[path.length - 1]] = fieldValue;
234-
onChange(newValue);
271+
const newObj = { ...obj };
272+
273+
if (restPath.length === 0) {
274+
newObj[key] = value;
275+
} else {
276+
// Ensure key exists
277+
if (!(key in newObj)) {
278+
console.warn(`Creating new key in object: ${key}`);
279+
newObj[key] = {};
280+
}
281+
newObj[key] = updateValue(newObj[key], restPath, value);
282+
}
283+
return newObj;
284+
};
285+
286+
const updateValue = (
287+
current: JsonValue,
288+
path: string[],
289+
value: JsonValue,
290+
): JsonValue => {
291+
if (path.length === 0) return value;
292+
293+
try {
294+
if (!current) {
295+
current = !isNaN(Number(path[0])) ? [] : {};
296+
}
297+
298+
// Type checking
299+
if (Array.isArray(current)) {
300+
return updateArray(current, path, value);
301+
} else if (typeof current === "object" && current !== null) {
302+
return updateObject(current, path, value);
303+
} else {
304+
console.error(
305+
`Cannot update path ${path.join(".")} in non-object/array value:`,
306+
current,
307+
);
308+
return current;
309+
}
310+
} catch (error) {
311+
console.error(`Error updating value at path ${path.join(".")}:`, error);
312+
return current;
313+
}
314+
};
315+
316+
try {
317+
const newValue = updateValue(value, path, fieldValue);
318+
onChange(newValue);
319+
} catch (error) {
320+
console.error("Failed to update form value:", error);
321+
// Keep the original value unchanged
322+
onChange(value);
323+
}
235324
};
236325

237326
return (

client/src/components/ToolsTab.tsx

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@ import ListPane from "./ListPane";
1717

1818
import { CompatibilityCallToolResult } from "@modelcontextprotocol/sdk/types.js";
1919

20-
type SchemaProperty = {
21-
type: string;
22-
description?: string;
23-
properties?: Record<string, SchemaProperty>;
24-
};
25-
2620
const ToolsTab = ({
2721
tools,
2822
listTools,
@@ -168,7 +162,7 @@ const ToolsTab = ({
168162
</p>
169163
{Object.entries(selectedTool.inputSchema.properties ?? []).map(
170164
([key, value]) => {
171-
const prop = value as SchemaProperty;
165+
const prop = value as JsonSchemaType;
172166
return (
173167
<div key={key}>
174168
<Label
@@ -211,16 +205,15 @@ const ToolsTab = ({
211205
}
212206
className="mt-1"
213207
/>
214-
) : prop.type === "object" ? (
208+
) : prop.type === "object" || prop.type === "array" ? (
215209
<div className="mt-1">
216210
<DynamicJsonForm
217-
schema={
218-
{
219-
type: "object",
220-
properties: prop.properties,
221-
description: prop.description,
222-
} as JsonSchemaType
223-
}
211+
schema={{
212+
type: prop.type,
213+
properties: prop.properties,
214+
description: prop.description,
215+
items: prop.items,
216+
}}
224217
value={(params[key] as JsonValue) ?? {}}
225218
onChange={(newValue: JsonValue) => {
226219
setParams({

0 commit comments

Comments
 (0)