الملفات
universal_migrator/S3S3Migrator.jsx

227 أسطر
7.9 KiB
JavaScript

import { useState } from "react";
import { listBuckets, startMigration, getProgress } from "../api";
export default function S3S3Migrator() {
const [awsAccess, setAwsAccess] = useState("");
const [awsSecret, setAwsSecret] = useState("");
const [awsRegion, setAwsRegion] = useState("us-east-1");
const [srcBucket, setSrcBucket] = useState("");
const [destBucket, setDestBucket] = useState("");
const [destEndpoint, setDestEndpoint] = useState("https://s3.amazonaws.com");
const [destAccess, setDestAccess] = useState("");
const [destSecret, setDestSecret] = useState("");
const [buckets, setBuckets] = useState([]);
const [progress, setProgress] = useState({ percent: 0, message: "Waiting to start..." });
const [loading, setLoading] = useState(false);
const loadBuckets = async () => {
if (!awsAccess || !awsSecret) {
alert("Please enter AWS Access Key and Secret Key first");
return;
}
setLoading(true);
try {
const data = await listBuckets({ AWS_SRC_ACCESS_KEY: awsAccess, AWS_SRC_SECRET_KEY: awsSecret, AWS_SRC_REGION: awsRegion });
if (data.success) {
setBuckets(data.buckets);
console.log("Buckets loaded:", data.buckets);
} else {
alert("Failed to load buckets: " + (data.error || "Unknown error"));
setBuckets([]);
}
} catch (error) {
console.error("Error loading buckets:", error);
alert("Connection error: " + error.message);
setBuckets([]);
} finally {
setLoading(false);
}
};
const handleMigration = async () => {
const payload = {
AWS_SRC_ACCESS_KEY: awsAccess,
AWS_SRC_SECRET_KEY: awsSecret,
AWS_SRC_REGION: awsRegion,
AWS_SRC_BUCKET: srcBucket,
CUMIN_DEST_ACCESS_KEY: destAccess,
CUMIN_DEST_SECRET_KEY: destSecret,
CUMIN_DEST_ENDPOINT: destEndpoint,
CUMIN_DEST_BUCKET: destBucket
};
try {
const data = await startMigration("s3_s3", payload);
if (data.success) {
pollProgress();
} else {
alert("Migration failed: " + (data.error || "Unknown error"));
}
} catch (error) {
console.error("Error starting migration:", error);
alert("Connection error: " + error.message);
}
};
const pollProgress = async () => {
try {
const data = await getProgress("s3_s3");
setProgress(data);
if (data.status === "error") {
alert("Migration error: " + (data.message || "Unknown error"));
} else if (data.percent < 100 && data.status !== "completed") {
setTimeout(pollProgress, 2000);
}
} catch (error) {
console.error("Error polling progress:", error);
setTimeout(pollProgress, 2000);
}
};
return (
<div className="space-y-8">
<div className="text-center">
<h2 className="text-2xl font-bold text-gray-900 dark:text-white mb-2">
S3 S3 Migration
</h2>
<p className="text-gray-600 dark:text-gray-300">
Migrate files between S3 buckets.
</p>
</div>
<div className="grid md:grid-cols-2 gap-8">
{/* Source S3 */}
<div className="bg-gray-50 dark:bg-gray-700 p-6 rounded-lg border border-gray-200 dark:border-red-600">
<h3 className="text-lg font-semibold mb-4 text-gray-900 dark:text-white">
Source S3
</h3>
<div className="space-y-4">
<div>
<label className="custom-label">Access Key</label>
<input
type="text"
placeholder="Enter Access Key"
value={awsAccess}
onChange={e => setAwsAccess(e.target.value)}
className="custom-input"
/>
</div>
<div>
<label className="custom-label">Secret Key</label>
<input
type="password"
placeholder="Enter Secret Key"
value={awsSecret}
onChange={e => setAwsSecret(e.target.value)}
className="custom-input"
/>
</div>
<div>
<label className="custom-label">Region</label>
<input
type="text"
placeholder="e.g., us-east-1"
value={awsRegion}
onChange={e => setAwsRegion(e.target.value)}
className="custom-input"
/>
</div>
<button
onClick={loadBuckets}
disabled={loading}
className="custom-button w-full"
>
{loading ? "Loading..." : "Load Buckets"}
</button>
{buckets.length > 0 && (
<div>
<label className="custom-label">Select Source Bucket</label>
<select
value={srcBucket}
onChange={e => setSrcBucket(e.target.value)}
className="custom-select"
>
<option value="">Select a bucket</option>
{buckets.map(b => <option key={b} value={b}>{b}</option>)}
</select>
</div>
)}
</div>
</div>
{/* Target S3 */}
<div className="bg-gray-50 dark:bg-gray-700 p-6 rounded-lg border border-gray-200 dark:border-red-600">
<h3 className="text-lg font-semibold mb-4 text-gray-900 dark:text-white">
Target S3
</h3>
<div className="space-y-4">
<div>
<label className="custom-label">Destination Access Key</label>
<input
type="text"
placeholder="Enter Destination Access Key"
value={destAccess}
onChange={e => setDestAccess(e.target.value)}
className="custom-input"
/>
</div>
<div>
<label className="custom-label">Destination Secret Key</label>
<input
type="password"
placeholder="Enter Destination Secret Key"
value={destSecret}
onChange={e => setDestSecret(e.target.value)}
className="custom-input"
/>
</div>
<div>
<label className="custom-label">Destination Endpoint</label>
<input
type="text"
placeholder="e.g., https://s3.amazonaws.com"
value={destEndpoint}
onChange={e => setDestEndpoint(e.target.value)}
className="custom-input"
/>
</div>
<div>
<label className="custom-label">Destination Bucket</label>
<input
type="text"
placeholder="e.g., target-bucket"
value={destBucket}
onChange={e => setDestBucket(e.target.value)}
className="custom-input"
/>
</div>
</div>
</div>
</div>
{/* Migration Button */}
<div className="text-center">
<button
onClick={handleMigration}
disabled={!srcBucket || !destBucket || !destAccess || !destSecret}
className="custom-button"
>
Start Migration
</button>
</div>
{/* Progress */}
<div className="bg-gray-50 dark:bg-gray-700 p-6 rounded-lg border border-gray-200 dark:border-red-600">
<h4 className="text-lg font-semibold mb-4 text-gray-900 dark:text-white">Progress</h4>
<div className="bg-gray-200 dark:bg-gray-600 rounded-full h-4 mb-4">
<div
className="bg-red-600 h-4 rounded-full transition-all duration-300"
style={{ width: `${progress.percent}%` }}
></div>
</div>
<pre className="bg-gray-800 text-red-400 p-4 rounded-lg overflow-auto text-sm border border-gray-600">
{JSON.stringify(progress, null, 2)}
</pre>
</div>
</div>
);
}