From c36d1b3333494ab73be9e9ba4144c5ed2b010cdd Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 17:54:26 -0500 Subject: [PATCH 01/18] feat: filter tags by architecture --- app/pages/api/dockerhub/[image].ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/pages/api/dockerhub/[image].ts b/app/pages/api/dockerhub/[image].ts index aedd0f5..976f181 100644 --- a/app/pages/api/dockerhub/[image].ts +++ b/app/pages/api/dockerhub/[image].ts @@ -19,6 +19,7 @@ type Response = { readonly name: string; readonly last_updated: string; readonly digest: string; + readonly architecture: string; }>; readonly next: string | undefined; }; @@ -35,7 +36,12 @@ const processTagsResponse = (tags: Response['results']): IR => Object.fromEntries( tags // Latest is an unpredictable branch, thus will exclude it - .filter(({ name }) => !name.startsWith('sha-') && name !== 'latest') + .filter( + ({ name, images }) => + !name.startsWith('sha-') && + name !== 'latest' && + images.some(({ architecture }) => architecture === 'arm64') + ) .map(({ name, last_updated, digest }) => [ name, { From 4c060bb1472ceed088ce2c43b7328225780a783f Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 17:56:52 -0500 Subject: [PATCH 02/18] fix: type mismatch --- app/pages/api/dockerhub/[image].ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/pages/api/dockerhub/[image].ts b/app/pages/api/dockerhub/[image].ts index 976f181..caa4dbf 100644 --- a/app/pages/api/dockerhub/[image].ts +++ b/app/pages/api/dockerhub/[image].ts @@ -19,7 +19,9 @@ type Response = { readonly name: string; readonly last_updated: string; readonly digest: string; - readonly architecture: string; + readonly images: RA<{ + readonly architecture: string; + }>; }>; readonly next: string | undefined; }; From 9839e296196ac49d5fcfa3f2887fc6be1dde302d Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 18:55:46 -0500 Subject: [PATCH 03/18] feat: automatically add date after database name --- app/pages/api/databases/upload.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/pages/api/databases/upload.ts b/app/pages/api/databases/upload.ts index 1465c3c..fd3c50c 100644 --- a/app/pages/api/databases/upload.ts +++ b/app/pages/api/databases/upload.ts @@ -45,14 +45,20 @@ export default async function handler( if (typeof data === 'string') return res.status(400).json({ error: data }); - const databaseName = data.fields.databaseName as string | undefined; + const databaseNameForm = data.fields.databaseName as string | undefined; - if (!databaseName) + if (!databaseNameForm) return res.status(400).json({ error: 'Database name is required' }); - if (databaseName.match(/^\w+$/) === null) + if (databaseNameForm.match(/^\w+$/) === null) return res.status(400).json({ error: 'Database name is invalid' }); + const today = new Date(); + const year = today.getFullYear(); + const month = String(today.getMonth() + 1).padStart(2, '0'); + const day = String(today.getDate()).padStart(2, '0'); + const databaseName = `${databaseNameForm}_${year}_${month}_${day}`; + const file = data.files.file as File | undefined; if (typeof file === 'undefined' || file.newFilename === null) From e5b7881f82b55bc14e0b39e6393a1543a1367168 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 19:01:00 -0500 Subject: [PATCH 04/18] fix: use `mariadb` instead of `mysql` Fixes issues due to the deprecation of `mysql` ``` { "error": "mysql: Deprecated program name. It will be removed in a future release, use '/usr/bin/mariadb' instead\n" } ``` --- app/pages/api/databases/[name]/export.ts | 29 ++++++++++++------------ app/pages/api/databases/upload.ts | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/app/pages/api/databases/[name]/export.ts b/app/pages/api/databases/[name]/export.ts index 4d423f5..8c5cb91 100644 --- a/app/pages/api/databases/[name]/export.ts +++ b/app/pages/api/databases/[name]/export.ts @@ -24,19 +24,13 @@ export default async function handler( const sanitizedFilename = String(databaseName).replace(/[^\w.-]/g, '_'); try { - res.setHeader( - 'Content-Disposition', - `attachment; filename="${sanitizedFilename}.sql"` - ); - - const child = spawn( - 'mysqldump', + const result = await spawn( + 'mariadb-dump', [ - `-u${process.env.MYSQL_USERNAME}`, - `-p${process.env.MYSQL_PASSWORD}`, - `-h${process.env.MYSQL_HOST}`, - `--databases ${databaseName}`, - '--no-create-db', + `--user=${process.env.MYSQL_USERNAME}`, + `--password=${process.env.MYSQL_PASSWORD}`, + `--host=${process.env.MYSQL_HOST}`, + databaseName, ], { stdio: ['ignore', 'pipe', 'pipe'], @@ -44,11 +38,16 @@ export default async function handler( } ); - child.stdout.pipe(res); - child.stderr.on('data', (error) => { + res.setHeader( + 'Content-Disposition', + `attachment; filename="${sanitizedFilename}.sql"` + ); + + result.stdout.pipe(res); + result.stderr.on('data', (error) => { throw new Error(error); }); - await new Promise((resolve) => child.stdout.on('exit', resolve)); + await new Promise((resolve) => result.stdout.on('exit', resolve)); } catch (error) { res.status(500).json({ error: (error as object).toString(), diff --git a/app/pages/api/databases/upload.ts b/app/pages/api/databases/upload.ts index fd3c50c..ddd4934 100644 --- a/app/pages/api/databases/upload.ts +++ b/app/pages/api/databases/upload.ts @@ -117,7 +117,7 @@ export default async function handler( await connection.execute(`CREATE DATABASE \`${databaseName}\``); await run( [ - `mysql -u${process.env.MYSQL_USERNAME} `, + `mariadb -u${process.env.MYSQL_USERNAME} `, `-p${process.env.MYSQL_PASSWORD} `, `-h${process.env.MYSQL_HOST} `, `--database "${databaseName}" < ${filePath}`, From 295bb37bb99606199dd0b2b96b5dd682ab1b9147 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 19:02:26 -0500 Subject: [PATCH 05/18] fix: set `databaseName` variable properly --- app/pages/api/databases/[name]/export.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/pages/api/databases/[name]/export.ts b/app/pages/api/databases/[name]/export.ts index 8c5cb91..d8d304c 100644 --- a/app/pages/api/databases/[name]/export.ts +++ b/app/pages/api/databases/[name]/export.ts @@ -30,7 +30,8 @@ export default async function handler( `--user=${process.env.MYSQL_USERNAME}`, `--password=${process.env.MYSQL_PASSWORD}`, `--host=${process.env.MYSQL_HOST}`, - databaseName, + `--databases ${databaseName}`, + '--no-create-db', ], { stdio: ['ignore', 'pipe', 'pipe'], From e34611503fce6354aafd769bec675f317a6a931e Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 19:07:55 -0500 Subject: [PATCH 06/18] refactor: create utility for generating database name with date --- app/lib/databaseNameHelper.ts | 11 +++++++++++ app/pages/api/databases/upload.ts | 7 ++----- 2 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 app/lib/databaseNameHelper.ts diff --git a/app/lib/databaseNameHelper.ts b/app/lib/databaseNameHelper.ts new file mode 100644 index 0000000..0d699fa --- /dev/null +++ b/app/lib/databaseNameHelper.ts @@ -0,0 +1,11 @@ +/** + * Generate a database name with today's date suffix + * Format: {baseName}_YYYY_MM_DD + */ +export function generateDatabaseNameWithDate(baseName: string): string { + const today = new Date(); + const year = today.getFullYear(); + const month = String(today.getMonth() + 1).padStart(2, '0'); + const day = String(today.getDate()).padStart(2, '0'); + return `${baseName}_${year}_${month}_${day}`; +} diff --git a/app/pages/api/databases/upload.ts b/app/pages/api/databases/upload.ts index ddd4934..aac775c 100644 --- a/app/pages/api/databases/upload.ts +++ b/app/pages/api/databases/upload.ts @@ -6,6 +6,7 @@ import path from 'node:path'; import { getUser, run } from '../../../lib/apiUtils'; import { connectToDatabase } from '../../../lib/database'; +import { generateDatabaseNameWithDate } from '../../../lib/databaseNameHelper'; // First we need to disable the default body parser export const config = { @@ -53,11 +54,7 @@ export default async function handler( if (databaseNameForm.match(/^\w+$/) === null) return res.status(400).json({ error: 'Database name is invalid' }); - const today = new Date(); - const year = today.getFullYear(); - const month = String(today.getMonth() + 1).padStart(2, '0'); - const day = String(today.getDate()).padStart(2, '0'); - const databaseName = `${databaseNameForm}_${year}_${month}_${day}`; + const databaseName = generateDatabaseNameWithDate(databaseNameForm); const file = data.files.file as File | undefined; From ecba1e37186e816f47d0b96af52f8619f74f374c Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 19:11:32 -0500 Subject: [PATCH 07/18] feat: show live preview of new database name --- app/const/localization.ts | 1 + app/pages/databases/upload.tsx | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/const/localization.ts b/app/const/localization.ts index 3d876d6..2d9872e 100644 --- a/app/const/localization.ts +++ b/app/const/localization.ts @@ -79,6 +79,7 @@ export const localization = { mb: 'MB', nameConflict: 'Database with this name already exists. Please delete it first', + finalDatabaseName: 'Final database name:', container: 'Container', noLogsAvailable: 'No logs available for this container', failedToDownload: 'Failed to download', diff --git a/app/pages/databases/upload.tsx b/app/pages/databases/upload.tsx index ad60d89..b991824 100644 --- a/app/pages/databases/upload.tsx +++ b/app/pages/databases/upload.tsx @@ -6,6 +6,7 @@ import Layout from '../../components/Layout'; import { useApi } from '../../components/useApi'; import { useDatabases } from '../index'; import { localization } from '../../const/localization'; +import { generateDatabaseNameWithDate } from '../../lib/databaseNameHelper'; const bytesToMb = (size: number): number => Math.round((size / 1024 / 1024) * 100) / 100; @@ -22,7 +23,8 @@ export default function Index(): JSX.Element { const isConflict = typeof databases === 'object' && - databases.some(({ name }) => name === databaseName); + Boolean(databaseName) && + databases.some(({ name }) => name === generateDatabaseNameWithDate(databaseName)); return ( @@ -91,6 +93,16 @@ export default function Index(): JSX.Element { diskUsage.data.free + fileSize >= diskUsage.data.size * 0.99 ? (

{localization.notEnoughSpace}

) : undefined} + {databaseName && ( +
+ +
+ {generateDatabaseNameWithDate(databaseName)} +
+
+ )} Date: Sun, 20 Jul 2025 19:47:52 -0500 Subject: [PATCH 08/18] refactor: create utility for resetting passwords --- app/lib/passwordUtils.ts | 19 +++++++++++++++++++ app/pages/api/databases/upload.ts | 9 ++------- 2 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 app/lib/passwordUtils.ts diff --git a/app/lib/passwordUtils.ts b/app/lib/passwordUtils.ts new file mode 100644 index 0000000..fb3b818 --- /dev/null +++ b/app/lib/passwordUtils.ts @@ -0,0 +1,19 @@ +import type { Connection } from 'mysql2/promise'; + +const testPassword = 'EC62DEF08F5E4FD556DAA86AEC5F3FB0390EF8A862A41ECA'; + +/** + * Resets all user passwords in the specified database + */ +export async function resetDatabasePasswords( + connection: Connection, + databaseName: string +): Promise { + await connection.execute( + `UPDATE \`${databaseName}\`.specifyuser + SET Password=?;`, + [testPassword] + ); +} + +export { testPassword }; diff --git a/app/pages/api/databases/upload.ts b/app/pages/api/databases/upload.ts index aac775c..b153786 100644 --- a/app/pages/api/databases/upload.ts +++ b/app/pages/api/databases/upload.ts @@ -7,6 +7,7 @@ import path from 'node:path'; import { getUser, run } from '../../../lib/apiUtils'; import { connectToDatabase } from '../../../lib/database'; import { generateDatabaseNameWithDate } from '../../../lib/databaseNameHelper'; +import { resetDatabasePasswords } from '../../../lib/passwordUtils'; // First we need to disable the default body parser export const config = { @@ -15,8 +16,6 @@ export const config = { }, }; -const testuserPassword = 'EC62DEF08F5E4FD556DAA86AEC5F3FB0390EF8A862A41ECA'; - export default async function handler( request: NextApiRequest, res: NextApiResponse @@ -120,11 +119,7 @@ export default async function handler( `--database "${databaseName}" < ${filePath}`, ].join('') ); - await connection.execute( - `UPDATE \`${databaseName}\`.specifyuser - SET Password=?;`, - [testuserPassword] - ); + await resetDatabasePasswords(connection, databaseName); res.writeHead(302, { Location: '/databases/', }); From a204868cc9bcbea7533b20f939780311c022c65f Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 19:48:49 -0500 Subject: [PATCH 09/18] feat: add localization --- app/const/localization.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/const/localization.ts b/app/const/localization.ts index 2d9872e..3fab37d 100644 --- a/app/const/localization.ts +++ b/app/const/localization.ts @@ -67,7 +67,14 @@ export const localization = { deleteDialogTitle: 'Delete Database?', deleteDialogMessage: (database: string) => `Are you sure you want to delete "${database}" database?`, - makeSuperUser: 'Make super user', + makeSuperUser: 'Make Institution Admin', + resetPasswords: 'Reset Passwords', + resetPasswordsDialogTitle: 'Reset All Passwords?', + resetPasswordsDialogMessage: (database: string) => + `Are you sure you want to reset all user passwords in the "${database}" database?`, + resettingPasswords: 'Resetting passwords...', + passwordsReset: 'All passwords have been reset successfully', + failedToResetPasswords: 'Failed to reset passwords', calculateSizes: 'Calculate sizes', uploadNewDatabase: 'Upload new database', databaseName: 'Database Name', From eafb88d6451bb6a2228166ad3004c5e6e4a3ce4d Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 19:49:15 -0500 Subject: [PATCH 10/18] feat: add reset passwords button to databases --- .../api/databases/[name]/reset-passwords.ts | 42 ++++++++++ app/pages/databases/index.tsx | 78 +++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 app/pages/api/databases/[name]/reset-passwords.ts diff --git a/app/pages/api/databases/[name]/reset-passwords.ts b/app/pages/api/databases/[name]/reset-passwords.ts new file mode 100644 index 0000000..7a54eab --- /dev/null +++ b/app/pages/api/databases/[name]/reset-passwords.ts @@ -0,0 +1,42 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; + +import { getUser } from '../../../../lib/apiUtils'; +import { connectToDatabase } from '../../../../lib/database'; +import { resetDatabasePasswords } from '../../../../lib/passwordUtils'; + +export default async function handler( + request: NextApiRequest, + res: NextApiResponse +) { + if (request.method !== 'POST') { + return res.status(405).json({ error: 'Method not allowed' }); + } + + const user = await getUser(request, res); + if (typeof user === 'undefined') return; + + const databaseName = request.query.name as string; + + if (!databaseName) { + return res.status(400).json({ error: 'Database name is required' }); + } + + // Validate database name to prevent SQL injection + if (databaseName.match(/^\w+$/) === null) { + return res.status(400).json({ error: 'Database name is invalid' }); + } + + try { + const connection = await connectToDatabase(); + + // Reset all user passwords to the test password + await resetDatabasePasswords(connection, databaseName); + + await connection.end(); + + res.status(200).json({ success: true }); + } catch (error: any) { + console.error('Failed to reset passwords:', error); + res.status(500).json({ error: error.toString() }); + } +} diff --git a/app/pages/databases/index.tsx b/app/pages/databases/index.tsx index c6bf437..6013e6e 100644 --- a/app/pages/databases/index.tsx +++ b/app/pages/databases/index.tsx @@ -37,6 +37,10 @@ export default function Index(): JSX.Element { string | undefined >(undefined); + const [resetPasswordsDatabase, setResetPasswordsDatabase] = React.useState< + string | undefined + >(undefined); + const [showSizes, setShowSizes] = React.useState(false); const [sizes, setSizes] = React.useState< { readonly data: IR } | string | undefined @@ -112,6 +116,13 @@ export default function Index(): JSX.Element { > {localization.listUsers} + ))} @@ -147,6 +158,12 @@ export default function Index(): JSX.Element { onClose={(): void => setDeleteDatabase(undefined)} /> )} + {typeof resetPasswordsDatabase === 'string' && ( + setResetPasswordsDatabase(undefined)} + /> + )} )}
@@ -233,3 +250,64 @@ function DeleteDatabase({ ); } + +function ResetPasswordsDatabase({ + database, + onClose: handleClose, +}: { + readonly database: string; + readonly onClose: () => void; +}): JSX.Element { + const [isResetting, setIsResetting] = React.useState(false); + + const handleResetPasswords = async (): Promise => { + setIsResetting(true); + try { + const response = await fetch(`/api/databases/${database}/reset-passwords`, { + method: 'POST', + }); + + if (response.ok) { + alert(localization.passwordsReset); + handleClose(); + } else { + const error = await response.json(); + alert(`${localization.failedToResetPasswords}: ${error.error || response.statusText}`); + } + } catch (error) { + console.error('Failed to reset passwords:', error); + alert(`${localization.failedToResetPasswords}: ${error}`); + } finally { + setIsResetting(false); + } + }; + + return ( + + + + + } + title={localization.resetPasswordsDialogTitle} + onClose={handleClose} + > + {localization.resetPasswordsDialogMessage(database)} + + ); +} From 80d06a3e7286cfa19c7d34356309556b5b54692c Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 19:57:04 -0500 Subject: [PATCH 11/18] fix: do not terminate connection --- app/pages/api/databases/[name]/reset-passwords.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/pages/api/databases/[name]/reset-passwords.ts b/app/pages/api/databases/[name]/reset-passwords.ts index 7a54eab..96d555b 100644 --- a/app/pages/api/databases/[name]/reset-passwords.ts +++ b/app/pages/api/databases/[name]/reset-passwords.ts @@ -32,8 +32,6 @@ export default async function handler( // Reset all user passwords to the test password await resetDatabasePasswords(connection, databaseName); - await connection.end(); - res.status(200).json({ success: true }); } catch (error: any) { console.error('Failed to reset passwords:', error); From 4827ca823ad9a2a808f247c253a796c4dc466fea Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 20:04:45 -0500 Subject: [PATCH 12/18] fix: allow databases to take full width --- app/pages/databases/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pages/databases/index.tsx b/app/pages/databases/index.tsx index 6013e6e..cc495ac 100644 --- a/app/pages/databases/index.tsx +++ b/app/pages/databases/index.tsx @@ -78,7 +78,7 @@ export default function Index(): JSX.Element {

{localization.pageTitle}

{localization.dashboard}

- + )} ); @@ -229,16 +237,17 @@ function DeleteDatabase({ buttons={ <> + {icons.trash} {localization.delete} @@ -287,7 +296,7 @@ function ResetPasswordsDatabase({ buttons={ <> From 1b9b2f72be09a319dd71e034f45735b4487eeeaf Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 20:11:58 -0500 Subject: [PATCH 14/18] fix: correct calculator icon --- app/components/Icons.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/components/Icons.tsx b/app/components/Icons.tsx index 760bb6c..eebb185 100644 --- a/app/components/Icons.tsx +++ b/app/components/Icons.tsx @@ -23,5 +23,14 @@ export const icons = { trash: , key: , upload: , - calculator: , + calculator: ( + + + + + + + + + ), } as const; From 1c6d7ac939759c724df3c347a75ced33ba331781 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 20:23:01 -0500 Subject: [PATCH 15/18] refactor: show icons and not text --- app/pages/databases/index.tsx | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/app/pages/databases/index.tsx b/app/pages/databases/index.tsx index e488069..11af674 100644 --- a/app/pages/databases/index.tsx +++ b/app/pages/databases/index.tsx @@ -94,51 +94,51 @@ export default function Index(): JSX.Element { {!usedDatabases.has(name) && ( { event.preventDefault(); setDeleteDatabase(name); }} > {icons.trash} - {localization.delete} )} {icons.download} - {localization.download} ))}
- + {icons.upload} - {localization.uploadNew}
{typeof listUsers === 'string' && ( From 97f85505666dbd47840a88f2e1029999147775f8 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 20:31:37 -0500 Subject: [PATCH 16/18] fix: remove unused declarations --- app/pages/databases/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/pages/databases/index.tsx b/app/pages/databases/index.tsx index 11af674..ead6e69 100644 --- a/app/pages/databases/index.tsx +++ b/app/pages/databases/index.tsx @@ -3,9 +3,7 @@ import React from 'react'; import { dangerButtonClassName, - infoButtonClassName, primaryButtonClassName, - successButtonClassName, } from '../../components/InteractivePrimitives'; import { icons } from '../../components/Icons'; import Layout from '../../components/Layout'; From 0dbc75bf09a30c21f64059a6449d4389ef104529 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 21:08:30 -0500 Subject: [PATCH 17/18] fix: make major buttons more prominent --- app/pages/databases/index.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/pages/databases/index.tsx b/app/pages/databases/index.tsx index ead6e69..c7a807b 100644 --- a/app/pages/databases/index.tsx +++ b/app/pages/databases/index.tsx @@ -2,6 +2,8 @@ import Link from 'next/link'; import React from 'react'; import { + infoButtonClassName, + successButtonClassName, dangerButtonClassName, primaryButtonClassName, } from '../../components/InteractivePrimitives'; @@ -131,11 +133,12 @@ export default function Index(): JSX.Element {
- + {icons.upload} + {localization.uploadNew}
{typeof listUsers === 'string' && ( From a2b4eafcea4ab86e9ec2c557611582877ae784d6 Mon Sep 17 00:00:00 2001 From: Grant Fitzsimmons <37256050+grantfitzsimmons@users.noreply.github.com> Date: Sun, 20 Jul 2025 21:13:24 -0500 Subject: [PATCH 18/18] fix: change colors for better contrast fix: update icon background fix: show trash even when database cannot be deleted fix: move delete before database name fix: remove unnecessary padding --- app/pages/databases/index.tsx | 36 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/app/pages/databases/index.tsx b/app/pages/databases/index.tsx index c7a807b..0083e64 100644 --- a/app/pages/databases/index.tsx +++ b/app/pages/databases/index.tsx @@ -85,6 +85,21 @@ export default function Index(): JSX.Element { className="flex flex-row gap-x-5 rounded bg-gray-300 p-5" key={name} > + { + if (usedDatabases.has(name)) { + event.preventDefault(); + return; + } + event.preventDefault(); + setDeleteDatabase(name); + }} + > + {icons.trash} + {name} ({version ?? localization.corruptDatabase}) @@ -92,28 +107,15 @@ export default function Index(): JSX.Element { {` (${size} ${localization.mb})`} )} - {!usedDatabases.has(name) && ( - { - event.preventDefault(); - setDeleteDatabase(name); - }} - > - {icons.trash} - - )} {icons.download}