fix: build errors + move platform info under screenshot card
- Fix premature </div> in Docker.tsx and History.tsx (TS1005/TS1128) - Fix unused imports/vars (noUnusedLocals): AgentStorage, AgentUpdatesModal, ErrorBoundary, useAgentUpdate, useHeartbeat, Dashboard, Updates - Move Platform/Distribution/Architecture under screenshot card in Agents page - Move Top Processes into right stats column
This commit is contained in:
parent
6b28498d84
commit
73c1e0ef21
10 changed files with 77 additions and 75 deletions
|
|
@ -59,7 +59,7 @@ export function AgentStorage({ agentId }: AgentStorageProps) {
|
|||
|
||||
// Fetch storage metrics - NO auto-refresh, data persists until manual refresh
|
||||
// Cache forever (24 hours) to prevent data loss on navigation
|
||||
const { data: storageData, refetch: refetchStorage, error: storageError, isLoading } = useQuery({
|
||||
const { data: storageData, refetch: refetchStorage, error: storageError } = useQuery({
|
||||
queryKey: ['storage-metrics', agentId],
|
||||
queryFn: async () => {
|
||||
clientLogger.debug('Fetching storage metrics for agent:', { agentId });
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { useState } from 'react';
|
||||
import {
|
||||
X,
|
||||
Download,
|
||||
CheckCircle,
|
||||
AlertCircle,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { Component, ErrorInfo, ReactNode } from 'react';
|
||||
import { Component, ErrorInfo, ReactNode } from 'react';
|
||||
|
||||
interface Props {
|
||||
children: ReactNode;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export function useAgentUpdate(): UseAgentUpdateReturn {
|
|||
clientLogger.debug('Update nonce generated', { agentId: agent.id, targetVersion });
|
||||
|
||||
// Step 3: Trigger the actual update
|
||||
const updateResponse = await agentApi.updateAgent(agent.id, {
|
||||
await agentApi.updateAgent(agent.id, {
|
||||
version: targetVersion,
|
||||
platform: `${agent.os_type}-${agent.os_architecture}`,
|
||||
// Include nonce in request for security
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useMemo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export interface HeartbeatStatus {
|
||||
enabled: boolean;
|
||||
|
|
|
|||
|
|
@ -897,6 +897,31 @@ const Agents: React.FC = () => {
|
|||
? <span className="text-red-500">Failed</span>
|
||||
: null}
|
||||
</div>
|
||||
{/* Platform info — under screenshot */}
|
||||
{(() => {
|
||||
const osInfo = parseOSInfo(selectedAgent);
|
||||
return (
|
||||
<div className="mt-2 space-y-1">
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">Platform</p>
|
||||
<p className="text-sm font-medium text-gray-900">{osInfo.platform}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">Distribution</p>
|
||||
<p className="text-sm font-medium text-gray-900">
|
||||
{osInfo.distribution}
|
||||
{osInfo.version && <span className="text-xs text-gray-500 ml-1">({osInfo.version})</span>}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">Architecture</p>
|
||||
<p className="text-sm font-medium text-gray-900">
|
||||
{selectedAgent.os_architecture || selectedAgent.architecture}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
|
@ -904,27 +929,9 @@ const Agents: React.FC = () => {
|
|||
{/* All stats — right column, stacked flush top */}
|
||||
<div className="flex-1 space-y-3 min-w-0">
|
||||
{(() => {
|
||||
const osInfo = parseOSInfo(selectedAgent);
|
||||
const meta = getSystemMetadata(selectedAgent);
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">Platform</p>
|
||||
<p className="text-sm font-medium text-gray-900">{osInfo.platform}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">Distribution</p>
|
||||
<p className="text-sm font-medium text-gray-900">
|
||||
{osInfo.distribution}
|
||||
{osInfo.version && <span className="text-xs text-gray-500 ml-1">({osInfo.version})</span>}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">Architecture</p>
|
||||
<p className="text-sm font-medium text-gray-900">
|
||||
{selectedAgent.os_architecture || selectedAgent.architecture}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500 flex items-center gap-1">
|
||||
<Cpu className="h-3 w-3" /> CPU
|
||||
|
|
@ -976,55 +983,55 @@ const Agents: React.FC = () => {
|
|||
</>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Top Processes — below the split */}
|
||||
<div className="mt-4 pt-4 border-t border-gray-200">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<p className="text-sm font-medium text-gray-900 flex items-center gap-1">
|
||||
<Activity className="h-4 w-4" /> Top Processes
|
||||
</p>
|
||||
<button
|
||||
onClick={() => navigate(`/updates?agent=${selectedAgent.id}`)}
|
||||
className="text-xs text-blue-600 hover:text-blue-800"
|
||||
>
|
||||
See More →
|
||||
</button>
|
||||
{/* Top Processes */}
|
||||
<div className="pt-3 border-t border-gray-200">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<p className="text-xs font-medium text-gray-900 flex items-center gap-1">
|
||||
<Activity className="h-3 w-3" /> Top Processes
|
||||
</p>
|
||||
<button
|
||||
onClick={() => navigate(`/updates?agent=${selectedAgent.id}`)}
|
||||
className="text-[10px] text-blue-600 hover:text-blue-800"
|
||||
>
|
||||
See More →
|
||||
</button>
|
||||
</div>
|
||||
{(() => {
|
||||
const meta = getSystemMetadata(selectedAgent);
|
||||
const topProcesses = selectedAgent.metadata?.top_processes;
|
||||
if (topProcesses && Array.isArray(topProcesses) && topProcesses.length > 0) {
|
||||
return (
|
||||
<table className="w-full text-xs">
|
||||
<thead>
|
||||
<tr className="text-gray-500 border-b border-gray-100">
|
||||
<th className="text-left py-1 font-medium">Name</th>
|
||||
<th className="text-right py-1 font-medium">PID</th>
|
||||
<th className="text-right py-1 font-medium">CPU%</th>
|
||||
<th className="text-right py-1 font-medium">Mem%</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{topProcesses.slice(0, 5).map((proc: any, i: number) => (
|
||||
<tr key={proc.pid || i} className="border-b border-gray-50 last:border-0">
|
||||
<td className="py-1 text-gray-900 font-medium truncate max-w-[160px]">{proc.name}</td>
|
||||
<td className="py-1 text-right text-gray-600">{proc.pid}</td>
|
||||
<td className="py-1 text-right text-gray-600">{proc.cpu != null ? `${proc.cpu.toFixed(1)}%` : '—'}</td>
|
||||
<td className="py-1 text-right text-gray-600">{proc.mem != null ? `${proc.mem.toFixed(1)}%` : '—'}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<p className="text-[10px] text-gray-400 italic">
|
||||
Process details not reported. Count: {meta.processes}
|
||||
</p>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
{(() => {
|
||||
const meta = getSystemMetadata(selectedAgent);
|
||||
const topProcesses = selectedAgent.metadata?.top_processes;
|
||||
if (topProcesses && Array.isArray(topProcesses) && topProcesses.length > 0) {
|
||||
return (
|
||||
<table className="w-full text-xs">
|
||||
<thead>
|
||||
<tr className="text-gray-500 border-b border-gray-100">
|
||||
<th className="text-left py-1 font-medium">Name</th>
|
||||
<th className="text-right py-1 font-medium">PID</th>
|
||||
<th className="text-right py-1 font-medium">CPU%</th>
|
||||
<th className="text-right py-1 font-medium">Mem%</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{topProcesses.slice(0, 5).map((proc: any, i: number) => (
|
||||
<tr key={proc.pid || i} className="border-b border-gray-50 last:border-0">
|
||||
<td className="py-1 text-gray-900 font-medium truncate max-w-[160px]">{proc.name}</td>
|
||||
<td className="py-1 text-right text-gray-600">{proc.pid}</td>
|
||||
<td className="py-1 text-right text-gray-600">{proc.cpu != null ? `${proc.cpu.toFixed(1)}%` : '—'}</td>
|
||||
<td className="py-1 text-right text-gray-600">{proc.mem != null ? `${proc.mem.toFixed(1)}%` : '—'}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<p className="text-xs text-gray-400 italic">
|
||||
Process details not reported by this agent. Showing count: {meta.processes}
|
||||
</p>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ const Dashboard: React.FC = () => {
|
|||
<div
|
||||
className={`h-2 rounded-full ${severity.color}`}
|
||||
style={{
|
||||
width: `${stats.pending_updates > 0 ? (severity.value / stats.pending_updates) * 100 : 0}%`
|
||||
width: `${(stats?.pending_updates ?? 0) > 0 ? (severity.value / (stats?.pending_updates ?? 1)) * 100 : 0}%`
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -173,7 +173,6 @@ const Docker: React.FC = () => {
|
|||
icon={<AlertTriangle className="h-8 w-8 text-red-400" />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Search + pills */}
|
||||
<div className="mb-6">
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ const HistoryPage: React.FC = () => {
|
|||
<p className="text-gray-600">
|
||||
Command history, package events, system activity, and client errors across all agents
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Filter bar — Novell-style dense row */}
|
||||
{showFilters && (
|
||||
|
|
|
|||
|
|
@ -160,8 +160,6 @@ const Updates: React.FC = () => {
|
|||
return true;
|
||||
});
|
||||
const packageTotalPages = Math.ceil(packageTotal / pageSize);
|
||||
const packageHasNext = currentPage < packageTotalPages;
|
||||
const packageHasPrev = currentPage > 1;
|
||||
const packageTypes = [...new Set(packages.map((p) => p.package_type))];
|
||||
|
||||
// Handle update actions
|
||||
|
|
|
|||
Loading…
Reference in a new issue