337 lines
12 KiB
TypeScript
337 lines
12 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useState, useEffect } from 'react';
|
||
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||
|
|
import { Button } from '@/components/ui/button';
|
||
|
|
import { Badge } from '@/components/ui/badge';
|
||
|
|
import {
|
||
|
|
CheckCircle,
|
||
|
|
XCircle,
|
||
|
|
AlertCircle,
|
||
|
|
RefreshCw,
|
||
|
|
Copy,
|
||
|
|
ExternalLink,
|
||
|
|
FileText
|
||
|
|
} from 'lucide-react';
|
||
|
|
|
||
|
|
interface HealthStatus {
|
||
|
|
status: 'healthy' | 'error';
|
||
|
|
message: string;
|
||
|
|
configuration?: {
|
||
|
|
apiUrl: string;
|
||
|
|
username: string;
|
||
|
|
password: string;
|
||
|
|
integrationCode: string;
|
||
|
|
};
|
||
|
|
instructions?: string[];
|
||
|
|
apiResponse?: {
|
||
|
|
status: number;
|
||
|
|
statusText: string;
|
||
|
|
error: string;
|
||
|
|
};
|
||
|
|
possibleIssues?: string[];
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function SetupPage() {
|
||
|
|
const [healthStatus, setHealthStatus] = useState<HealthStatus | null>(null);
|
||
|
|
const [loading, setLoading] = useState(false);
|
||
|
|
const [copied, setCopied] = useState(false);
|
||
|
|
|
||
|
|
const checkHealth = async () => {
|
||
|
|
setLoading(true);
|
||
|
|
try {
|
||
|
|
const response = await fetch('/api/health');
|
||
|
|
const data = await response.json();
|
||
|
|
setHealthStatus(data);
|
||
|
|
} catch (error) {
|
||
|
|
setHealthStatus({
|
||
|
|
status: 'error',
|
||
|
|
message: 'Failed to check API health',
|
||
|
|
instructions: ['Make sure the Next.js server is running']
|
||
|
|
});
|
||
|
|
} finally {
|
||
|
|
setLoading(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
checkHealth();
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const copyEnvTemplate = () => {
|
||
|
|
const template = `# Autotask API Configuration
|
||
|
|
AUTOTASK_API_URL=https://webservices1.autotask.net/atservicesrest/v1.0
|
||
|
|
AUTOTASK_USERNAME=your-api-username@yourdomain.com
|
||
|
|
AUTOTASK_SECRET=your-api-password
|
||
|
|
AUTOTASK_API_INTEGRATION_CODE=your-tracking-code`;
|
||
|
|
|
||
|
|
navigator.clipboard.writeText(template);
|
||
|
|
setCopied(true);
|
||
|
|
setTimeout(() => setCopied(false), 2000);
|
||
|
|
};
|
||
|
|
|
||
|
|
const getStatusIcon = (status: string) => {
|
||
|
|
if (status === 'configured') {
|
||
|
|
return <CheckCircle className="w-4 h-4 text-green-500" />;
|
||
|
|
}
|
||
|
|
return <XCircle className="w-4 h-4 text-red-500" />;
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-950 p-8">
|
||
|
|
<div className="max-w-4xl mx-auto space-y-6">
|
||
|
|
<div className="text-center mb-8">
|
||
|
|
<h1 className="text-3xl font-bold text-gray-900 dark:text-white mb-2">
|
||
|
|
Autotask API Setup & Diagnostics
|
||
|
|
</h1>
|
||
|
|
<p className="text-gray-600 dark:text-gray-400">
|
||
|
|
Configure and test your Autotask API connection
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Health Status Card */}
|
||
|
|
<Card>
|
||
|
|
<CardHeader>
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<div>
|
||
|
|
<CardTitle>API Connection Status</CardTitle>
|
||
|
|
<CardDescription>
|
||
|
|
Current status of your Autotask API configuration
|
||
|
|
</CardDescription>
|
||
|
|
</div>
|
||
|
|
<Button
|
||
|
|
onClick={checkHealth}
|
||
|
|
disabled={loading}
|
||
|
|
variant="outline"
|
||
|
|
>
|
||
|
|
{loading ? (
|
||
|
|
<RefreshCw className="w-4 h-4 mr-2 animate-spin" />
|
||
|
|
) : (
|
||
|
|
<RefreshCw className="w-4 h-4 mr-2" />
|
||
|
|
)}
|
||
|
|
Refresh
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent>
|
||
|
|
{healthStatus && (
|
||
|
|
<div className="space-y-4">
|
||
|
|
{/* Overall Status */}
|
||
|
|
<div className="flex items-center gap-3">
|
||
|
|
{healthStatus.status === 'healthy' ? (
|
||
|
|
<>
|
||
|
|
<CheckCircle className="w-6 h-6 text-green-500" />
|
||
|
|
<span className="text-lg font-semibold text-green-600">
|
||
|
|
{healthStatus.message}
|
||
|
|
</span>
|
||
|
|
</>
|
||
|
|
) : (
|
||
|
|
<>
|
||
|
|
<XCircle className="w-6 h-6 text-red-500" />
|
||
|
|
<span className="text-lg font-semibold text-red-600">
|
||
|
|
{healthStatus.message}
|
||
|
|
</span>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Configuration Status */}
|
||
|
|
{healthStatus.configuration && (
|
||
|
|
<div className="border rounded-lg p-4 space-y-2">
|
||
|
|
<h3 className="font-semibold mb-2">Configuration Status:</h3>
|
||
|
|
<div className="grid grid-cols-2 gap-2">
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
{getStatusIcon(healthStatus.configuration.apiUrl)}
|
||
|
|
<span>API URL</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
{getStatusIcon(healthStatus.configuration.username)}
|
||
|
|
<span>Username</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
{getStatusIcon(healthStatus.configuration.password)}
|
||
|
|
<span>Password</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
{getStatusIcon(healthStatus.configuration.integrationCode)}
|
||
|
|
<span>Integration Code</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* API Response Error */}
|
||
|
|
{healthStatus.apiResponse && (
|
||
|
|
<div className="border border-red-200 bg-red-50 dark:bg-red-900/20 rounded-lg p-4">
|
||
|
|
<h3 className="font-semibold text-red-700 dark:text-red-400 mb-2">
|
||
|
|
API Response Error:
|
||
|
|
</h3>
|
||
|
|
<div className="space-y-1 text-sm">
|
||
|
|
<p>Status: {healthStatus.apiResponse.status} - {healthStatus.apiResponse.statusText}</p>
|
||
|
|
{healthStatus.apiResponse.error && (
|
||
|
|
<p className="text-xs font-mono bg-red-100 dark:bg-red-900/30 p-2 rounded mt-2">
|
||
|
|
{healthStatus.apiResponse.error}
|
||
|
|
</p>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Possible Issues */}
|
||
|
|
{healthStatus.possibleIssues && (
|
||
|
|
<div className="border border-yellow-200 bg-yellow-50 dark:bg-yellow-900/20 rounded-lg p-4">
|
||
|
|
<h3 className="font-semibold text-yellow-700 dark:text-yellow-400 mb-2 flex items-center gap-2">
|
||
|
|
<AlertCircle className="w-4 h-4" />
|
||
|
|
Possible Issues:
|
||
|
|
</h3>
|
||
|
|
<ul className="list-disc list-inside space-y-1 text-sm">
|
||
|
|
{healthStatus.possibleIssues.map((issue, index) => (
|
||
|
|
<li key={index}>{issue}</li>
|
||
|
|
))}
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Setup Instructions */}
|
||
|
|
{healthStatus.instructions && (
|
||
|
|
<div className="border border-blue-200 bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4">
|
||
|
|
<h3 className="font-semibold text-blue-700 dark:text-blue-400 mb-2">
|
||
|
|
Setup Instructions:
|
||
|
|
</h3>
|
||
|
|
<ol className="space-y-1 text-sm">
|
||
|
|
{healthStatus.instructions.map((instruction, index) => (
|
||
|
|
<li key={index} className={instruction.startsWith(' ') ? 'ml-4 font-mono' : ''}>
|
||
|
|
{instruction}
|
||
|
|
</li>
|
||
|
|
))}
|
||
|
|
</ol>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
|
||
|
|
{/* Environment Template Card */}
|
||
|
|
<Card>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle>Environment Variables Template</CardTitle>
|
||
|
|
<CardDescription>
|
||
|
|
Copy this template to create your .env.local file
|
||
|
|
</CardDescription>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent>
|
||
|
|
<div className="relative">
|
||
|
|
<pre className="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto text-sm">
|
||
|
|
<code>{`# Autotask API Configuration
|
||
|
|
AUTOTASK_API_URL=https://webservices1.autotask.net/atservicesrest/v1.0
|
||
|
|
AUTOTASK_USERNAME=your-api-username@yourdomain.com
|
||
|
|
AUTOTASK_SECRET=your-api-password
|
||
|
|
AUTOTASK_API_INTEGRATION_CODE=your-tracking-code`}</code>
|
||
|
|
</pre>
|
||
|
|
<Button
|
||
|
|
onClick={copyEnvTemplate}
|
||
|
|
variant="outline"
|
||
|
|
size="sm"
|
||
|
|
className="absolute top-2 right-2"
|
||
|
|
>
|
||
|
|
{copied ? (
|
||
|
|
<>
|
||
|
|
<CheckCircle className="w-4 h-4 mr-2" />
|
||
|
|
Copied!
|
||
|
|
</>
|
||
|
|
) : (
|
||
|
|
<>
|
||
|
|
<Copy className="w-4 h-4 mr-2" />
|
||
|
|
Copy
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
<div className="mt-4 space-y-2 text-sm text-gray-600 dark:text-gray-400">
|
||
|
|
<p className="flex items-center gap-2">
|
||
|
|
<FileText className="w-4 h-4" />
|
||
|
|
Save this as <code className="bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded">.env.local</code> in the project root
|
||
|
|
</p>
|
||
|
|
<p className="flex items-center gap-2">
|
||
|
|
<AlertCircle className="w-4 h-4 text-yellow-500" />
|
||
|
|
Remember to restart the server after adding the file
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
|
||
|
|
{/* Resources Card */}
|
||
|
|
<Card>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle>Helpful Resources</CardTitle>
|
||
|
|
<CardDescription>
|
||
|
|
Documentation and guides for Autotask API integration
|
||
|
|
</CardDescription>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent>
|
||
|
|
<div className="space-y-3">
|
||
|
|
<a
|
||
|
|
href="https://ww1.autotask.net/help/DeveloperHelp/Content/APIs/REST/REST_API_Home.htm"
|
||
|
|
target="_blank"
|
||
|
|
rel="noopener noreferrer"
|
||
|
|
className="flex items-center gap-2 text-blue-600 hover:text-blue-700 dark:text-blue-400"
|
||
|
|
>
|
||
|
|
<ExternalLink className="w-4 h-4" />
|
||
|
|
Autotask REST API Documentation
|
||
|
|
</a>
|
||
|
|
<a
|
||
|
|
href="/api/health"
|
||
|
|
target="_blank"
|
||
|
|
className="flex items-center gap-2 text-blue-600 hover:text-blue-700 dark:text-blue-400"
|
||
|
|
>
|
||
|
|
<ExternalLink className="w-4 h-4" />
|
||
|
|
API Health Check Endpoint
|
||
|
|
</a>
|
||
|
|
<a
|
||
|
|
href="/"
|
||
|
|
className="flex items-center gap-2 text-blue-600 hover:text-blue-700 dark:text-blue-400"
|
||
|
|
>
|
||
|
|
<ExternalLink className="w-4 h-4" />
|
||
|
|
Back to Dashboard
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
|
||
|
|
{/* API Zone Information */}
|
||
|
|
<Card>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle>Autotask API Zones</CardTitle>
|
||
|
|
<CardDescription>
|
||
|
|
Make sure you're using the correct zone URL for your Autotask instance
|
||
|
|
</CardDescription>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent>
|
||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
|
||
|
|
<div>
|
||
|
|
<h4 className="font-semibold mb-2">North America</h4>
|
||
|
|
<ul className="space-y-1 font-mono text-xs">
|
||
|
|
<li>Zone 1: webservices1.autotask.net</li>
|
||
|
|
<li>Zone 2: webservices2.autotask.net</li>
|
||
|
|
<li>Zone 3: webservices3.autotask.net</li>
|
||
|
|
<li>Zone 4: webservices4.autotask.net</li>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
<div>
|
||
|
|
<h4 className="font-semibold mb-2">Other Regions</h4>
|
||
|
|
<ul className="space-y-1 font-mono text-xs">
|
||
|
|
<li>Zone 5: webservices5.autotask.net</li>
|
||
|
|
<li>Zone 6: webservices6.autotask.net</li>
|
||
|
|
<li>PRD: prde.autotask.net</li>
|
||
|
|
<li>IOC: ioce.autotask.net</li>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|