Fix migration connection exhaustion and polish auth pages

- apply-migrations.ts: use single shared connection instead of one per operation
- Increase MariaDB max_connections from 151 to 300 in server config
- home-login-form.tsx: replace hardcoded gray colors with theme variables
- register-form.tsx: add password strength meter, spinner, theme-aligned inputs
- login-form.tsx: add Discord/Google SVG icons, spinner, smoother 2FA animation
- page/register/login: apply premium animations (float, stagger, glow, gradient)
This commit is contained in:
openhands committed 2026-07-24 11:30:58 +02:00
1 parent a9f1f4f99d
commit f7f6e09174
7 files changed
+394 -303

No files matched your search

+65 -66
View File
@@ -24,27 +24,27 @@ function getDbConfig(): { url: string; database: string } {
return { url: mysqlConnectionUrl(url), database: dbName };
}
async function ensureConnection(): Promise<void> {
async function openConnection() {
const { url } = getDbConfig();
const mysql = await import("mysql2/promise");
const conn = await mysql.createConnection(url);
try {
await conn.execute(
`CREATE TABLE IF NOT EXISTS \`${TRACKING_TABLE}\` (
return mysql.createConnection(url);
}
async function createTrackingTable(
conn: import("mysql2/promise").Connection,
): Promise<void> {
await conn.execute(
`CREATE TABLE IF NOT EXISTS \`${TRACKING_TABLE}\` (
id INT AUTO_INCREMENT PRIMARY KEY,
migration VARCHAR(255) NOT NULL UNIQUE,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4`,
);
} finally {
await conn.end();
}
);
}
async function getApplied(): Promise<Set<string>> {
const { url } = getDbConfig();
const mysql = await import("mysql2/promise");
const conn = await mysql.createConnection(url);
async function getApplied(
conn: import("mysql2/promise").Connection,
): Promise<Set<string>> {
try {
const [rows] = await conn.execute(
`SELECT migration FROM \`${TRACKING_TABLE}\` ORDER BY id`,
@@ -52,8 +52,6 @@ async function getApplied(): Promise<Set<string>> {
return new Set((rows as { migration: string }[]).map((r) => r.migration));
} catch {
return new Set();
} finally {
await conn.end();
}
}
@@ -70,69 +68,70 @@ function loadMigrations(): MigrationFile[] {
});
}
async function apply(migration: MigrationFile): Promise<void> {
const { url } = getDbConfig();
const mysql = await import("mysql2/promise");
const conn = await mysql.createConnection(url);
try {
const statements = splitSqlStatements(migration.sql);
async function apply(
conn: import("mysql2/promise").Connection,
migration: MigrationFile,
): Promise<void> {
const statements = splitSqlStatements(migration.sql);
for (const stmt of statements) {
await conn.execute(stmt);
}
await conn.execute(
`INSERT INTO \`${TRACKING_TABLE}\` (migration) VALUES (?)`,
[migration.id],
);
console.log(`[migrate] Applied: ${migration.name}`);
} finally {
await conn.end();
for (const stmt of statements) {
await conn.execute(stmt);
}
await conn.execute(
`INSERT INTO \`${TRACKING_TABLE}\` (migration) VALUES (?)`,
[migration.id],
);
console.log(`[migrate] Applied: ${migration.name}`);
}
async function main() {
const flag = process.argv[2];
const mysql = await import("mysql2/promise");
const { url } = getDbConfig();
const conn = await mysql.createConnection(url);
if (flag === "--status") {
await ensureConnection();
const applied = await getApplied();
const all = loadMigrations();
try {
await createTrackingTable(conn);
const applied = await getApplied(conn);
console.log("\nMigration status:\n");
for (const m of all) {
const done = applied.has(m.id);
console.log(
` ${done ? "✓" : " "} ${m.name}${done ? "" : " [PENDING]"}`,
);
if (process.argv[2] === "--status") {
const all = loadMigrations();
console.log("\nMigration status:\n");
for (const m of all) {
const done = applied.has(m.id);
console.log(
` ${done ? "✓" : " "} ${m.name}${done ? "" : " [PENDING]"}`,
);
}
const pending = all.filter((m) => !applied.has(m.id));
const total = all.length;
const done = total - pending.length;
console.log(`\n${done}/${total} applied, ${pending.length} pending\n`);
return;
}
const pending = all.filter((m) => !applied.has(m.id));
const total = all.length;
const done = total - pending.length;
console.log(`\n${done}/${total} applied, ${pending.length} pending\n`);
return;
}
const pending = loadMigrations().filter((m) => !applied.has(m.id));
await ensureConnection();
const applied = await getApplied();
const pending = loadMigrations().filter((m) => !applied.has(m.id));
if (pending.length === 0) {
console.log("[migrate] All migrations already applied.");
return;
}
console.log(`[migrate] Applying ${pending.length} migration(s)...\n`);
for (const m of pending) {
try {
await apply(m);
} catch (err) {
console.error(`[migrate] FAILED: ${m.name}`, err);
process.exit(1);
if (pending.length === 0) {
console.log("[migrate] All migrations already applied.");
return;
}
console.log(`[migrate] Applying ${pending.length} migration(s)...\n`);
for (const m of pending) {
try {
await apply(conn, m);
} catch (err) {
console.error(`[migrate] FAILED: ${m.name}`, err);
process.exit(1);
}
}
console.log("\n[migrate] Done.");
} finally {
await conn.end();
}
console.log("\n[migrate] Done.");
}
main().catch((err) => {