diff --git a/frontend/pages/applications/[slug].vue b/frontend/pages/applications/[slug].vue index f4c308b..cf476a5 100644 --- a/frontend/pages/applications/[slug].vue +++ b/frontend/pages/applications/[slug].vue @@ -4,8 +4,8 @@ import { getApplication, updateApplication, deleteApplication } from '~/services import { createEnvironment, updateEnvironment, deleteEnvironment, toggleMaintenance } from '~/services/environments' import type { DeployResult } from '~/services/dto/deploy' import { getAvailableTags, deploy } from '~/services/deploy' -import type { EnvironmentHealth } from '~/services/dto/dashboard' -import { getEnvironmentHealth } from '~/services/dashboard' +import type { EnvironmentHealth, DatabaseInfo } from '~/services/dto/dashboard' +import { getEnvironmentHealth, getDatabaseInfo } from '~/services/dashboard' import type { LogOutput } from '~/services/dto/logs' import { getDockerLogs, getSymfonyLog } from '~/services/logs' @@ -31,6 +31,9 @@ const deployResult = ref(null) const healthByEnvId = ref>({}) const loadingHealth = ref(false) +// Database info per env +const dbInfoByEnvId = ref>({}) + // Log modals const showLogModal = ref(false) const logContent = ref('') @@ -54,6 +57,7 @@ const envForm = ref({ deployScriptPath: '', maintenanceFilePath: '', appUrl: '', + databaseName: '', logFiles: [], }) const isSubmittingEnv = ref(false) @@ -66,6 +70,7 @@ async function loadApplication() { loading.value = false } loadHealthData() + loadDatabaseData() } // Application edit @@ -103,7 +108,7 @@ async function handleDeleteApp() { // Environment CRUD function openCreateEnvModal() { editingEnvId.value = null - envForm.value = { name: '', containerName: '', deployScriptPath: '', maintenanceFilePath: '', appUrl: '', logFiles: [] } + envForm.value = { name: '', containerName: '', deployScriptPath: '', maintenanceFilePath: '', appUrl: '', databaseName: '', logFiles: [] } showEnvModal.value = true } @@ -115,6 +120,7 @@ function openEditEnvModal(env: Environment) { deployScriptPath: env.deployScriptPath, maintenanceFilePath: env.maintenanceFilePath, appUrl: env.appUrl ?? '', + databaseName: env.databaseName ?? '', logFiles: env.logFiles.map(lf => ({ label: lf.label, path: lf.path })), } showEnvModal.value = true @@ -215,6 +221,20 @@ async function loadHealthData() { } } +async function loadDatabaseData() { + if (!application.value?.environments?.length) return + const promises = application.value.environments.map(async (env) => { + if (!env.databaseName) return + try { + const info = await getDatabaseInfo(env.id!) + dbInfoByEnvId.value[env.id!] = info + } catch { + // silently ignore — no database configured or unreachable + } + }) + await Promise.all(promises) +} + function formatUptime(startedAt: string): string { if (!startedAt) return '-' const start = new Date(startedAt) @@ -471,6 +491,50 @@ onMounted(loadApplication) + + +
+

{{ t('environments.database.title') }}

+
+
+

{{ t('environments.database.status') }}

+ + {{ dbInfoByEnvId[env.id!].connected + ? t('environments.database.connected') + : t('environments.database.unreachable') }} + +
+
+

{{ t('environments.database.name') }}

+

{{ dbInfoByEnvId[env.id!].name }}

+
+
+

{{ t('environments.database.size') }}

+

{{ dbInfoByEnvId[env.id!].size || '-' }}

+
+
+

{{ t('environments.database.tableCount') }}

+

{{ dbInfoByEnvId[env.id!].tableCount }}

+
+
+

{{ t('environments.database.activeConnections') }}

+

{{ dbInfoByEnvId[env.id!].activeConnections }}

+
+
+

{{ t('environments.database.cacheHitRatio') }}

+

{{ dbInfoByEnvId[env.id!].cacheHitRatio }}%

+
+
+

+ {{ t('environments.database.largestTable') }} : {{ dbInfoByEnvId[env.id!].largestTable }} +

+
+
+