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'),
});
const skills = data?? [];
const skills = Array.isArray(data) ? data : [];
// Mutations ------------------------------------------------------------
const createMutation = useMutation({

View File

@ -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

View File

@ -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 <p className="text-muted-foreground">{tc('loading')}</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 }),
});
const contacts = data?? [];
const contacts = Array.isArray(data) ? data : [];
const handleOpenAdd = () => {
setEditingContact(null);
@ -528,7 +528,7 @@ function EscalationPoliciesTab() {
queryFn: () => apiClient<Contact[]>('/api/v1/comm/contacts'),
});
const contacts = contactsData?? [];
const contacts = Array.isArray(contactsData) ? contactsData : [];
const createMutation = useMutation({
mutationFn: (body: Omit<EscalationPolicy, 'id'>) =>
@ -551,7 +551,7 @@ function EscalationPoliciesTab() {
onSuccess: () => queryClient.invalidateQueries({ queryKey: queryKeys.escalationPolicies.all }),
});
const policies = data?? [];
const policies = Array.isArray(data) ? data : [];
return (
<div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -342,7 +342,7 @@ export default function RolesPage() {
queryFn: () => apiClient<RolesResponse>('/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<PermissionsListResponse>('/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({

View File

@ -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({

View File

@ -372,7 +372,7 @@ export default function ClustersPage() {
queryFn: () => apiClient<ClustersResponse>('/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({

View File

@ -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(() => {

View File

@ -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),

View File

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

View File

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