gmail-to-exchange365
Version:
Complete Gmail to Exchange 365 migration tool with UI - Migrate emails, attachments, and folders seamlessly
263 lines (226 loc) • 8.23 kB
JavaScript
// State management
let migrationState = {
googleConnected: false,
msConnected: false,
isRunning: false,
isPaused: false
};
// DOM elements
const googleBtn = document.getElementById("google-btn");
const msBtn = document.getElementById("ms-btn");
const googleStatus = document.getElementById("google-status");
const msStatus = document.getElementById("ms-status");
const googleIndicator = document.getElementById("google-indicator");
const msIndicator = document.getElementById("ms-indicator");
const startBtn = document.getElementById("start-btn");
const pauseBtn = document.getElementById("pause-btn");
const resumeBtn = document.getElementById("resume-btn");
const stopBtn = document.getElementById("stop-btn");
const progressFill = document.getElementById("progress-fill");
const progressPercentage = document.getElementById("progress-percentage");
const progressCount = document.getElementById("progress-count");
const progressMessage = document.getElementById("progress-message");
const logsContainer = document.getElementById("logs");
const batchSizeInput = document.getElementById("batch-size");
const delayInput = document.getElementById("delay");
let eventSource = null;
// Initialize
document.addEventListener("DOMContentLoaded", () => {
checkAuthStatus();
setupEventListeners();
checkUrlParams();
});
function checkUrlParams() {
const params = new URLSearchParams(window.location.search);
if (params.get("google") === "connected") {
addLog("✅ Google account connected successfully", "success");
checkAuthStatus();
}
if (params.get("ms") === "connected") {
addLog("✅ Microsoft account connected successfully", "success");
checkAuthStatus();
}
if (params.get("error")) {
addLog(`❌ Error: ${params.get("error")}`, "error");
}
}
async function checkAuthStatus() {
try {
const response = await fetch("/api/status");
const data = await response.json();
migrationState.googleConnected = data.google;
migrationState.msConnected = data.ms;
updateUI();
} catch (error) {
console.error("Error checking auth status:", error);
}
}
function updateUI() {
// Update Google status
if (migrationState.googleConnected) {
googleStatus.textContent = "Google Connected";
googleIndicator.className = "status-indicator connected";
googleBtn.classList.add("connected");
} else {
googleStatus.textContent = "Connect Google";
googleIndicator.className = "status-indicator";
googleBtn.classList.remove("connected");
}
// Update Microsoft status
if (migrationState.msConnected) {
msStatus.textContent = "Microsoft Connected";
msIndicator.className = "status-indicator connected";
msBtn.classList.add("connected");
} else {
msStatus.textContent = "Connect Microsoft";
msIndicator.className = "status-indicator";
msBtn.classList.remove("connected");
}
// Update start button
startBtn.disabled = !(migrationState.googleConnected && migrationState.msConnected) || migrationState.isRunning;
// Update control buttons
pauseBtn.disabled = !migrationState.isRunning || migrationState.isPaused;
resumeBtn.disabled = !migrationState.isRunning || !migrationState.isPaused;
stopBtn.disabled = !migrationState.isRunning;
}
function setupEventListeners() {
googleBtn.addEventListener("click", () => {
window.location.href = "/google/auth";
});
msBtn.addEventListener("click", () => {
window.location.href = "/ms/auth";
});
startBtn.addEventListener("click", startMigration);
pauseBtn.addEventListener("click", pauseMigration);
resumeBtn.addEventListener("click", resumeMigration);
stopBtn.addEventListener("click", stopMigration);
}
async function startMigration() {
if (!migrationState.googleConnected || !migrationState.msConnected) {
addLog("❌ Please connect both Google and Microsoft accounts first", "error");
return;
}
migrationState.isRunning = true;
migrationState.isPaused = false;
updateUI();
const batchSize = parseInt(batchSizeInput.value) || 10;
const delay = parseInt(delayInput.value) || 1000;
addLog("🚀 Starting migration...", "info");
addLog(`📊 Configuration: Batch size=${batchSize}, Delay=${delay}ms`, "info");
try {
const response = await fetch("/api/migrate", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
batchSize,
delayBetweenBatches: delay,
retryAttempts: 3,
retryDelay: 5000
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() || "";
for (const line of lines) {
if (line.startsWith("data: ")) {
try {
const data = JSON.parse(line.substring(6));
handleProgressUpdate(data);
} catch (e) {
console.error("Error parsing progress data:", e);
}
}
}
}
if (buffer.startsWith("data: ")) {
try {
const data = JSON.parse(buffer.substring(6));
handleProgressUpdate(data);
} catch (e) {
console.error("Error parsing final progress data:", e);
}
}
} catch (error) {
addLog(`❌ Migration error: ${error.message}`, "error");
migrationState.isRunning = false;
updateUI();
}
}
function handleProgressUpdate(data) {
if (data.error) {
addLog(`❌ Error: ${data.error}`, "error");
migrationState.isRunning = false;
updateUI();
return;
}
if (data.completed) {
addLog("✅ Migration completed successfully!", "success");
migrationState.isRunning = false;
updateUI();
return;
}
if (data.current !== undefined && data.total !== undefined) {
const percentage = data.total > 0 ? Math.round((data.current / data.total) * 100) : 0;
progressFill.style.width = `${percentage}%`;
progressPercentage.textContent = `${percentage}%`;
progressCount.textContent = `${data.current} / ${data.total}`;
if (data.message) {
progressMessage.textContent = data.message;
if (data.current % 10 === 0 || data.current === data.total) {
addLog(data.message, "info");
}
}
}
}
async function pauseMigration() {
try {
const response = await fetch("/api/migrate/pause", { method: "POST" });
const data = await response.json();
addLog("⏸️ Migration paused", "info");
migrationState.isPaused = true;
updateUI();
} catch (error) {
addLog(`❌ Error pausing migration: ${error.message}`, "error");
}
}
async function resumeMigration() {
try {
const response = await fetch("/api/migrate/resume", { method: "POST" });
const data = await response.json();
addLog("▶️ Migration resumed", "info");
migrationState.isPaused = false;
updateUI();
} catch (error) {
addLog(`❌ Error resuming migration: ${error.message}`, "error");
}
}
async function stopMigration() {
try {
const response = await fetch("/api/migrate/stop", { method: "POST" });
const data = await response.json();
addLog("⏹️ Migration stopped", "warning");
migrationState.isRunning = false;
migrationState.isPaused = false;
updateUI();
} catch (error) {
addLog(`❌ Error stopping migration: ${error.message}`, "error");
}
}
function addLog(message, type = "info") {
const logEntry = document.createElement("div");
logEntry.className = `log-entry log-${type}`;
logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
logsContainer.appendChild(logEntry);
logsContainer.scrollTop = logsContainer.scrollHeight;
}