رفع الملفات إلى "/"

هذا الالتزام موجود في:
2026-01-16 22:21:58 +00:00
الأصل f9182d9e05
التزام 595dd8e5eb
5 ملفات معدلة مع 208 إضافات و0 حذوفات

101
App.jsx Normal file
عرض الملف

@@ -0,0 +1,101 @@
import { Routes, Route, Link, useLocation } from "react-router-dom";
import { useState, useEffect } from "react";
import MySQLMySQLMigrator from "./components/MySQLMySQLMigrator";
import PostgreSQLPostgreSQLMigrator from "./components/PostgreSQLPostgreSQLMigrator";
import PostgreSQLS3Migrator from "./components/PostgreSQLS3Migrator";
import S3S3Migrator from "./components/S3S3Migrator";
export default function App() {
const [darkMode, setDarkMode] = useState(() => {
const saved = localStorage.getItem('darkMode');
return saved ? JSON.parse(saved) : true; // Default to dark mode
});
const location = useLocation();
useEffect(() => {
localStorage.setItem('darkMode', JSON.stringify(darkMode));
if (darkMode) {
document.body.classList.add('dark');
} else {
document.body.classList.remove('dark');
}
}, [darkMode]);
const navItems = [
{ path: "/mysql-mysql", label: "MySQL → MySQL", icon: "🗄️" },
{ path: "/psql-psql", label: "PostgreSQL → PostgreSQL", icon: "🐘" },
{ path: "/psql-s3", label: "PostgreSQL → S3", icon: "☁️" },
{ path: "/s3-s3", label: "S3 → S3", icon: "📦" },
];
return (
<div className="min-h-screen bg-black dark:bg-black text-gray-900 dark:text-white transition-colors">
<div className="container mx-auto px-4 py-8 max-w-6xl">
{/* Header */}
<header className="bg-gray-900 dark:bg-gray-900 rounded-lg shadow-2xl p-6 mb-8 border border-red-600 glow-red">
<div className="flex justify-between items-center">
<div>
<h1 className="text-3xl font-bold text-red-600 dark:text-red-500">
Universal Database Migrator
</h1>
<p className="text-gray-400 dark:text-white mt-2">
Seamlessly migrate your databases across platforms
</p>
</div>
<button
onClick={() => setDarkMode(!darkMode)}
className="px-4 py-2 bg-red-600 dark:bg-red-700 text-white rounded-lg hover:bg-red-700 dark:hover:bg-red-800 transition-colors shadow-lg"
>
{darkMode ? "☀️ Light" : "🌙 Dark"}
</button>
</div>
</header>
{/* Navigation */}
<nav className="bg-gray-900 dark:bg-gray-900 rounded-lg shadow-2xl p-6 mb-8 border border-red-600 glow-red">
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{navItems.map((item) => (
<Link
key={item.path}
to={item.path}
className={`block p-4 rounded-lg border-2 transition-all ${
location.pathname === item.path
? "border-red-500 bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-white"
: "border-gray-600 dark:border-gray-700 hover:border-red-300 dark:hover:border-red-600 hover:bg-gray-800 dark:hover:bg-gray-700"
}`}
>
<div className="text-center">
<div className="text-3xl mb-2">{item.icon}</div>
<div className="text-sm font-medium">{item.label}</div>
</div>
</Link>
))}
</div>
</nav>
{/* Main Content */}
<main className="bg-gray-900 dark:bg-gray-900 rounded-lg shadow-2xl p-6 border border-red-600 glow-red">
<Routes>
<Route path="/mysql-mysql" element={<MySQLMySQLMigrator />} />
<Route path="/psql-psql" element={<PostgreSQLPostgreSQLMigrator />} />
<Route path="/psql-s3" element={<PostgreSQLS3Migrator />} />
<Route path="/s3-s3" element={<S3S3Migrator />} />
<Route
path="/"
element={
<div className="text-center py-12">
<div className="text-6xl mb-4">🚀</div>
<h2 className="text-2xl font-bold mb-4">Welcome to Universal Migrator</h2>
<p className="text-gray-600 dark:text-gray-400">
Choose a migration type from the navigation above to get started.
</p>
</div>
}
/>
</Routes>
</main>
</div>
</div>
);
}

69
api.js Normal file
عرض الملف

@@ -0,0 +1,69 @@
// API Base URL من متغيرات البيئة
const API_BASE = import.meta.env.VITE_API_BASE ?? "";
// =========================
// Schemas
// =========================
async function getSchemas(type, payload) {
const r = await fetch(`${API_BASE}/api/get_schemas`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
type,
...payload
})
});
return r.json();
}
// =========================
// Tables
// =========================
async function getTables(type, payload) {
const r = await fetch(`${API_BASE}/api/get_tables`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
type,
...payload
})
});
return r.json();
}
// =========================
// Start Migration
// =========================
async function startMigration(type, payload) {
const r = await fetch(`${API_BASE}/api/migrate`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
type,
...payload
})
});
return r.json();
}
// =========================
// Progress
// =========================
async function getProgress(type) {
const r = await fetch(`${API_BASE}/api/progress/${type}`);
return r.json();
}
// =========================
// List Buckets
// =========================
async function listBuckets(payload) {
const r = await fetch(`${API_BASE}/api/list_buckets`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
return r.json();
}
export { getSchemas, getTables, startMigration, getProgress, listBuckets };

13
main.jsx Normal file
عرض الملف

@@ -0,0 +1,13 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App.jsx";
import "./styles.css";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);

6
postcss.config.js Normal file
عرض الملف

@@ -0,0 +1,6 @@
export default {
plugins: {
'@tailwindcss/postcss': {},
autoprefixer: {},
},
}

19
vite.config.js Normal file
عرض الملف

@@ -0,0 +1,19 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
build: {
outDir: '../dist', // البناء ينتج مجلد dist خارج frontend
emptyOutDir: true
},
server: {
proxy: {
'/api': {
target: 'http://localhost:8001',
changeOrigin: true
}
}
}
});