Skip to content

feat: Fix Web UI re-rendering and scroll position loss#114

Merged
Dumbris merged 1 commit into
mainfrom
fix/web-ui-smooth-rendering
Oct 31, 2025
Merged

feat: Fix Web UI re-rendering and scroll position loss#114
Dumbris merged 1 commit into
mainfrom
fix/web-ui-smooth-rendering

Conversation

@Dumbris

@Dumbris Dumbris commented Oct 31, 2025

Copy link
Copy Markdown
Member

Summary

This PR fixes the jarring Web UI experience where pages lose scroll position and flash/jump during updates. The issue was caused by SSE events triggering full array replacements in the store, which caused Vue to destroy and recreate all components.

Problem

  • Scroll position loss: Every SSE update scrolled the page back to top
  • Full re-renders: All server cards were destroyed and recreated on any data change
  • Flickering content: Loading states and component recreation caused visual jumps
  • Affected views: Servers, Secrets, Tool Calls, and Repositories all had similar issues

Solution

1. Smart Data Merging in Servers Store

  • Implemented mergeServers() function that updates server objects in-place
  • Preserves object references to prevent unnecessary Vue component re-renders
  • Added silent background refresh mode (fetchServers(true)) to skip loading states during SSE updates
  • Uses Object.assign() for efficient property updates

Key changes in stores/servers.ts:

function mergeServers(existing: Server[], incoming: Server[]): Server[] {
  const existingMap = new Map(existing.map(s => [s.name, s]))
  const result: Server[] = []

  incoming.forEach(incomingServer => {
    const existingServer = existingMap.get(incomingServer.name)
    if (existingServer) {
      // Update in-place - preserves object reference
      Object.assign(existingServer, incomingServer)
      result.push(existingServer)
    } else {
      // Add new server
      result.push(incomingServer)
    }
  })

  return result.sort((a, b) => a.name.localeCompare(b.name))
}

2. Vue Best Practices

  • TransitionGroup: Added to Servers, Secrets, and Repositories views for smooth animations
  • v-memo: Applied to ServerCard component to skip re-renders when props haven't changed
  • Stable keys: All list items use unique, stable keys (server.name, secret_ref.name, call.id)
  • Background updates: No more loading spinners during SSE data refreshes

3. Smooth CSS Transitions

Added professional enter/leave/move animations:

  • Server cards: Fade + translate Y with scale
  • Secrets: Fade + translate X
  • Repositories: Fade + scale
  • All using cubic-bezier timing functions for smooth motion

4. Files Modified

  • src/stores/servers.ts - Smart merging + silent refresh mode
  • src/views/Servers.vue - TransitionGroup + v-memo
  • src/views/Secrets.vue - TransitionGroup with unique keys
  • src/views/ToolCalls.vue - Stable keys for preserved expanded state
  • src/views/Repositories.vue - TransitionGroup for search results
  • src/assets/main.css - Smooth transition styles

Benefits

  • Scroll position maintained during SSE updates
  • Individual cards update without full page re-render
  • Smooth animations when servers are added/removed
  • No more flickering or jumping content
  • Better performance with large server lists (100+ servers)
  • Professional UX with polished transitions

Testing

  • Frontend builds successfully without errors
  • All modified Vue components use correct TransitionGroup syntax
  • CSS transitions follow Vue animation naming conventions
  • TypeScript compilation passes
  • Smart merging preserves object references

Visual Improvements

Before:

  • Scroll jumps to top on every SSE event
  • All cards flash/flicker during updates
  • Loading spinner appears for background refreshes
  • Jarring addition/removal of servers

After:

  • Scroll position stays exactly where user left it
  • Only changed cards update (smooth property transitions)
  • Background updates are silent and seamless
  • Smooth fade/scale animations for add/remove

Implementation Notes

The core insight was to stop replacing arrays and instead update objects in-place. Vue's reactivity system can detect property changes on existing objects without destroying components, as long as we preserve the object references.

The v-memo directive ensures Vue only re-renders ServerCard when specific props actually change, not just when the parent re-renders.

TransitionGroup provides smooth animations during list changes, making the UI feel polished and professional.

🤖 Generated with Claude Code

**Problem**:
- SSE events triggered full page re-renders, causing scroll position loss
- All server cards were destroyed and recreated on any data update
- Similar issues across Servers, Secrets, Tool Calls, and Repositories views
- Jarring UX with flickering and jumping content

**Solution**:

1. **Smart Data Merging in Servers Store**:
   - Implemented `mergeServers()` function to update server objects in-place
   - Preserves object references to prevent unnecessary component re-renders
   - Added silent background refresh mode to avoid loading states during SSE updates
   - Uses Object.assign for efficient property updates

2. **Vue Best Practices**:
   - Added `TransitionGroup` components for smooth list animations
   - Implemented `v-memo` directive on ServerCard to skip re-renders when props unchanged
   - Used stable, unique keys for all list items (server.name, secret_ref.name, call.id)
   - Background data updates no longer show loading spinners

3. **Smooth CSS Transitions**:
   - Added enter/leave/move animations for all list components
   - Fade and scale effects for adding/removing items
   - Cubic bezier timing functions for smooth, professional animations

4. **Views Updated**:
   - Servers.vue: TransitionGroup with v-memo optimization
   - Secrets.vue: TransitionGroup for secrets and env vars
   - ToolCalls.vue: Stable keys with preserved expanded state
   - Repositories.vue: TransitionGroup for search results

**Benefits**:
- ✅ Scroll position maintained during SSE updates
- ✅ Individual cards update without full page re-render
- ✅ Smooth animations when servers added/removed
- ✅ Reduced flickering and jumping content
- ✅ Better performance with large server lists
- ✅ Improved overall UX

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📦 Build Artifacts for PR #114

Version: v0.9.21-dev-0a21aed-pr114
Latest tag: v0.9.21

Available Artifacts

  • archive-darwin-amd64 (17 MB)
  • installer-dmg-darwin-amd64 (19 MB)
  • archive-linux-arm64 (8.6 MB)
  • archive-linux-amd64 (9.4 MB)
  • archive-windows-arm64 (16 MB)
  • archive-windows-amd64 (17 MB)
  • archive-darwin-arm64 (16 MB)
  • installer-dmg-darwin-arm64 (18 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 18980085294 --repo smart-mcp-proxy/mcpproxy-go

# Or download a specific artifact:
gh run download 18980085294 --name dmg-darwin-arm64

Note: Artifacts expire in 14 days.

@Dumbris Dumbris merged commit 034e6b4 into main Oct 31, 2025
36 checks passed
@Dumbris Dumbris deleted the fix/web-ui-smooth-rendering branch October 31, 2025 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant