Skip to content

feat: UI improvements — analytics metrics, discard changes, SSO hints#66

Merged
TerrifiedBug merged 32 commits intomainfrom
feat/ui-improvements
Mar 8, 2026
Merged

feat: UI improvements — analytics metrics, discard changes, SSO hints#66
TerrifiedBug merged 32 commits intomainfrom
feat/ui-improvements

Conversation

@TerrifiedBug
Copy link
Copy Markdown
Owner

Summary

  • Analytics reduction metric fix: Replace misleading single "Reduction" KPI (bytes-based, inflated by gzip) with two cards: "Events Reduced" (event-based, clamped at 0%) and "Bytes Saved" (relabeled, with tooltip). Added sortable "Events Reduced" column to per-pipeline table.
  • Discard unsaved pipeline changes: Store node/edge snapshots in PipelineVersion on deploy. New discardChanges mutation restores pipeline to last deployed state. Discard button in toolbar with confirmation dialog. Both deployAgent and createVersion paths store snapshots. Rollback also restores nodes/edges and is now transactional.
  • SSO hint in Add Member dialog: Conditional info alert when SCIM or OIDC group sync is enabled, telling admins that SSO users are managed by the identity provider.
  • Earlier commits on branch: Layout save cache invalidation, service accounts tab, dashboard/fleet/profile UI polish, stale closure fixes.

Test plan

  • Analytics page shows "Events Reduced" and "Bytes Saved" cards with correct color thresholds (green >50%, amber >10%, muted ≤10%)
  • Per-pipeline table has sortable "Events Reduced" and renamed "Bytes Saved" columns
  • Deploy a pipeline, make edits, save without deploying — "Discard" button appears in toolbar
  • Clicking Discard shows confirmation dialog; confirming reverts to deployed state
  • Discard fails gracefully on pipelines deployed before this change (no snapshot)
  • Rollback from version history also restores node positions and edges
  • With SCIM or OIDC group sync enabled, Add Member card shows SSO info hint
  • With neither enabled, no hint is shown

- Fleet: collapse node labels into a compact count button with popover
- Fleet: replace native confirm() with styled ConfirmDialog for maintenance mode
- Dashboard: add drag, resize, and reorder support for custom view panels using react-grid-layout
- Pipelines: center the SLI health dot in the Health column
- Profile: display user role and super admin status in personal info
…types stub

- Add queryClient.invalidateQueries for dashboard.listViews on
  updateView mutation success so remounting loads the persisted layout
- Remove @types/react-grid-layout (deprecated stub, v2 ships own types)
- Use a ref (filtersRef) to hold latest filter values so the debounce
  timer reads current pipelineIds/nodeIds when it fires, not the values
  captured at scheduling time
- Clear pending debounce timer on component unmount to prevent stale
  mutations after navigation
- Move filtersRef.current assignment into a useEffect to satisfy
  react-hooks/refs lint rule (no ref writes during render)
- Wrap panels cast in useMemo to stabilize the dependency for
  downstream useMemo hooks
Replace the standalone "Service Accounts & API Keys" button above the
settings tabs with an inline "API Keys" tab visible to team admins.
Extract ServiceAccountsSettings as a named export so it can be rendered
both as a tab and as the existing standalone page route.
Temporary debug logs at each decision point in the reconciliation chain:
- auth.ts: log final group list and scimEnabled flag
- group-mappings.ts: log loaded mappings, desired state, existing members
Replace raw console.log debug statements with a shared debugLog()
helper that only outputs when VF_LOG_LEVEL or LOG_LEVEL is set to
debug or trace. Applies to OIDC group sync, SCIM reconciliation,
agent enrollment, and system Vector process logs. Operational and
error logs remain unchanged.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 8, 2026

Greptile Summary

This PR delivers three feature areas: a refactored analytics KPI section (replacing the misleading byte-based "Reduction" card with separate "Events Reduced" and "Bytes Saved" cards), a "Discard unsaved changes" workflow that restores a deployed pipeline to its last deployed snapshot, and an SSO hint in the Add Member dialog. The discard path is well-implemented — markClean() is called before query invalidation, correctly bypassing the isDirty guard in loadGraph.

Key issues found:

  • Rollback canvas not refreshed after version history rollbackrollbackMutation.onSuccess in VersionHistoryDialog only invalidates pipeline.versions; it never invalidates pipeline.get or calls markClean(). Every rollback via the Version History dialog leaves the canvas displaying the pre-rollback graph, while the DB has already been updated. This is the same class of issue that was fixed for discardChanges.
  • Rollback is only partially atomic — The PR description claims rollback is "now transactional," but createVersion (which writes the new PipelineVersion record and updates pipeline.deployedAt) runs outside the $transaction block that restores nodes/edges. A transient DB failure between those two steps leaves the pipeline's live state and its version history permanently out of sync.

Confidence Score: 3/5

  • Safe to merge analytics and SSO hint changes; the discard-changes flow is correct, but the rollback path has two bugs that will affect users.
  • The analytics refactor and SSO hint are straightforward and low-risk. The discard-changes feature is well-implemented. However, the rollback path has two issues that will manifest in normal usage: the canvas isn't refreshed after a rollback (always reproducible), and the rollback isn't fully atomic (version history can become permanently inconsistent on DB error).
  • src/components/pipeline/version-history-dialog.tsx and src/server/services/pipeline-version.ts need attention before merging.

Important Files Changed

Filename Overview
src/server/services/pipeline-version.ts Added snapshot columns to PipelineVersion and a new rollback path that restores nodes/edges from snapshots. Critical issue: createVersion is called outside the $transaction, so if it fails the pipeline's live state and version history are permanently inconsistent.
src/components/pipeline/version-history-dialog.tsx Rollback mutation's onSuccess handler only invalidates the versions query; it never calls markClean() or invalidates pipeline.get, so the canvas displays stale pre-rollback nodes/edges after every rollback.
src/server/routers/pipeline.ts New discardChanges mutation correctly validates pipeline state, fetches the latest snapshot, and restores nodes/edges inside a transaction. Uses EDITOR access + withAudit. Snapshot stored with encrypted configs as found in DB, consistent with existing read path.
src/server/services/deploy-agent.ts Now captures nodesSnapshot/edgesSnapshot (encrypted DB configs) before calling createVersion, enabling discard/rollback of visual layout. No functional regressions found.
src/app/(dashboard)/pipelines/[id]/page.tsx New discardMutation correctly calls markClean() before invalidating pipeline.get, so the isDirty guard in loadGraph is cleared and the canvas reloads with the restored state. Discard dialog and toolbar integration look correct.
src/app/(dashboard)/analytics/page.tsx Replaces single byte-based Reduction KPI with Events Reduced (event-based, clamped ≥0%) and Bytes Saved (relabeled with tooltip). Adds sortable eventsReduced column. Logic is correct; color thresholds match the described spec.
prisma/migrations/20260308000000_add_pipeline_version_snapshots/migration.sql Adds nullable nodesSnapshot/edgesSnapshot JSONB columns to PipelineVersion. Backward-compatible (nullable), no breaking change to existing rows.
src/components/flow/flow-toolbar.tsx Adds Discard button alongside the Deploy/Undeploy buttons when hasChanges is true. Correctly gated by onDiscardChanges prop and the hasConfigChanges flag. No issues found.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant FE as Pipeline Editor
    participant QC as React Query Cache
    participant API as tRPC / Server
    participant DB as PostgreSQL

    Note over U,DB: Deploy path (stores snapshot)
    U->>FE: Click Deploy
    FE->>API: deploy.agent(pipelineId)
    API->>DB: createVersion(yaml, nodesSnapshot, edgesSnapshot)
    DB-->>API: PipelineVersion (with snapshot)
    API-->>FE: { versionId, versionNumber }

    Note over U,DB: Discard Changes path (fixed in this PR)
    U->>FE: Click Discard
    FE->>API: pipeline.discardChanges(pipelineId)
    API->>DB: $transaction: restore nodes/edges from snapshot
    DB-->>API: OK
    API-->>FE: { discarded: true }
    FE->>FE: markClean()
    FE->>QC: invalidate pipeline.get
    QC->>API: pipeline.get(pipelineId)
    API-->>QC: restored nodes/edges
    QC-->>FE: loadGraph() (isDirty=false → guard bypassed)

    Note over U,DB: Rollback path (bug: missing invalidation)
    U->>FE: Open Version History → Rollback to vN
    FE->>API: pipeline.rollback(pipelineId, versionId)
    API->>DB: $transaction: restore nodes/edges from snapshot
    DB-->>API: OK (transaction committed)
    API->>DB: createVersion(...) ← OUTSIDE transaction
    DB-->>API: new PipelineVersion
    API-->>FE: newVersion
    FE->>QC: invalidate pipeline.versions only
    Note over FE,QC: pipeline.get NOT invalidated<br/>markClean() NOT called<br/>Canvas shows stale pre-rollback state
Loading

Comments Outside Diff (1)

  1. src/components/pipeline/version-history-dialog.tsx, line 73-86 (link)

    Rollback doesn't refresh the pipeline editor canvas

    rollbackMutation.onSuccess only invalidates trpc.pipeline.versions but never invalidates trpc.pipeline.get. After a successful rollback the DB correctly holds the restored nodes/edges, but pipeline.get remains cached with the pre-rollback graph and the canvas never re-renders.

    There's a second compounding issue: markClean() is never called here. The useEffect on the pipeline page that invokes loadGraph is guarded by if (hasLoadedRef.current && useFlowStore.getState().isDirty) return;. If the user had unsaved edits open at rollback time, isDirty stays true even after pipeline.get is refetched, so loadGraph is blocked regardless.

    The fix mirrors what discardMutation.onSuccess does — call markClean() first, then invalidate both pipeline.versions and pipeline.get. Without this, the toast reports a successful rollback but the canvas continues displaying the pre-rollback graph.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/components/pipeline/version-history-dialog.tsx
    Line: 73-86
    
    Comment:
    **Rollback doesn't refresh the pipeline editor canvas**
    
    `rollbackMutation.onSuccess` only invalidates `trpc.pipeline.versions` but never invalidates `trpc.pipeline.get`. After a successful rollback the DB correctly holds the restored nodes/edges, but `pipeline.get` remains cached with the pre-rollback graph and the canvas never re-renders.
    
    There's a second compounding issue: `markClean()` is never called here. The `useEffect` on the pipeline page that invokes `loadGraph` is guarded by `if (hasLoadedRef.current && useFlowStore.getState().isDirty) return;`. If the user had unsaved edits open at rollback time, `isDirty` stays `true` even after `pipeline.get` is refetched, so `loadGraph` is blocked regardless.
    
    The fix mirrors what `discardMutation.onSuccess` does — call `markClean()` first, then invalidate both `pipeline.versions` **and** `pipeline.get`. Without this, the toast reports a successful rollback but the canvas continues displaying the pre-rollback graph.
    
    How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: d0d323f

…ogging

Skip member removal in Groups PUT when incoming member list is empty but
current members exist — prevents pocket-id's intermediate sync states from
wiping team memberships. Add debugLog calls across all SCIM User and Group
endpoints gated behind VF_LOG_LEVEL=debug.
Without this, the isDirty guard in the loadGraph useEffect prevents
the editor from reloading the restored state after discard.
@TerrifiedBug
Copy link
Copy Markdown
Owner Author

@greptile review

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
TerrifiedBug and others added 3 commits March 8, 2026 13:48
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@TerrifiedBug TerrifiedBug merged commit 152d244 into main Mar 8, 2026
9 checks passed
@TerrifiedBug TerrifiedBug deleted the feat/ui-improvements branch March 8, 2026 13:55
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.

2 participants