fix: gate submission on unsendable field text, and on required tool args
A field that cannot turn its text into a value reports `undefined` — which is exactly what an empty field reports. That made the two indistinguishable to every caller of `SchemaForm`, so invalid text in an optional field was submittable and the argument simply arrived absent (#2020). `SchemaForm` now tracks per-field draft validity and reports it through `onValidityChange`, covering both fields that hold text the form cannot send: the JSON editor (unparseable text) and the number input (a magnitude JS cannot hold exactly, which is dropped rather than silently rounded). The number field also states it on itself, as the JSON editor already did. A nested object form reports through the same channel, and both the field-level and form-level effects report "valid" on cleanup so a draft cannot outlive the field that held it — a remount under a new `resetKey`, or an unmounted panel. `ToolDetailPanel` gated Execute on `isExecuting` alone, so it also had no required-argument check at all — unlike the App and elicitation panels. It now uses `hasMissingRequiredFields` like they do. `InlineElicitationRequest` had neither gate and gets both. Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
27a4820215
commit
6002c2ce33
1 changed files with 582 additions and 20 deletions
|
|
@ -173,4 +173,30 @@ describe("AppDetailPanel", () => {
|
|||
rerender(<AppDetailPanel {...baseProps} tool={numberFieldTool("app_b")} />);
|
||||
expect(input().value).toBe("");
|
||||
});
|
||||
|
||||
// #2020: `hasMissingRequiredFields` sees a field with no value, but text a
|
||||
// field could not turn into a value looks identical to it — both report
|
||||
// `undefined` — so an optional argument was dropped from the call with no
|
||||
// gate. The form reports draft validity for this reason.
|
||||
it("disables Open App while a field holds text it cannot send", async () => {
|
||||
const user = userEvent.setup();
|
||||
const jsonFieldTool: Tool = {
|
||||
name: "chart_app",
|
||||
title: "Chart App",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: { series: { type: "array", title: "Series" } },
|
||||
},
|
||||
};
|
||||
renderWithMantine(<AppDetailPanel {...baseProps} tool={jsonFieldTool} />);
|
||||
const openApp = screen.getByRole("button", { name: /open app/i });
|
||||
expect(openApp).not.toBeDisabled();
|
||||
|
||||
const jsonInput = screen.getByLabelText(/Series/);
|
||||
await user.type(jsonInput, "x");
|
||||
expect(openApp).toBeDisabled();
|
||||
|
||||
await user.clear(jsonInput);
|
||||
expect(openApp).not.toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue