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:
@@ -225,6 +225,8 @@ jobs:
|
|||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
platforms: linux/amd64,linux/arm64
|
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 ─────────────────────────
|
# ── Phase 5: GitOps – update preprod k8s manifest ─────────────────────────
|
||||||
update-k8s-manifest:
|
update-k8s-manifest:
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ RUN pip install --no-cache-dir -r requirements.txt
|
|||||||
# Copy application code
|
# Copy application code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
# Inject build metadata
|
||||||
|
ARG BUILD_DATE=""
|
||||||
|
ENV BUILD_DATE=${BUILD_DATE}
|
||||||
|
|
||||||
# Create non-root user
|
# Create non-root user
|
||||||
RUN useradd -m -u 1000 appuser && \
|
RUN useradd -m -u 1000 appuser && \
|
||||||
chown -R appuser:appuser /app
|
chown -R appuser:appuser /app
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from app.api.v1.endpoints import (
|
|||||||
providers,
|
providers,
|
||||||
app_settings,
|
app_settings,
|
||||||
logs,
|
logs,
|
||||||
|
version,
|
||||||
)
|
)
|
||||||
|
|
||||||
api_router = APIRouter()
|
api_router = APIRouter()
|
||||||
@@ -38,3 +39,4 @@ api_router.include_router(app_settings.router, prefix="/settings", tags=["Settin
|
|||||||
api_router.include_router(
|
api_router.include_router(
|
||||||
logs.router, prefix="/processing-runs", tags=["Processing Logs"]
|
logs.router, prefix="/processing-runs", tags=["Processing Logs"]
|
||||||
)
|
)
|
||||||
|
api_router.include_router(version.router, prefix="/version", tags=["Version"])
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ class Settings(BaseSettings):
|
|||||||
# Application
|
# Application
|
||||||
APP_NAME: str = "InboxConverge"
|
APP_NAME: str = "InboxConverge"
|
||||||
APP_VERSION: str = "2.0.0"
|
APP_VERSION: str = "2.0.0"
|
||||||
|
BUILD_DATE: str = ""
|
||||||
APP_URL: str = "https://inboxconverge.com"
|
APP_URL: str = "https://inboxconverge.com"
|
||||||
CONTACT_EMAIL: str = "christian@inboxconverge.com"
|
CONTACT_EMAIL: str = "christian@inboxconverge.com"
|
||||||
DEBUG: bool = False
|
DEBUG: bool = False
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { usePathname, useRouter } from 'next/navigation';
|
import { usePathname, useRouter } from 'next/navigation';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useAuthStore } from '@/store/authStore';
|
import { useAuthStore } from '@/store/authStore';
|
||||||
|
import { versionApi } from '@/lib/api';
|
||||||
import {
|
import {
|
||||||
LayoutDashboard,
|
LayoutDashboard,
|
||||||
Mail,
|
Mail,
|
||||||
@@ -30,6 +32,12 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { user, logout } = useAuthStore();
|
const { user, logout } = useAuthStore();
|
||||||
|
|
||||||
|
const { data: versionInfo } = useQuery({
|
||||||
|
queryKey: ['version'],
|
||||||
|
queryFn: () => versionApi.get(),
|
||||||
|
staleTime: Infinity,
|
||||||
|
});
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
logout();
|
logout();
|
||||||
router.push('/login');
|
router.push('/login');
|
||||||
@@ -235,13 +243,30 @@ export function DashboardLayout({ children }: DashboardLayoutProps) {
|
|||||||
|
|
||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<footer className="border-t border-gray-200 bg-white py-4 px-4 sm:px-6 lg:px-8">
|
<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">
|
<div className="mx-auto max-w-7xl flex flex-wrap items-center justify-between gap-2 text-xs text-gray-400">
|
||||||
<Link href="/impressum" className="hover:text-gray-600 transition-colors">
|
<div className="flex flex-wrap gap-4">
|
||||||
Impressum
|
<Link href="/impressum" className="hover:text-gray-600 transition-colors">
|
||||||
</Link>
|
Impressum
|
||||||
<Link href="/datenschutz" className="hover:text-gray-600 transition-colors">
|
</Link>
|
||||||
Datenschutz
|
<Link href="/datenschutz" className="hover:text-gray-600 transition-colors">
|
||||||
</Link>
|
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>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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;
|
export default api;
|
||||||
|
|||||||
Reference in New Issue
Block a user