From 513e575f1f2e0c193f4caa6f118c3fc1d3c7431e Mon Sep 17 00:00:00 2001 From: hailin Date: Sat, 7 Mar 2026 08:37:11 -0800 Subject: [PATCH] fix(web-admin): guard all data?? [] against non-array API responses Co-Authored-By: Claude Sonnet 4.6 --- .../src/app/(admin)/agent-config/skills/page.tsx | 2 +- it0-web-admin/src/app/(admin)/audit/replay/page.tsx | 2 +- it0-web-admin/src/app/(admin)/communication/page.tsx | 8 ++++---- .../src/app/(admin)/monitoring/alert-rules/[id]/page.tsx | 2 +- .../src/app/(admin)/monitoring/alert-rules/page.tsx | 2 +- .../src/app/(admin)/monitoring/health-checks/page.tsx | 2 +- it0-web-admin/src/app/(admin)/monitoring/metrics/page.tsx | 2 +- .../src/app/(admin)/security/credentials/page.tsx | 2 +- .../src/app/(admin)/security/risk-rules/page.tsx | 2 +- it0-web-admin/src/app/(admin)/security/roles/page.tsx | 6 +++--- it0-web-admin/src/app/(admin)/servers/[id]/page.tsx | 4 ++-- it0-web-admin/src/app/(admin)/servers/clusters/page.tsx | 4 ++-- it0-web-admin/src/app/(admin)/sessions/[id]/page.tsx | 4 ++-- it0-web-admin/src/app/(admin)/tenants/[id]/page.tsx | 2 +- it0-web-admin/src/app/(admin)/terminal/page.tsx | 2 +- it0-web-admin/src/app/(admin)/users/[id]/page.tsx | 2 +- 16 files changed, 24 insertions(+), 24 deletions(-) diff --git a/it0-web-admin/src/app/(admin)/agent-config/skills/page.tsx b/it0-web-admin/src/app/(admin)/agent-config/skills/page.tsx index 9c3398f..6157ca8 100644 --- a/it0-web-admin/src/app/(admin)/agent-config/skills/page.tsx +++ b/it0-web-admin/src/app/(admin)/agent-config/skills/page.tsx @@ -320,7 +320,7 @@ export default function SkillsPage() { queryFn: () => apiClient('/api/v1/agent/skills'), }); - const skills = data?? []; + const skills = Array.isArray(data) ? data : []; // Mutations ------------------------------------------------------------ const createMutation = useMutation({ diff --git a/it0-web-admin/src/app/(admin)/audit/replay/page.tsx b/it0-web-admin/src/app/(admin)/audit/replay/page.tsx index 009a55a..a422598 100644 --- a/it0-web-admin/src/app/(admin)/audit/replay/page.tsx +++ b/it0-web-admin/src/app/(admin)/audit/replay/page.tsx @@ -204,7 +204,7 @@ export default function SessionReplayPage() { enabled: !!selectedSessionId, }); - const events = eventsData?? []; + const events = Array.isArray(eventsData) ? eventsData : []; const selectedSession = sessions.find((s) => s.id === selectedSessionId) ?? null; // Reset playback when selecting a new session diff --git a/it0-web-admin/src/app/(admin)/communication/page.tsx b/it0-web-admin/src/app/(admin)/communication/page.tsx index cb76fff..cc12a7e 100644 --- a/it0-web-admin/src/app/(admin)/communication/page.tsx +++ b/it0-web-admin/src/app/(admin)/communication/page.tsx @@ -173,7 +173,7 @@ function ChannelsTab() { onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.channels.all }), }); - const channels = data?? []; + const channels = Array.isArray(data) ? data : []; if (isLoading) return

{tc('loading')}

; if (error) return

{tc('error')}: {(error as Error).message}

; @@ -315,7 +315,7 @@ function ContactsTab() { onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.contacts.all }), }); - const contacts = data?? []; + const contacts = Array.isArray(data) ? data : []; const handleOpenAdd = () => { setEditingContact(null); @@ -528,7 +528,7 @@ function EscalationPoliciesTab() { queryFn: () => apiClient('/api/v1/comm/contacts'), }); - const contacts = contactsData?? []; + const contacts = Array.isArray(contactsData) ? contactsData : []; const createMutation = useMutation({ mutationFn: (body: Omit) => @@ -551,7 +551,7 @@ function EscalationPoliciesTab() { onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.escalationPolicies.all }), }); - const policies = data?? []; + const policies = Array.isArray(data) ? data : []; return (
diff --git a/it0-web-admin/src/app/(admin)/monitoring/alert-rules/[id]/page.tsx b/it0-web-admin/src/app/(admin)/monitoring/alert-rules/[id]/page.tsx index f480d3f..8fc7a1b 100644 --- a/it0-web-admin/src/app/(admin)/monitoring/alert-rules/[id]/page.tsx +++ b/it0-web-admin/src/app/(admin)/monitoring/alert-rules/[id]/page.tsx @@ -290,7 +290,7 @@ export default function AlertRuleDetailPage() { enabled: !!id, }); - const alertEvents = eventsData?? []; + const alertEvents = Array.isArray(eventsData) ? eventsData : []; // Mutations ------------------------------------------------------------ const updateMutation = useMutation({ diff --git a/it0-web-admin/src/app/(admin)/monitoring/alert-rules/page.tsx b/it0-web-admin/src/app/(admin)/monitoring/alert-rules/page.tsx index 1049a54..439c66f 100644 --- a/it0-web-admin/src/app/(admin)/monitoring/alert-rules/page.tsx +++ b/it0-web-admin/src/app/(admin)/monitoring/alert-rules/page.tsx @@ -459,7 +459,7 @@ export default function AlertRulesPage() { queryFn: () => apiClient('/api/v1/monitor/alerts/rules'), }); - const rules = data?? []; + const rules = Array.isArray(data) ? data : []; // Mutations ------------------------------------------------------------ const createMutation = useMutation({ diff --git a/it0-web-admin/src/app/(admin)/monitoring/health-checks/page.tsx b/it0-web-admin/src/app/(admin)/monitoring/health-checks/page.tsx index ae29191..7805814 100644 --- a/it0-web-admin/src/app/(admin)/monitoring/health-checks/page.tsx +++ b/it0-web-admin/src/app/(admin)/monitoring/health-checks/page.tsx @@ -177,7 +177,7 @@ export default function HealthChecksPage() { queryFn: () => apiClient('/api/v1/monitor/health-checks'), }); - const allChecks = data?? []; + const allChecks = Array.isArray(data) ? data : []; const filteredChecks = useMemo(() => { if (statusFilter === 'all') return allChecks; diff --git a/it0-web-admin/src/app/(admin)/monitoring/metrics/page.tsx b/it0-web-admin/src/app/(admin)/monitoring/metrics/page.tsx index 243ea6a..9c2b519 100644 --- a/it0-web-admin/src/app/(admin)/monitoring/metrics/page.tsx +++ b/it0-web-admin/src/app/(admin)/monitoring/metrics/page.tsx @@ -250,7 +250,7 @@ export default function MetricsPage() { queryFn: () => apiClient('/api/v1/monitor/metrics/servers'), }); - const allServers = serversData?? []; + const allServers = Array.isArray(serversData) ? serversData : []; // Auto-refresh --------------------------------------------------------- useEffect(() => { diff --git a/it0-web-admin/src/app/(admin)/security/credentials/page.tsx b/it0-web-admin/src/app/(admin)/security/credentials/page.tsx index f9bc32d..3be8dcb 100644 --- a/it0-web-admin/src/app/(admin)/security/credentials/page.tsx +++ b/it0-web-admin/src/app/(admin)/security/credentials/page.tsx @@ -468,7 +468,7 @@ export default function CredentialsPage() { apiClient('/api/v1/inventory/credentials'), }); - const credentials = data?? []; + const credentials = Array.isArray(data) ? data : []; // Mutations ------------------------------------------------------------ const createMutation = useMutation({ diff --git a/it0-web-admin/src/app/(admin)/security/risk-rules/page.tsx b/it0-web-admin/src/app/(admin)/security/risk-rules/page.tsx index 17b03c8..6a909fd 100644 --- a/it0-web-admin/src/app/(admin)/security/risk-rules/page.tsx +++ b/it0-web-admin/src/app/(admin)/security/risk-rules/page.tsx @@ -412,7 +412,7 @@ export default function RiskRulesPage() { queryFn: () => apiClient('/api/v1/agent/risk-rules'), }); - const rules = rulesData?? []; + const rules = Array.isArray(rulesData) ? rulesData : []; // Queries - permissions matrix ----------------------------------------- const { isLoading: matrixLoading } = useQuery({ diff --git a/it0-web-admin/src/app/(admin)/security/roles/page.tsx b/it0-web-admin/src/app/(admin)/security/roles/page.tsx index 2a8577c..1fa80ca 100644 --- a/it0-web-admin/src/app/(admin)/security/roles/page.tsx +++ b/it0-web-admin/src/app/(admin)/security/roles/page.tsx @@ -342,7 +342,7 @@ export default function RolesPage() { queryFn: () => apiClient('/api/v1/auth/roles'), }); - const roles = rolesData?? []; + const roles = Array.isArray(rolesData) ? rolesData : []; // Fetch all permissions (for checkbox lists) const { data: allPermsData } = useQuery({ @@ -350,7 +350,7 @@ export default function RolesPage() { queryFn: () => apiClient('/api/v1/auth/permissions'), }); - const allPermissions = allPermsData?? []; + const allPermissions = Array.isArray(allPermsData) ? allPermsData : []; // Fetch permissions for expanded role const { data: rolePermsData, isLoading: rolePermsLoading } = useQuery({ @@ -362,7 +362,7 @@ export default function RolesPage() { enabled: !!expandedRoleId, }); - const rolePermissions = rolePermsData?? []; + const rolePermissions = Array.isArray(rolePermsData) ? rolePermsData : []; // Mutations ------------------------------------------------------------ const createMutation = useMutation({ diff --git a/it0-web-admin/src/app/(admin)/servers/[id]/page.tsx b/it0-web-admin/src/app/(admin)/servers/[id]/page.tsx index 1c381fa..60409b1 100644 --- a/it0-web-admin/src/app/(admin)/servers/[id]/page.tsx +++ b/it0-web-admin/src/app/(admin)/servers/[id]/page.tsx @@ -284,8 +284,8 @@ export default function ServerDetailPage() { enabled: !!id, }); - const healthChecks = healthData?? []; - const recentCommands = commandsData?? []; + const healthChecks = Array.isArray(healthData) ? healthData : []; + const recentCommands = Array.isArray(commandsData) ? commandsData : []; // Mutations ------------------------------------------------------------ const updateMutation = useMutation({ diff --git a/it0-web-admin/src/app/(admin)/servers/clusters/page.tsx b/it0-web-admin/src/app/(admin)/servers/clusters/page.tsx index 2cffd19..5b3b35f 100644 --- a/it0-web-admin/src/app/(admin)/servers/clusters/page.tsx +++ b/it0-web-admin/src/app/(admin)/servers/clusters/page.tsx @@ -372,7 +372,7 @@ export default function ClustersPage() { queryFn: () => apiClient('/api/v1/inventory/clusters'), }); - const clusters = data?? []; + const clusters = Array.isArray(data) ? data : []; // Fetch servers for the dialog server selection const { data: serversData, isLoading: serversLoading } = useQuery({ @@ -381,7 +381,7 @@ export default function ClustersPage() { enabled: dialogOpen, }); - const servers = serversData?? []; + const servers = Array.isArray(serversData) ? serversData : []; // Mutations ------------------------------------------------------------ const createMutation = useMutation({ diff --git a/it0-web-admin/src/app/(admin)/sessions/[id]/page.tsx b/it0-web-admin/src/app/(admin)/sessions/[id]/page.tsx index d7d93d1..670b094 100644 --- a/it0-web-admin/src/app/(admin)/sessions/[id]/page.tsx +++ b/it0-web-admin/src/app/(admin)/sessions/[id]/page.tsx @@ -276,8 +276,8 @@ export default function SessionDetailPage() { enabled: !!id, }); - const events = eventsData?? []; - const tasks = tasksData?? []; + const events = Array.isArray(eventsData) ? eventsData : []; + const tasks = Array.isArray(tasksData) ? tasksData : []; // Auto-scroll to bottom when new events arrive useEffect(() => { diff --git a/it0-web-admin/src/app/(admin)/tenants/[id]/page.tsx b/it0-web-admin/src/app/(admin)/tenants/[id]/page.tsx index eaed148..f319c98 100644 --- a/it0-web-admin/src/app/(admin)/tenants/[id]/page.tsx +++ b/it0-web-admin/src/app/(admin)/tenants/[id]/page.tsx @@ -254,7 +254,7 @@ export default function TenantDetailPage() { enabled: !!id, }); - const members = membersData?? []; + const members = Array.isArray(membersData) ? membersData : []; const { data: invites = [] } = useQuery({ queryKey: queryKeys.tenants.invites(id), diff --git a/it0-web-admin/src/app/(admin)/terminal/page.tsx b/it0-web-admin/src/app/(admin)/terminal/page.tsx index 9fca350..aba7345 100644 --- a/it0-web-admin/src/app/(admin)/terminal/page.tsx +++ b/it0-web-admin/src/app/(admin)/terminal/page.tsx @@ -133,7 +133,7 @@ export default function TerminalPage() { queryFn: () => apiClient('/api/v1/inventory/servers'), }); - const servers = serversData?? []; + const servers = Array.isArray(serversData) ? serversData : []; // ---- Auto-scroll ---- useEffect(() => { diff --git a/it0-web-admin/src/app/(admin)/users/[id]/page.tsx b/it0-web-admin/src/app/(admin)/users/[id]/page.tsx index 791c81e..0bb5bb8 100644 --- a/it0-web-admin/src/app/(admin)/users/[id]/page.tsx +++ b/it0-web-admin/src/app/(admin)/users/[id]/page.tsx @@ -358,7 +358,7 @@ export default function UserDetailPage() { enabled: !!id, }); - const activityLog = activityData?? []; + const activityLog = Array.isArray(activityData) ? activityData : []; // Mutations ------------------------------------------------------------ const updateMutation = useMutation({