wulf-pulse/components/configuration-items/addigy-tab.tsx
root 6eee14f8af Add comprehensive admin features and multi-system integration
- Add admin dashboard with sync controls and data browser
- Implement RMM, Auvik, and Addigy organization mappings
- Add chunked ticket sync with progress tracking
- Implement entity sync service with rate limiting
- Add analytics engine and performance optimizer
- Create data browser for all PSA entities
- Add navigation components and UI improvements
- Implement background processing and sync services
- Add comprehensive documentation and migration scripts
- Update configuration items with multi-system support
- Enhance contact management and purchase history
- Add issue type assignment and LLM analyzer
- Improve error handling and logging utilities
2025-11-19 14:18:16 -05:00

360 lines
13 KiB
TypeScript

'use client';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Label } from '@/components/ui/label';
import {
Smartphone,
Info,
HardDrive,
Shield,
Wifi,
XCircle,
Battery,
CheckCircle,
AlertCircle
} from 'lucide-react';
import { AddigyDevice } from '@/lib/types/addigy';
interface AddigyTabProps {
device?: AddigyDevice;
}
export function AddigyTab({ device }: AddigyTabProps) {
if (!device) {
return (
<Card className="border-0 shadow-lg">
<CardContent className="pt-6">
<div className="text-center py-12 text-muted-foreground">
<Smartphone className="w-12 h-12 mx-auto mb-4 opacity-50" />
<p>No Addigy data available for this device</p>
</div>
</CardContent>
</Card>
);
}
const isOnline = device.online;
const batteryPercentage = device['Battery Percentage'];
const isCharging = device['Battery Charging'];
const freeSpacePercentage = device['Free Disk Percentage'];
return (
<Card className="border-0 shadow-lg">
<CardHeader className="bg-gradient-to-r from-orange-50 to-orange-100 dark:from-orange-950 dark:to-orange-900 rounded-t-lg">
<CardTitle className="text-lg flex items-center gap-2">
<Smartphone className="w-5 h-5" />
Addigy Device Information (Apple RMM)
</CardTitle>
</CardHeader>
<CardContent className="pt-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Basic Information */}
<div className="space-y-4">
<h3 className="font-semibold flex items-center gap-2">
<Info className="w-4 h-4" />
Basic Information
</h3>
<div className="space-y-3">
<div>
<Label>Device Name</Label>
<p className="text-sm text-muted-foreground mt-1">{device['Device Name']}</p>
</div>
<div>
<Label>Model</Label>
<p className="text-sm text-muted-foreground mt-1">
{device['Device Model Name'] || '-'}
</p>
</div>
<div>
<Label>Serial Number</Label>
<p className="text-sm text-muted-foreground font-mono mt-1">
{device['Serial Number'] || '-'}
</p>
</div>
<div>
<Label>Current User</Label>
<p className="text-sm text-muted-foreground mt-1">
{device['Current User'] || '-'}
</p>
</div>
<div>
<Label>Status</Label>
<div className="flex items-center gap-2 mt-1">
{isOnline ? (
<Badge variant="default" className="bg-green-600">
<Wifi className="w-3 h-3 mr-1" />
Online
</Badge>
) : (
<Badge variant="secondary">
<XCircle className="w-3 h-3 mr-1" />
Offline
</Badge>
)}
</div>
</div>
{device['Last Check In'] && (
<div>
<Label>Last Check In</Label>
<p className="text-sm text-muted-foreground mt-1">
{new Date(device['Last Check In']).toLocaleString()}
</p>
</div>
)}
</div>
</div>
{/* System Information */}
<div className="space-y-4">
<h3 className="font-semibold flex items-center gap-2">
<HardDrive className="w-4 h-4" />
System Information
</h3>
<div className="space-y-3">
<div>
<Label>Operating System</Label>
<p className="text-sm text-muted-foreground mt-1">
{device['MAC OS X Version'] || device['iOS Version'] || '-'}
</p>
</div>
{device['Processor Type'] && (
<div>
<Label>Processor</Label>
<p className="text-sm text-muted-foreground mt-1">
{device['Processor Type']}
{device['Processor Speed (GHz)'] && ` @ ${device['Processor Speed (GHz)']} GHz`}
</p>
</div>
)}
{device['Total Disk Space (GB)'] && (
<div>
<Label>Disk Space</Label>
<div className="mt-1">
<p className="text-sm text-muted-foreground">
{device['Free Disk Space (GB)']} GB free of {device['Total Disk Space (GB)']} GB
</p>
{freeSpacePercentage !== undefined && (
<div className="flex items-center gap-2 mt-1">
<div className="flex-1 h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
<div
className={`h-full ${
freeSpacePercentage < 10 ? 'bg-red-500' :
freeSpacePercentage < 20 ? 'bg-orange-500' :
'bg-green-500'
}`}
style={{ width: `${freeSpacePercentage}%` }}
/>
</div>
<span className="text-xs text-muted-foreground">{freeSpacePercentage.toFixed(1)}%</span>
</div>
)}
</div>
</div>
)}
{batteryPercentage !== undefined && (
<div>
<Label>Battery</Label>
<div className="flex items-center gap-2 mt-1">
<Battery className={`w-4 h-4 ${isCharging ? 'text-green-600' : ''}`} />
<span className="text-sm text-muted-foreground">
{batteryPercentage}%
{isCharging && ' (Charging)'}
</span>
{device['Battery Capacity Loss Percentage'] !== undefined && (
<span className="text-xs text-muted-foreground">
({device['Battery Capacity Loss Percentage']}% capacity loss)
</span>
)}
</div>
</div>
)}
<div>
<Label>Agent Version</Label>
<p className="text-sm text-muted-foreground mt-1">
{device['Agent Version'] || '-'}
</p>
</div>
{device.Timezone && (
<div>
<Label>Timezone</Label>
<p className="text-sm text-muted-foreground mt-1">
{device.Timezone}
</p>
</div>
)}
</div>
</div>
{/* Security & Features */}
<div className="space-y-4">
<h3 className="font-semibold flex items-center gap-2">
<Shield className="w-4 h-4" />
Security & Features
</h3>
<div className="space-y-3">
<div>
<Label>Firewall</Label>
<div className="flex items-center gap-2 mt-1">
{device['Firewall Enabled'] ? (
<Badge variant="default" className="bg-green-600">
<CheckCircle className="w-3 h-3 mr-1" />
Enabled
</Badge>
) : (
<Badge variant="destructive">
<XCircle className="w-3 h-3 mr-1" />
Disabled
</Badge>
)}
</div>
</div>
<div>
<Label>FileVault</Label>
<div className="flex items-center gap-2 mt-1">
{device['FileVault Enabled'] ? (
<Badge variant="default" className="bg-green-600">
<CheckCircle className="w-3 h-3 mr-1" />
Enabled
</Badge>
) : (
<Badge variant="destructive">
<XCircle className="w-3 h-3 mr-1" />
Disabled
</Badge>
)}
</div>
</div>
{device['Remote Login Enabled'] !== undefined && (
<div>
<Label>Remote Login</Label>
<div className="flex items-center gap-2 mt-1">
{device['Remote Login Enabled'] ? (
<Badge variant="outline">
<CheckCircle className="w-3 h-3 mr-1" />
Enabled
</Badge>
) : (
<Badge variant="secondary">
<XCircle className="w-3 h-3 mr-1" />
Disabled
</Badge>
)}
</div>
</div>
)}
{device['SMART Failing'] !== undefined && (
<div>
<Label>SMART Status</Label>
<div className="flex items-center gap-2 mt-1">
{device['SMART Failing'] ? (
<Badge variant="destructive">
<AlertCircle className="w-3 h-3 mr-1" />
Failing
</Badge>
) : (
<Badge variant="default" className="bg-green-600">
<CheckCircle className="w-3 h-3 mr-1" />
Healthy
</Badge>
)}
</div>
</div>
)}
{device['Has Wireless'] !== undefined && (
<div>
<Label>Wireless Capability</Label>
<p className="text-sm text-muted-foreground mt-1">
{device['Has Wireless'] ? 'Yes' : 'No'}
</p>
</div>
)}
{device['XCode Installed'] !== undefined && (
<div>
<Label>XCode</Label>
<p className="text-sm text-muted-foreground mt-1">
{device['XCode Installed'] ? 'Installed' : 'Not Installed'}
</p>
</div>
)}
</div>
</div>
{/* Additional Information */}
<div className="space-y-4">
<h3 className="font-semibold flex items-center gap-2">
<Info className="w-4 h-4" />
Additional Information
</h3>
<div className="space-y-3">
<div>
<Label>Agent ID</Label>
<p className="text-sm text-muted-foreground font-mono mt-1">
{device.agentid}
</p>
</div>
<div>
<Label>Policy ID</Label>
<p className="text-sm text-muted-foreground font-mono mt-1">
{device.policy_id}
</p>
</div>
{device['Warranty Expiration Date'] && (
<div>
<Label>Warranty</Label>
<p className="text-sm text-muted-foreground mt-1">
Expires: {new Date(device['Warranty Expiration Date']).toLocaleDateString()}
{device['Warranty Days Left'] !== undefined && (
<span className="ml-2">({device['Warranty Days Left']} days left)</span>
)}
</p>
</div>
)}
{device['TeamViewer Client Id'] && (
<div>
<Label>TeamViewer ID</Label>
<p className="text-sm text-muted-foreground font-mono mt-1">
{device['TeamViewer Client Id']}
</p>
</div>
)}
{device['Displays Serial Number'] && device['Displays Serial Number'].length > 0 && (
<div>
<Label>Display Serial Numbers</Label>
<div className="text-sm text-muted-foreground font-mono mt-1 space-y-1">
{device['Displays Serial Number'].map((serial, idx) => (
<div key={idx}>{serial}</div>
))}
</div>
</div>
)}
</div>
</div>
</div>
</CardContent>
</Card>
);
}