From 595dd8e5eb069ccd65a84370b283761fdde03773 Mon Sep 17 00:00:00 2001 From: mustafa_98 Date: Fri, 16 Jan 2026 22:21:58 +0000 Subject: [PATCH] =?UTF-8?q?=D8=B1=D9=81=D8=B9=20=D8=A7=D9=84=D9=85=D9=84?= =?UTF-8?q?=D9=81=D8=A7=D8=AA=20=D8=A5=D9=84=D9=89=20"/"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.jsx | 101 ++++++++++++++++++++++++++++++++++++++++++++++ api.js | 69 +++++++++++++++++++++++++++++++ main.jsx | 13 ++++++ postcss.config.js | 6 +++ vite.config.js | 19 +++++++++ 5 files changed, 208 insertions(+) create mode 100644 App.jsx create mode 100644 api.js create mode 100644 main.jsx create mode 100644 postcss.config.js create mode 100644 vite.config.js diff --git a/App.jsx b/App.jsx new file mode 100644 index 0000000..79f371b --- /dev/null +++ b/App.jsx @@ -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 ( +
+
+ {/* Header */} +
+
+
+

+ Universal Database Migrator +

+

+ Seamlessly migrate your databases across platforms +

+
+ +
+
+ + {/* Navigation */} + + + {/* Main Content */} +
+ + } /> + } /> + } /> + } /> + +
🚀
+

Welcome to Universal Migrator

+

+ Choose a migration type from the navigation above to get started. +

+
+ } + /> + + +
+ + ); +} \ No newline at end of file diff --git a/api.js b/api.js new file mode 100644 index 0000000..5d0946f --- /dev/null +++ b/api.js @@ -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 }; \ No newline at end of file diff --git a/main.jsx b/main.jsx new file mode 100644 index 0000000..8cc8d25 --- /dev/null +++ b/main.jsx @@ -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( + + + + + +); \ No newline at end of file diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..af9d8dc --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {}, + }, +} \ No newline at end of file diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..c40fc47 --- /dev/null +++ b/vite.config.js @@ -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 + } + } + } +}); \ No newline at end of file