- Renamed project from PSA-Utils to Pulse - Moved all app files from autotask-app/ to root - Updated package.json name to 'pulse' - Updated Docker container names to pulse-app and pulse-redis - Updated Docker network name to pulse-network
153 lines
4.8 KiB
TypeScript
153 lines
4.8 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@/components/ui/dialog';
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
import { PSATab } from './psa-tab';
|
|
import { RMMTab } from './rmm-tab';
|
|
import { StatusCards } from './status-cards';
|
|
import {
|
|
Server,
|
|
Monitor,
|
|
AlertCircle
|
|
} from 'lucide-react';
|
|
import { ConfigurationItem } from '@/lib/types/autotask';
|
|
import { DattoRMMDevice } from '@/lib/types/datto-rmm';
|
|
|
|
interface ConfigItemDetail {
|
|
autotaskDevice?: ConfigurationItem;
|
|
rmmDevice?: DattoRMMDevice;
|
|
companyName?: string;
|
|
}
|
|
|
|
interface ConfigItemModalProps {
|
|
itemId: string | number | null;
|
|
type?: 'autotask' | 'rmm';
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
}
|
|
|
|
export function ConfigItemModal({ itemId, type = 'autotask', open, onOpenChange }: ConfigItemModalProps) {
|
|
const [data, setData] = useState<ConfigItemDetail>({});
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!open || !itemId) {
|
|
return;
|
|
}
|
|
|
|
const fetchData = async () => {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const response = await fetch(`/api/configuration-items/${itemId}?type=${type}`);
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch configuration item');
|
|
}
|
|
|
|
const result = await response.json();
|
|
setData(result);
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'An error occurred');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchData();
|
|
}, [itemId, type, open]);
|
|
|
|
const handleUpdate = (updatedDevice: ConfigurationItem) => {
|
|
setData({ ...data, autotaskDevice: updatedDevice });
|
|
};
|
|
|
|
const device = data.autotaskDevice;
|
|
const rmmDevice = data.rmmDevice;
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent
|
|
className="w-[95vw] sm:w-[90vw] md:w-[85vw] lg:w-[80vw] xl:w-[75vw] h-[90vh] overflow-y-auto"
|
|
style={{ maxWidth: '1400px' }}
|
|
>
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-3">
|
|
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-purple-600 to-purple-700 text-white">
|
|
<Server className="h-4 w-4" />
|
|
</div>
|
|
<div>
|
|
<div className="text-lg font-semibold">
|
|
{device?.referenceTitle || rmmDevice?.hostname || 'Configuration Item'}
|
|
</div>
|
|
{data.companyName && (
|
|
<div className="text-sm font-normal text-muted-foreground">
|
|
{data.companyName}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</DialogTitle>
|
|
</DialogHeader>
|
|
|
|
{loading ? (
|
|
<div className="space-y-4 py-4">
|
|
<Skeleton className="h-24 w-full" />
|
|
<Skeleton className="h-96 w-full" />
|
|
</div>
|
|
) : error ? (
|
|
<div className="py-8">
|
|
<div className="flex items-center gap-2 text-red-500 justify-center">
|
|
<AlertCircle className="w-5 h-5" />
|
|
<p>Error: {error}</p>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-6">
|
|
{/* Status Cards */}
|
|
<StatusCards device={device} rmmDevice={rmmDevice} />
|
|
|
|
{/* Tabs */}
|
|
<Tabs defaultValue="psa" className="space-y-4">
|
|
<TabsList className="grid w-full grid-cols-2">
|
|
<TabsTrigger value="psa" className="flex items-center gap-2">
|
|
<Server className="w-4 h-4" />
|
|
PSA Data
|
|
{device && (
|
|
<Badge variant="outline" className="ml-1">
|
|
{device.isActive ? 'Active' : 'Inactive'}
|
|
</Badge>
|
|
)}
|
|
</TabsTrigger>
|
|
<TabsTrigger value="rmm" className="flex items-center gap-2">
|
|
<Monitor className="w-4 h-4" />
|
|
RMM Data
|
|
{rmmDevice && (
|
|
<Badge variant="outline" className="ml-1">
|
|
{rmmDevice.online ? 'Online' : 'Offline'}
|
|
</Badge>
|
|
)}
|
|
</TabsTrigger>
|
|
</TabsList>
|
|
|
|
<TabsContent value="psa">
|
|
<PSATab device={device} onUpdate={handleUpdate} />
|
|
</TabsContent>
|
|
|
|
<TabsContent value="rmm">
|
|
<RMMTab device={rmmDevice} />
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
)}
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|