feat: bump to v0.1.23 with security metrics and UI improvements
- Bump agent and server versions to 0.1.23 - Implement security metrics collection (bound agents, command processing, version compliance) - Add dismiss button for timed out commands in agent status - Add config sync endpoint for server->agent configuration updates - Add ignored updates workflow in AgentUpdatesEnhanced (approve/reject workflow) - Swap AgentScanners layout (subsystems top, security bottom) - Replace placeholder security data with database metrics - Add backpressure detection based on pending command ratios
This commit is contained in:
@@ -40,7 +40,7 @@ interface LogResponse {
|
||||
result: string;
|
||||
}
|
||||
|
||||
type StatusTab = 'pending' | 'approved' | 'installing' | 'installed';
|
||||
type StatusTab = 'pending' | 'approved' | 'installing' | 'installed' | 'ignored';
|
||||
|
||||
export function AgentUpdatesEnhanced({ agentId }: AgentUpdatesEnhancedProps) {
|
||||
const [activeStatus, setActiveStatus] = useState<StatusTab>('pending');
|
||||
@@ -123,6 +123,21 @@ export function AgentUpdatesEnhanced({ agentId }: AgentUpdatesEnhancedProps) {
|
||||
},
|
||||
});
|
||||
|
||||
const rejectMutation = useMutation({
|
||||
mutationFn: async (updateId: string) => {
|
||||
const response = await updateApi.rejectUpdate(updateId);
|
||||
return response;
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success('Update rejected');
|
||||
refetch();
|
||||
queryClient.invalidateQueries({ queryKey: ['agent-updates'] });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
toast.error(`Failed to reject: ${error.message || 'Unknown error'}`);
|
||||
},
|
||||
});
|
||||
|
||||
const getLogsMutation = useMutation({
|
||||
mutationFn: async (commandId: string) => {
|
||||
setIsLoadingLogs(true);
|
||||
@@ -182,6 +197,10 @@ export function AgentUpdatesEnhanced({ agentId }: AgentUpdatesEnhancedProps) {
|
||||
installMutation.mutate(updateId);
|
||||
};
|
||||
|
||||
const handleReject = async (updateId: string) => {
|
||||
rejectMutation.mutate(updateId);
|
||||
};
|
||||
|
||||
const handleBulkApprove = async () => {
|
||||
if (selectedUpdates.length === 0) {
|
||||
toast.error('Select at least one update');
|
||||
@@ -241,6 +260,7 @@ export function AgentUpdatesEnhanced({ agentId }: AgentUpdatesEnhancedProps) {
|
||||
{ key: 'approved', label: 'Approved' },
|
||||
{ key: 'installing', label: 'Installing' },
|
||||
{ key: 'installed', label: 'Installed' },
|
||||
{ key: 'ignored', label: 'Ignored' },
|
||||
].map((tab) => (
|
||||
<button
|
||||
key={tab.key}
|
||||
@@ -387,12 +407,20 @@ export function AgentUpdatesEnhanced({ agentId }: AgentUpdatesEnhancedProps) {
|
||||
|
||||
<div className="flex items-center space-x-2 flex-shrink-0">
|
||||
{activeStatus === 'pending' && (
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); handleApprove(update.id); }}
|
||||
className="text-xs text-gray-600 hover:text-gray-900 px-2 py-1"
|
||||
>
|
||||
Approve
|
||||
</button>
|
||||
<>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); handleApprove(update.id); }}
|
||||
className="text-xs text-gray-600 hover:text-gray-900 px-2 py-1"
|
||||
>
|
||||
Approve
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); handleReject(update.id); }}
|
||||
className="text-xs text-red-600 hover:text-red-800 px-2 py-1"
|
||||
>
|
||||
Reject
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{activeStatus === 'approved' && (
|
||||
<button
|
||||
@@ -402,6 +430,11 @@ export function AgentUpdatesEnhanced({ agentId }: AgentUpdatesEnhancedProps) {
|
||||
Install
|
||||
</button>
|
||||
)}
|
||||
{activeStatus === 'ignored' && (
|
||||
<span className="text-xs text-gray-500 px-2 py-1">
|
||||
Rejected
|
||||
</span>
|
||||
)}
|
||||
{update.recent_command_id && (
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); handleViewLogs(update); }}
|
||||
|
||||
Reference in New Issue
Block a user