Add version/build-date status bar to dashboard footer

Agent-Logs-Url: https://github.com/christianlouis/InboxConverge/sessions/9efbf677-2d92-487b-abae-9adf0c728f88

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-03-28 11:09:38 +00:00
parent b1dd322ec1
commit 1bb3f71230
7 changed files with 73 additions and 7 deletions
+2
View File
@@ -225,6 +225,8 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
build-args: |
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
# ── Phase 5: GitOps update preprod k8s manifest ─────────────────────────
update-k8s-manifest:
+4
View File
@@ -18,6 +18,10 @@ RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Inject build metadata
ARG BUILD_DATE=""
ENV BUILD_DATE=${BUILD_DATE}
# Create non-root user
RUN useradd -m -u 1000 appuser && \
chown -R appuser:appuser /app
+2
View File
@@ -14,6 +14,7 @@ from app.api.v1.endpoints import (
providers,
app_settings,
logs,
version,
)
api_router = APIRouter()
@@ -38,3 +39,4 @@ api_router.include_router(app_settings.router, prefix="/settings", tags=["Settin
api_router.include_router(
logs.router, prefix="/processing-runs", tags=["Processing Logs"]
)
api_router.include_router(version.router, prefix="/version", tags=["Version"])
+18
View File
@@ -0,0 +1,18 @@
"""
Version endpoint returns the application version and build date.
"""
from fastapi import APIRouter
from app.core.config import settings
router = APIRouter()
@router.get("")
async def get_version():
"""Return application version and build metadata."""
return {
"version": settings.APP_VERSION,
"build_date": settings.BUILD_DATE or None,
}
+1
View File
@@ -29,6 +29,7 @@ class Settings(BaseSettings):
# Application
APP_NAME: str = "InboxConverge"
APP_VERSION: str = "2.0.0"
BUILD_DATE: str = ""
APP_URL: str = "https://inboxconverge.com"
CONTACT_EMAIL: str = "christian@inboxconverge.com"
DEBUG: bool = False
+32 -7
View File
@@ -3,7 +3,9 @@
import { useState } from 'react';
import Link from 'next/link';
import { usePathname, useRouter } from 'next/navigation';
import { useQuery } from '@tanstack/react-query';
import { useAuthStore } from '@/store/authStore';
import { versionApi } from '@/lib/api';
import {
LayoutDashboard,
Mail,
@@ -30,6 +32,12 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
const router = useRouter();
const { user, logout } = useAuthStore();
const { data: versionInfo } = useQuery({
queryKey: ['version'],
queryFn: () => versionApi.get(),
staleTime: Infinity,
});
const handleLogout = () => {
logout();
router.push('/login');
@@ -235,13 +243,30 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
{/* Footer */}
<footer className="border-t border-gray-200 bg-white py-4 px-4 sm:px-6 lg:px-8">
<div className="mx-auto max-w-7xl flex flex-wrap justify-center gap-4 text-xs text-gray-400">
<Link href="/impressum" className="hover:text-gray-600 transition-colors">
Impressum
</Link>
<Link href="/datenschutz" className="hover:text-gray-600 transition-colors">
Datenschutz
</Link>
<div className="mx-auto max-w-7xl flex flex-wrap items-center justify-between gap-2 text-xs text-gray-400">
<div className="flex flex-wrap gap-4">
<Link href="/impressum" className="hover:text-gray-600 transition-colors">
Impressum
</Link>
<Link href="/datenschutz" className="hover:text-gray-600 transition-colors">
Datenschutz
</Link>
</div>
{versionInfo && (
<div className="flex flex-wrap gap-3">
<span>v{versionInfo.version}</span>
{versionInfo.build_date && (
<span>
Built{' '}
{new Date(versionInfo.build_date).toLocaleDateString(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
})}
</span>
)}
</div>
)}
</div>
</footer>
</div>
+14
View File
@@ -755,4 +755,18 @@ export const adminNotificationsApi = {
},
};
// ── Version API ─────────────────────────────────────────────────────────
export interface VersionInfo {
version: string;
build_date: string | null;
}
export const versionApi = {
async get(): Promise<VersionInfo> {
const response = await api.get<VersionInfo>('/version');
return response.data;
},
};
export default api;