Skip to content
Merged
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
24 changes: 24 additions & 0 deletions frontend/src/components/workflows/VariableTablePanel.test.tsx
Original file line number Diff line number Diff line change
@@ -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]");
});

});
3 changes: 2 additions & 1 deletion frontend/src/components/workflows/VariableTablePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/components/workflows/parse-plain-for-display.ts
Original file line number Diff line number Diff line change
@@ -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;
}
8 changes: 4 additions & 4 deletions frontend/src/routes/_app.teams.$teamSlug.workflows.index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ function WorkflowsListPage() {
)}

{!workflows.isLoading && !workflows.error && rows.length > 0 && (
<table className="tbl">
<table className="tbl wf-table">
<thead>
<tr>
<th style={{ width: "44%" }}>Workflow</th>
<th>Triggers</th>
<th>Version</th>
<th>Updated</th>
<th className="col-right" />
<th className="col-right wf-col-actions" />
</tr>
</thead>
<tbody>
Expand All @@ -146,7 +146,7 @@ function WorkflowsListPage() {
</div>
<div className="repo-info">
<div className="repo-name">
{w.name}
<span className="repo-name-text" title={w.name}>{w.name}</span>
{!w.enabled && <span className="wf-badge wf-badge-disabled">disabled</span>}
</div>
{/* Wrap in .repo-path-desc so a long description ellipsis-truncates
Expand All @@ -169,7 +169,7 @@ function WorkflowsListPage() {
</td>
<td><span className="wf-version">v{w.latestVersion}</span></td>
<td>{formatRelative(w.lastModifiedDate)}</td>
<td className="col-right" onClick={(e) => e.stopPropagation()}>
<td className="col-right wf-col-actions" onClick={(e) => e.stopPropagation()}>
<div className="wf-row-actions">
<button
className="btn btn-ghost"
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/styles/ai-code-space.css
Original file line number Diff line number Diff line change
Expand Up @@ -2030,6 +2030,14 @@ textarea:-webkit-autofill {
.acs-root .wf-trigger-chip-soft { background: var(--panel-2); color: var(--ink-2); }
.acs-root .wf-trigger-muted { color: var(--muted); font-size: 11.5px; font-style: italic; }

/* Workflows list: auto layout lets long names/trigger chips widen the Workflow column
* until the action buttons are pushed out of view. Fixed layout + a reserved action
* width keeps them visible; narrow viewports scroll through .ct-body. */
.acs-root .wf-table { table-layout: fixed; min-width: 760px; }
.acs-root .wf-table .repo-name { min-width: 0; }
.acs-root .wf-table .repo-name-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acs-root .wf-table .wf-col-actions { width: 104px; white-space: nowrap; }

.acs-root .wf-version {
display: inline-block; font-family: inherit; font-size: 10.5px; color: var(--muted);
padding: 1px 5px; border: 1px solid var(--line); border-radius: 3px; background: var(--panel);
Expand Down
Loading