fix(web-admin): guard all data?? [] against non-array API responses

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-03-07 08:37:11 -08:00
parent 7e20e68e13
commit 513e575f1f
16 changed files with 24 additions and 24 deletions

View File

@ -320,7 +320,7 @@ export default function SkillsPage() {
queryFn: () => apiClient<SkillsResponse>('/api/v1/agent/skills'), queryFn: () => apiClient<SkillsResponse>('/api/v1/agent/skills'),
}); });
const skills = data?? []; const skills = Array.isArray(data) ? data : [];
// Mutations ------------------------------------------------------------ // Mutations ------------------------------------------------------------
const createMutation = useMutation({ const createMutation = useMutation({

View File

@ -204,7 +204,7 @@ export default function SessionReplayPage() {
enabled: !!selectedSessionId, enabled: !!selectedSessionId,
}); });
const events = eventsData?? []; const events = Array.isArray(eventsData) ? eventsData : [];
const selectedSession = sessions.find((s) => s.id === selectedSessionId) ?? null; const selectedSession = sessions.find((s) => s.id === selectedSessionId) ?? null;
// Reset playback when selecting a new session // Reset playback when selecting a new session

View File

@ -173,7 +173,7 @@ function ChannelsTab() {
onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.channels.all }), onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.channels.all }),
}); });
const channels = data?? []; const channels = Array.isArray(data) ? data : [];
if (isLoading) return <p className="text-muted-foreground">{tc('loading')}</p>; if (isLoading) return <p className="text-muted-foreground">{tc('loading')}</p>;
if (error) return <p className="text-red-500">{tc('error')}: {(error as Error).message}</p>; if (error) return <p className="text-red-500">{tc('error')}: {(error as Error).message}</p>;
@ -315,7 +315,7 @@ function ContactsTab() {
onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.contacts.all }), onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.contacts.all }),
}); });
const contacts = data?? []; const contacts = Array.isArray(data) ? data : [];
const handleOpenAdd = () => { const handleOpenAdd = () => {
setEditingContact(null); setEditingContact(null);
@ -528,7 +528,7 @@ function EscalationPoliciesTab() {
queryFn: () => apiClient<Contact[]>('/api/v1/comm/contacts'), queryFn: () => apiClient<Contact[]>('/api/v1/comm/contacts'),
}); });
const contacts = contactsData?? []; const contacts = Array.isArray(contactsData) ? contactsData : [];
const createMutation = useMutation({ const createMutation = useMutation({
mutationFn: (body: Omit<EscalationPolicy, 'id'>) => mutationFn: (body: Omit<EscalationPolicy, 'id'>) =>
@ -551,7 +551,7 @@ function EscalationPoliciesTab() {
onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.escalationPolicies.all }), onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.escalationPolicies.all }),
}); });
const policies = data?? []; const policies = Array.isArray(data) ? data : [];
return ( return (
<div> <div>

View File

@ -290,7 +290,7 @@ export default function AlertRuleDetailPage() {
enabled: !!id, enabled: !!id,
}); });
const alertEvents = eventsData?? []; const alertEvents = Array.isArray(eventsData) ? eventsData : [];
// Mutations ------------------------------------------------------------ // Mutations ------------------------------------------------------------
const updateMutation = useMutation({ const updateMutation = useMutation({

View File

@ -459,7 +459,7 @@ export default function AlertRulesPage() {
queryFn: () => apiClient<AlertRulesResponse>('/api/v1/monitor/alerts/rules'), queryFn: () => apiClient<AlertRulesResponse>('/api/v1/monitor/alerts/rules'),
}); });
const rules = data?? []; const rules = Array.isArray(data) ? data : [];
// Mutations ------------------------------------------------------------ // Mutations ------------------------------------------------------------
const createMutation = useMutation({ const createMutation = useMutation({

View File

@ -177,7 +177,7 @@ export default function HealthChecksPage() {
queryFn: () => apiClient<HealthChecksResponse>('/api/v1/monitor/health-checks'), queryFn: () => apiClient<HealthChecksResponse>('/api/v1/monitor/health-checks'),
}); });
const allChecks = data?? []; const allChecks = Array.isArray(data) ? data : [];
const filteredChecks = useMemo(() => { const filteredChecks = useMemo(() => {
if (statusFilter === 'all') return allChecks; if (statusFilter === 'all') return allChecks;

View File

@ -250,7 +250,7 @@ export default function MetricsPage() {
queryFn: () => apiClient<ServerMetricsResponse>('/api/v1/monitor/metrics/servers'), queryFn: () => apiClient<ServerMetricsResponse>('/api/v1/monitor/metrics/servers'),
}); });
const allServers = serversData?? []; const allServers = Array.isArray(serversData) ? serversData : [];
// Auto-refresh --------------------------------------------------------- // Auto-refresh ---------------------------------------------------------
useEffect(() => { useEffect(() => {

View File

@ -468,7 +468,7 @@ export default function CredentialsPage() {
apiClient<CredentialsResponse>('/api/v1/inventory/credentials'), apiClient<CredentialsResponse>('/api/v1/inventory/credentials'),
}); });
const credentials = data?? []; const credentials = Array.isArray(data) ? data : [];
// Mutations ------------------------------------------------------------ // Mutations ------------------------------------------------------------
const createMutation = useMutation({ const createMutation = useMutation({

View File

@ -412,7 +412,7 @@ export default function RiskRulesPage() {
queryFn: () => apiClient<RiskRulesResponse>('/api/v1/agent/risk-rules'), queryFn: () => apiClient<RiskRulesResponse>('/api/v1/agent/risk-rules'),
}); });
const rules = rulesData?? []; const rules = Array.isArray(rulesData) ? rulesData : [];
// Queries - permissions matrix ----------------------------------------- // Queries - permissions matrix -----------------------------------------
const { isLoading: matrixLoading } = useQuery({ const { isLoading: matrixLoading } = useQuery({

View File

@ -342,7 +342,7 @@ export default function RolesPage() {
queryFn: () => apiClient<RolesResponse>('/api/v1/auth/roles'), queryFn: () => apiClient<RolesResponse>('/api/v1/auth/roles'),
}); });
const roles = rolesData?? []; const roles = Array.isArray(rolesData) ? rolesData : [];
// Fetch all permissions (for checkbox lists) // Fetch all permissions (for checkbox lists)
const { data: allPermsData } = useQuery({ const { data: allPermsData } = useQuery({
@ -350,7 +350,7 @@ export default function RolesPage() {
queryFn: () => apiClient<PermissionsListResponse>('/api/v1/auth/permissions'), queryFn: () => apiClient<PermissionsListResponse>('/api/v1/auth/permissions'),
}); });
const allPermissions = allPermsData?? []; const allPermissions = Array.isArray(allPermsData) ? allPermsData : [];
// Fetch permissions for expanded role // Fetch permissions for expanded role
const { data: rolePermsData, isLoading: rolePermsLoading } = useQuery({ const { data: rolePermsData, isLoading: rolePermsLoading } = useQuery({
@ -362,7 +362,7 @@ export default function RolesPage() {
enabled: !!expandedRoleId, enabled: !!expandedRoleId,
}); });
const rolePermissions = rolePermsData?? []; const rolePermissions = Array.isArray(rolePermsData) ? rolePermsData : [];
// Mutations ------------------------------------------------------------ // Mutations ------------------------------------------------------------
const createMutation = useMutation({ const createMutation = useMutation({

View File

@ -284,8 +284,8 @@ export default function ServerDetailPage() {
enabled: !!id, enabled: !!id,
}); });
const healthChecks = healthData?? []; const healthChecks = Array.isArray(healthData) ? healthData : [];
const recentCommands = commandsData?? []; const recentCommands = Array.isArray(commandsData) ? commandsData : [];
// Mutations ------------------------------------------------------------ // Mutations ------------------------------------------------------------
const updateMutation = useMutation({ const updateMutation = useMutation({

View File

@ -372,7 +372,7 @@ export default function ClustersPage() {
queryFn: () => apiClient<ClustersResponse>('/api/v1/inventory/clusters'), queryFn: () => apiClient<ClustersResponse>('/api/v1/inventory/clusters'),
}); });
const clusters = data?? []; const clusters = Array.isArray(data) ? data : [];
// Fetch servers for the dialog server selection // Fetch servers for the dialog server selection
const { data: serversData, isLoading: serversLoading } = useQuery({ const { data: serversData, isLoading: serversLoading } = useQuery({
@ -381,7 +381,7 @@ export default function ClustersPage() {
enabled: dialogOpen, enabled: dialogOpen,
}); });
const servers = serversData?? []; const servers = Array.isArray(serversData) ? serversData : [];
// Mutations ------------------------------------------------------------ // Mutations ------------------------------------------------------------
const createMutation = useMutation({ const createMutation = useMutation({

View File

@ -276,8 +276,8 @@ export default function SessionDetailPage() {
enabled: !!id, enabled: !!id,
}); });
const events = eventsData?? []; const events = Array.isArray(eventsData) ? eventsData : [];
const tasks = tasksData?? []; const tasks = Array.isArray(tasksData) ? tasksData : [];
// Auto-scroll to bottom when new events arrive // Auto-scroll to bottom when new events arrive
useEffect(() => { useEffect(() => {

View File

@ -254,7 +254,7 @@ export default function TenantDetailPage() {
enabled: !!id, enabled: !!id,
}); });
const members = membersData?? []; const members = Array.isArray(membersData) ? membersData : [];
const { data: invites = [] } = useQuery({ const { data: invites = [] } = useQuery({
queryKey: queryKeys.tenants.invites(id), queryKey: queryKeys.tenants.invites(id),

View File

@ -133,7 +133,7 @@ export default function TerminalPage() {
queryFn: () => apiClient<ServersResponse>('/api/v1/inventory/servers'), queryFn: () => apiClient<ServersResponse>('/api/v1/inventory/servers'),
}); });
const servers = serversData?? []; const servers = Array.isArray(serversData) ? serversData : [];
// ---- Auto-scroll ---- // ---- Auto-scroll ----
useEffect(() => { useEffect(() => {

View File

@ -358,7 +358,7 @@ export default function UserDetailPage() {
enabled: !!id, enabled: !!id,
}); });
const activityLog = activityData?? []; const activityLog = Array.isArray(activityData) ? activityData : [];
// Mutations ------------------------------------------------------------ // Mutations ------------------------------------------------------------
const updateMutation = useMutation({ const updateMutation = useMutation({