[eric] tool-ui: string columns coerce instead of failing, validation runs per payload not per render, rowIdKey nags only when actionable

This commit is contained in:
ciregenz
2026-08-04 20:31:30 -07:00
parent 96565841ff
commit bd1855da30
3 changed files with 39 additions and 17 deletions
@@ -651,7 +651,9 @@ function DataTableBody() {
React.useEffect(() => {
if (hasWarnedRowKeyRef.current) return;
if (process.env.NODE_ENV !== "production" && !rowIdKey && data.length > 0) {
// Only nag when the data actually CARRIES an id-like field the caller forgot to point at; model payloads usually have none, and the warning was pure console noise for them.
const hasIdLikeField = data.length > 0 && ["id", "uuid", "key", "symbol"].some((k) => k in (data[0] as Record<string, unknown>));
if (process.env.NODE_ENV !== "production" && !rowIdKey && hasIdLikeField) {
hasWarnedRowKeyRef.current = true;
console.warn(
"[DataTable] Missing `rowIdKey` prop. Falling back to inferred/content-derived row keys. " +
@@ -79,18 +79,31 @@ const formatSchema = z.discriminatedUnion("kind", [
}),
]);
export const serializableColumnSchema = z.object({
key: z.string(),
label: z.string(),
abbr: z.string().optional(),
sortable: z.boolean().optional(),
align: AlignEnum.optional(),
width: z.string().optional(),
truncate: z.boolean().optional(),
priority: PriorityEnum.optional(),
hideOnMobile: z.boolean().optional(),
format: formatSchema.optional(),
});
// Models routinely send columns as bare strings or as {key}-only / {label}-only objects; rejecting those threw away perfectly renderable tables, so coerce instead of failing.
export const serializableColumnSchema = z.preprocess(
(raw) => {
if (typeof raw === "string") return { key: raw, label: raw };
if (raw && typeof raw === "object") {
const o = raw as Record<string, unknown>;
const key = typeof o.key === "string" ? o.key : typeof o.label === "string" ? o.label : undefined;
const label = typeof o.label === "string" ? o.label : typeof o.key === "string" ? o.key : undefined;
if (key !== undefined || label !== undefined) return { ...o, key, label };
}
return raw;
},
z.object({
key: z.string(),
label: z.string(),
abbr: z.string().optional(),
sortable: z.boolean().optional(),
align: AlignEnum.optional(),
width: z.string().optional(),
truncate: z.boolean().optional(),
priority: PriorityEnum.optional(),
hideOnMobile: z.boolean().optional(),
format: formatSchema.optional(),
}),
);
const JsonPrimitiveSchema = z.union([
z.string(),