Skip to content

fix: pipeline editor UX improvements#112

Merged
TerrifiedBug merged 9 commits intomainfrom
ux-improvements
Mar 26, 2026
Merged

fix: pipeline editor UX improvements#112
TerrifiedBug merged 9 commits intomainfrom
ux-improvements

Conversation

@TerrifiedBug
Copy link
Copy Markdown
Owner

Summary

  • Error badge scoped to session: Red dot on logs icon now only shows ERROR-level logs from the current pipeline process lifecycle (using uptimeSeconds), not a hardcoded 24h window
  • Uptime column: Added pipeline uptime to the pipeline list table (min across all running nodes)
  • AI + Debug merged: Consolidated the separate AI Builder (Sparkles) and Debug (Bug) dialogs into a single "AI Assistant" dialog with three tabs: Generate / Review / Debug
  • Modal stability: Disabled refetchOnWindowFocus globally to prevent modals (VRL editor, config forms) from closing when switching browser tabs
  • Fleet tab order: Swapped Nodes and Overview tabs so the default view (Nodes) is on the left

Test plan

  • Open pipeline editor, verify red dot only appears for errors in current session (not old ones from previous runs)
  • Check pipeline list page shows Uptime column with correct formatting
  • Open AI Assistant dialog, verify all 3 tabs work (Generate, Review, Debug)
  • Verify Bug icon is removed from toolbar, only Sparkles remains
  • Open VRL editor or any modal, switch browser tabs and return — modal should stay open
  • Navigate to /fleet, verify Nodes tab is on the left

@github-actions github-actions bot added the fix label Mar 26, 2026
…ity lint

Date.now() is impure and cannot be called inside useMemo per
react-hooks/purity. Moved to useEffect + useState instead.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 26, 2026

Greptile Summary

This PR delivers five UX improvements to the pipeline editor and fleet pages: scoping the error badge to the current process session via uptimeSeconds, adding an Uptime column to the pipeline list, consolidating the AI Builder and Debug dialogs into a single 3-tab "AI Assistant", disabling refetchOnWindowFocus globally to stabilise modals, and reordering the Fleet tabs. The changes are well-scoped and follow established patterns — uptimeSeconds is threaded correctly through the tRPC layer, the debug-tab migration from ai-debug-panel.tsx is faithful to the deleted component, and the session-start derivation logic is sound.\n\nKey changes:\n- pipeline.get and listPipelinesForEnvironment now select uptimeSeconds from nodeStatuses; minUptimeSeconds is computed server-side and surfaced in the pipeline list\n- sessionStart is derived client-side as Date.now() - minUptime * 1000; the error-badge query is disabled (via enabled) when no running nodes exist, keeping the non-null assertion safe at runtime\n- AiDebugPanel is deleted; its conversation UI is reproduced in a new Debug TabsContent inside AiPipelineDialog, backed by the existing useAiDebugConversation hook\n- Global refetchOnWindowFocus: false is intentional — live data is already driven by explicit refetchInterval on metric queries\n- One minor bug: formatUptime uses !seconds which returns "—" for seconds === 0, conflating "no data" with "just started"

Confidence Score: 4/5

Safe to merge after the one-line formatUptime fix; no security or data-loss risk introduced.

All logic changes are correct and the implementation is clean. Only one minor correctness bug exists (formatUptime returning "—" for 0 seconds instead of "0s"), which is a trivial one-line fix. The session-scoped error badge, merged AI dialog, and global refetchOnWindowFocus change all behave as intended.

src/app/(dashboard)/pipelines/page.tsx — formatUptime bug on line 128

Important Files Changed

Filename Overview
src/app/(dashboard)/fleet/page.tsx Tab order swap — Nodes moved before Overview. Pure UI reorder, no logic changes.
src/app/(dashboard)/pipelines/[id]/page.tsx Removed AiDebugPanel; replaced hardcoded 24h error-check window with session-scoped sessionStart derived from min uptimeSeconds; passes currentYaml to merged AiPipelineDialog.
src/app/(dashboard)/pipelines/page.tsx Adds formatUptime helper and Uptime column using minUptimeSeconds; minor bug: !seconds conflates null and 0.
src/components/flow/ai-debug-panel.tsx File deleted — functionality absorbed into the Debug tab of ai-pipeline-dialog.tsx.
src/components/flow/ai-pipeline-dialog.tsx Merged Generate/Review/Debug into a single 3-tab dialog; Debug tab wires useAiDebugConversation with the new currentYaml prop; logic mirrors the deleted AiDebugPanel faithfully.
src/components/flow/flow-toolbar.tsx Removed Bug button and onDebugOpen prop; consolidated to single Sparkles AI assistant button.
src/server/routers/pipeline.ts Adds uptimeSeconds to the nodeStatuses select in pipeline.get — minimal, correct change.
src/server/services/pipeline-graph.ts Adds uptimeSeconds to nodeStatuses select and computes minUptimeSeconds (min uptime across RUNNING nodes) in the list response.
src/trpc/client.tsx Adds refetchOnWindowFocus: false globally to prevent modals from unmounting on tab switch.

Sequence Diagram

sequenceDiagram
    participant PE as Pipeline Editor
    participant PQ as pipelineQuery (tRPC)
    participant DB as DB (nodeStatuses)
    participant EQ as recentErrorsQuery

    PE->>PQ: pipeline.get({ id })
    PQ->>DB: SELECT status, uptimeSeconds FROM nodeStatuses
    DB-->>PQ: [{ status: "RUNNING", uptimeSeconds: 300 }]
    PQ-->>PE: pipelineQuery.data.nodeStatuses

    Note over PE: useMemo → sessionStart = now - minUptime*1000

    alt sessionStart != null AND isDeployed
        PE->>EQ: pipeline.logs({ since: sessionStart, levels: ["ERROR"] })
        EQ-->>PE: hasRecentErrors = items.length > 0
        Note over PE: Red dot shown only for current session
    else sessionStart is null (no running nodes)
        Note over PE: recentErrorsQuery disabled, no badge
    end
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/app/(dashboard)/pipelines/page.tsx
Line: 128

Comment:
**`formatUptime` returns "—" for `0` seconds**

`!seconds` is truthy for both `null` and `0`. If a heartbeat arrives with `uptimeSeconds: 0` (pipeline just started), the Uptime column will display "—" instead of "0s". The condition should check strictly for `null`/`undefined`:

```suggestion
  if (seconds == null) return "\u2014";
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix: use useEffect instead of useMemo fo..." | Re-trigger Greptile

}

function formatUptime(seconds: number | null): string {
if (!seconds) return "\u2014";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 formatUptime returns "—" for 0 seconds

!seconds is truthy for both null and 0. If a heartbeat arrives with uptimeSeconds: 0 (pipeline just started), the Uptime column will display "—" instead of "0s". The condition should check strictly for null/undefined:

Suggested change
if (!seconds) return "\u2014";
if (seconds == null) return "\u2014";
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/app/(dashboard)/pipelines/page.tsx
Line: 128

Comment:
**`formatUptime` returns "—" for `0` seconds**

`!seconds` is truthy for both `null` and `0`. If a heartbeat arrives with `uptimeSeconds: 0` (pipeline just started), the Uptime column will display "—" instead of "0s". The condition should check strictly for `null`/`undefined`:

```suggestion
  if (seconds == null) return "\u2014";
```

How can I resolve this? If you propose a fix, please make it concise.

- Replace useEffect+setState with useMemo using pipelineQuery.dataUpdatedAt
  as stable timestamp (satisfies both purity and set-state-in-effect rules)
- Fix formatUptime to use == null instead of !seconds so uptimeSeconds: 0
  displays "0s" instead of "—"
@TerrifiedBug TerrifiedBug merged commit 7153995 into main Mar 26, 2026
9 checks passed
@TerrifiedBug TerrifiedBug deleted the ux-improvements branch March 26, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant