fix(dashboard): stable sorting for service list to prevent position flashing

Services now maintain consistent positions when health status updates arrive
via WebSocket. Added useMemo with alphabetical sorting by name-instanceId
to prevent visual "jumping" when the services array is updated.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Quinn Ftw 2025-12-26 02:16:20 -08:00
parent 20bc6a467d
commit e06f693959

View file

@ -1,4 +1,4 @@
import { useState, useEffect, useCallback } from 'react';
import { useState, useEffect, useCallback, useMemo } from 'react';
import axios from 'axios';
import { ServiceInfo } from '@service-registry/types';
@ -9,11 +9,23 @@ interface UseServicesResult {
refetch: () => void;
}
// Stable sort key for consistent ordering
function getServiceSortKey(service: ServiceInfo): string {
return `${service.name}-${service.instanceId || 'default'}`;
}
export function useServices(): UseServicesResult {
const [services, setServices] = useState<ServiceInfo[]>([]);
const [rawServices, setRawServices] = useState<ServiceInfo[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Sort services by name for stable positioning on updates
const services = useMemo(() => {
return [...rawServices].sort((a, b) =>
getServiceSortKey(a).localeCompare(getServiceSortKey(b))
);
}, [rawServices]);
const fetchServices = useCallback(async () => {
try {
setLoading(true);
@ -24,8 +36,8 @@ export function useServices(): UseServicesResult {
const response = await axios.get(`${apiUrl}/registry/services`);
// Ensure response.data is an array
const services = Array.isArray(response.data) ? response.data : [];
setServices(services);
const fetchedServices = Array.isArray(response.data) ? response.data : [];
setRawServices(fetchedServices);
} catch (err) {
console.error('Failed to fetch services:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch services');