diff --git a/frontend/src/components/workflows/VariableTablePanel.test.tsx b/frontend/src/components/workflows/VariableTablePanel.test.tsx new file mode 100644 index 000000000..b7d8b962c --- /dev/null +++ b/frontend/src/components/workflows/VariableTablePanel.test.tsx @@ -0,0 +1,24 @@ +import { describe, expect, it } from "vitest"; + +import { parsePlainForDisplay } from "./parse-plain-for-display"; + +describe("VariableTablePanel plain value display", () => { + it("shows a String value without its JSON quotes", () => { + expect(parsePlainForDisplay("String", "\"hello\"")).toBe("hello"); + }); + + it("falls back to the stored text when a String value is not valid JSON", () => { + expect(parsePlainForDisplay("String", "hello")).toBe("hello"); + }); + + it("keeps typed values readable without their JSON wrapper", () => { + expect(parsePlainForDisplay("Number", "42")).toBe("42"); + expect(parsePlainForDisplay("Boolean", "true")).toBe("true"); + }); + + it("leaves Object and Array values as the JSON the operator edits", () => { + expect(parsePlainForDisplay("Object", "{\"a\":1}")).toBe("{\"a\":1}"); + expect(parsePlainForDisplay("Array", "[1,2]")).toBe("[1,2]"); + }); + +}); diff --git a/frontend/src/components/workflows/VariableTablePanel.tsx b/frontend/src/components/workflows/VariableTablePanel.tsx index 882dcca49..8121d8fe3 100644 --- a/frontend/src/components/workflows/VariableTablePanel.tsx +++ b/frontend/src/components/workflows/VariableTablePanel.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { Ic } from "@/_imported/ai-code-space/icons"; import type { VariableSummary, VariableValueType } from "@/api/variables"; +import { parsePlainForDisplay } from "./parse-plain-for-display"; import { useDeleteProjectVariable, useDeleteTeamVariable, @@ -273,7 +274,7 @@ interface PlainValueEditorProps { } function PlainValueEditor({ valueType, valuePlain, isMutating, onSave }: PlainValueEditorProps) { - const [draft, setDraft] = useState(valuePlain ?? ""); + const [draft, setDraft] = useState(parsePlainForDisplay(valueType, valuePlain)); const save = async () => { const parsed = parsePlainAs(valueType, draft); diff --git a/frontend/src/components/workflows/parse-plain-for-display.ts b/frontend/src/components/workflows/parse-plain-for-display.ts new file mode 100644 index 000000000..5576df199 --- /dev/null +++ b/frontend/src/components/workflows/parse-plain-for-display.ts @@ -0,0 +1,21 @@ +import type { VariableValueType } from "@/api/variables"; + +/** + * Decode the stored JSON-encoded plaintext for display. String values are stored as JSON + * text (including quotes), so showing the raw column would render `"value"` in the editor. + * Object / Array keep their JSON text verbatim because that is what the operator edits. + */ +export function parsePlainForDisplay(valueType: VariableValueType, valuePlain: string | null): string { + const raw = valuePlain ?? ""; + if (valueType === "Object" || valueType === "Array" || raw === "") return raw; + + try { + const parsed: unknown = JSON.parse(raw); + if (typeof parsed === "string") return parsed; + if (typeof parsed === "number" || typeof parsed === "boolean") return String(parsed); + } catch { + // Malformed stored JSON falls back to the raw text so the operator can see and repair it. + } + + return raw; +} diff --git a/frontend/src/routes/_app.teams.$teamSlug.workflows.index.tsx b/frontend/src/routes/_app.teams.$teamSlug.workflows.index.tsx index 9e1b80c1e..5e62d1b49 100644 --- a/frontend/src/routes/_app.teams.$teamSlug.workflows.index.tsx +++ b/frontend/src/routes/_app.teams.$teamSlug.workflows.index.tsx @@ -114,14 +114,14 @@ function WorkflowsListPage() { )} {!workflows.isLoading && !workflows.error && rows.length > 0 && ( -
| Workflow | Triggers | Version | Updated | -+ | v{w.latestVersion} | {formatRelative(w.lastModifiedDate)} | -e.stopPropagation()}> + | e.stopPropagation()}>
|
|---|