Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import type { DereferencedSchema } from "./schemaFilter";
import type { ContentFormat } from "./workflowSdk";

/**
* A single form field descriptor produced by walking a task's JSON Schema.
Expand Down Expand Up @@ -107,7 +108,7 @@ export interface MapField extends FieldBase {

export interface JsonField extends FieldBase {
kind: "json";
format: "json" | "yaml";
format: ContentFormat;
}

export interface OneOfField extends FieldBase {
Expand Down Expand Up @@ -313,7 +314,7 @@ export function schemaToFormFields(
defs?: Record<string, unknown>,
requiredSet?: Set<string>,
path = "",
format: "json" | "yaml" = "yaml",
format: ContentFormat = "yaml",
): FormFieldDescriptor[] {
const fields: FormFieldDescriptor[] = [];

Expand Down Expand Up @@ -636,7 +637,7 @@ function buildOneOfVariants(
candidates: unknown[],
defs: Record<string, unknown> | undefined,
parentPath: string,
format: "json" | "yaml" = "yaml",
format: ContentFormat = "yaml",
): OneOfVariant[] {
const leafPath = parentPath || "__leaf__";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import { GraphNodeType } from "@openworkflowspec/sdk";
import { getSchemaForDefinition } from "./schemaFilter";
import { schemaToFormFields, FormFieldDescriptor } from "./schemaToFormFields";
import type { ContentFormat } from "./workflowSdk";

// ---------------------------------------------------------------------------
// Node-type → schema definition-name mapping
Expand Down Expand Up @@ -60,7 +61,7 @@ const _fieldCache = new Map<string, FormFieldDescriptor[]>();
*/
export function getFormFieldsForNodeType(
nodeType: string,
format: "json" | "yaml" = "yaml",
format: ContentFormat = "yaml",
): FormFieldDescriptor[] {
const cacheKey = `${nodeType}:${format}`;
const cached = _fieldCache.get(cacheKey);
Expand Down

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@handreyrc I opened a PR to your fork, trying to simplify this component.
Can you please review and test my version?

Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ function SingleLineStringControl({ field, id }: StringControlProps) {
}
}
setInputValue(typeof live === "string" ? live : "");
// `getValues` and `getFieldState` are plain functions created inside
// react-hook-form's `useForm` and are NOT wrapped in useCallback, so their
// reference changes on every render. Including them in the dependency array
// would re-run this effect on every render. They are intentionally omitted
// because the logic only needs to re-run when the form resets (new
// `defaultValues` identity) or when the field path / kind changes.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [defaultValues, field.path, field.isRuntimeExpression]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Controller, useFormContext, useFormState } from "react-hook-form";
import { dump, load } from "js-yaml";
import { Textarea } from "../ui/textarea";
import type { JsonField } from "../../../core/schemaToFormFields";
import type { ContentFormat } from "../../../core/workflowSdk";
import { useTaskFormContext, getNestedValue } from "../taskFormContext";
import { useFieldError, FieldWithError } from "./fieldHelpers";

Expand All @@ -31,7 +32,7 @@ export type StructuredValueFieldProps = {
id?: string | undefined;
};

function valueToText(value: unknown, format: "json" | "yaml"): string {
function valueToText(value: unknown, format: ContentFormat): string {
if (value === undefined || value === null) return "";
if (typeof value === "string") return value;
try {
Expand All @@ -43,7 +44,7 @@ function valueToText(value: unknown, format: "json" | "yaml"): string {
}
}

function parseText(text: string, format: "json" | "yaml"): unknown {
function parseText(text: string, format: ContentFormat): unknown {
if (format === "json") {
return JSON.parse(text);
}
Expand Down Expand Up @@ -104,6 +105,12 @@ export function StructuredValueField({ field, id }: StructuredValueFieldProps) {
return;
}
setText(valueToText(fromDefault, field.format));
// The effect intentionally reads `prevDefaultValuesRef`, `prevFormatRef`,
// and `prevPathRef` as mutable ref containers — refs are stable objects and
// must NOT be in the dependency array (they never change identity, so adding
// them would not trigger the effect; and their `.current` mutations are the
// side-effect, not the trigger). The deps are exactly the reactive values
// that should re-run the effect: `defaultValues`, `field.format`, `field.path`.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [defaultValues, field.format, field.path]);

Expand Down
Loading