diff --git a/frontend/src/app/(app)/layout/horizontal/header/Header.tsx b/frontend/src/app/(app)/layout/horizontal/header/Header.tsx
index cc027c1..7be73c1 100644
--- a/frontend/src/app/(app)/layout/horizontal/header/Header.tsx
+++ b/frontend/src/app/(app)/layout/horizontal/header/Header.tsx
@@ -9,8 +9,8 @@ import useMediaQuery from '@mui/material/useMediaQuery';
import { styled } from '@mui/material/styles';
import { IconMenu2 } from "@tabler/icons-react";
+import About from "../../vertical/header/About";
import ApiDocsLink from "../../vertical/header/ApiDocsLink";
-import Notifications from "../../vertical/header/Notification";
import Profile from "../../vertical/header/Profile";
import Search from "../../vertical/header/Search";
import Logo from "../../shared/logo/Logo";
@@ -85,7 +85,7 @@ export default function Header() {
)}
-
+
diff --git a/frontend/src/app/(app)/layout/vertical/header/About.tsx b/frontend/src/app/(app)/layout/vertical/header/About.tsx
new file mode 100644
index 0000000..27ed723
--- /dev/null
+++ b/frontend/src/app/(app)/layout/vertical/header/About.tsx
@@ -0,0 +1,134 @@
+"use client";
+
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import Dialog from "@mui/material/Dialog";
+import DialogActions from "@mui/material/DialogActions";
+import DialogContent from "@mui/material/DialogContent";
+import DialogTitle from "@mui/material/DialogTitle";
+import IconButton from "@mui/material/IconButton";
+import Stack from "@mui/material/Stack";
+import Tooltip from "@mui/material/Tooltip";
+import Typography from "@mui/material/Typography";
+import ContentCopyIcon from "@mui/icons-material/ContentCopy";
+import { Icon } from "@iconify/react";
+import { useEffect, useState } from "react";
+
+interface ServerVersion {
+ version: string;
+ buildTime: string;
+ gitCommit: string;
+}
+
+// The /api/v1/version probe predates the {success,data} envelope the rest of
+// the API uses and returns bare snake_case JSON, so it is fetched directly
+// rather than through the api client (which requires the envelope). Both
+// shapes are accepted in case that endpoint is ever normalised.
+async function fetchVersion(signal: AbortSignal): Promise {
+ const res = await fetch("/api/v1/version", { signal });
+ if (!res.ok) throw new Error(`version request failed (${res.status})`);
+ const body = await res.json();
+ const v = body?.data ?? body ?? {};
+ return {
+ version: v.version ?? v.Version ?? "unknown",
+ buildTime: v.build_time ?? v.buildTime ?? "",
+ gitCommit: v.git_commit ?? v.gitCommit ?? "",
+ };
+}
+
+function formatBuildTime(raw: string): string {
+ if (!raw || raw === "unknown") return "—";
+ const d = new Date(raw);
+ return Number.isNaN(d.getTime()) ? raw : d.toLocaleString();
+}
+
+// About shows the running server's build so an operator can confirm which
+// version is deployed — and quote it verbatim in a bug report — without
+// shelling onto the host.
+export default function About() {
+ const [open, setOpen] = useState(false);
+ const [info, setInfo] = useState(null);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ if (!open) return;
+ const controller = new AbortController();
+ setError(null);
+ fetchVersion(controller.signal)
+ .then(setInfo)
+ .catch((err) => {
+ if (err?.name !== "AbortError") setError("Could not read the server version.");
+ });
+ return () => controller.abort();
+ }, [open]);
+
+ const summary = info
+ ? `OrchestrAD ${info.version}${info.gitCommit ? ` (${info.gitCommit})` : ""}`
+ : "";
+
+ const rows: Array<[string, string]> = info
+ ? [
+ ["Version", info.version],
+ ["Built", formatBuildTime(info.buildTime)],
+ ["Commit", info.gitCommit || "—"],
+ ]
+ : [];
+
+ return (
+ <>
+
+ setOpen(true)}>
+
+
+
+
+
+ >
+ );
+}
diff --git a/frontend/src/app/(app)/layout/vertical/header/AppLinks.tsx b/frontend/src/app/(app)/layout/vertical/header/AppLinks.tsx
deleted file mode 100644
index c4014f4..0000000
--- a/frontend/src/app/(app)/layout/vertical/header/AppLinks.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import Avatar from '@mui/material/Avatar';
-import Box from '@mui/material/Box';
-import { Grid } from '@mui/material';
-import Stack from '@mui/material/Stack';
-import Typography from '@mui/material/Typography';
-import * as dropdownData from './data';
-import Link from 'next/link';
-import React from 'react';
-
-const AppLinks = () => {
- return (
- (
- {dropdownData.appsLink.map((links, index) => (
-
-
-
-
-
-
-
-
- {links.title}
-
-
- {links.subtext}
-
-
-
-
-
- ))}
- )
- );
-};
-
-export default AppLinks;
diff --git a/frontend/src/app/(app)/layout/vertical/header/Header.tsx b/frontend/src/app/(app)/layout/vertical/header/Header.tsx
index 4de1b34..fc884ad 100644
--- a/frontend/src/app/(app)/layout/vertical/header/Header.tsx
+++ b/frontend/src/app/(app)/layout/vertical/header/Header.tsx
@@ -8,8 +8,8 @@ import { styled } from '@mui/material/styles';
import config from '@/app/context/config'
import { useContext } from "react";
import { Icon } from "@iconify/react";
+import About from "./About";
import ApiDocsLink from "./ApiDocsLink";
-import Notifications from "./Notification";
import Profile from "./Profile";
import Search from "./Search";
@@ -88,7 +88,7 @@ const Header = () => {
-
+
diff --git a/frontend/src/app/(app)/layout/vertical/header/Notification.tsx b/frontend/src/app/(app)/layout/vertical/header/Notification.tsx
deleted file mode 100644
index e95b4f2..0000000
--- a/frontend/src/app/(app)/layout/vertical/header/Notification.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-import React, { useState } from "react";
-import Avatar from '@mui/material/Avatar';
-import Box from '@mui/material/Box';
-import Button from '@mui/material/Button';
-import Chip from '@mui/material/Chip';
-import Menu from '@mui/material/Menu';
-import MenuItem from '@mui/material/MenuItem';
-import Typography from '@mui/material/Typography';
-import * as dropdownData from "./data";
-import Scrollbar from "@/app/components/custom-scroll/Scrollbar";
-
-import { Icon } from "@iconify/react";
-import { Stack } from "@mui/system";
-import Link from "next/link";
-
-const Notifications = () => {
- const [anchorEl2, setAnchorEl2] = useState(null);
-
- const handleClick2 = (event: React.MouseEvent) => {
- setAnchorEl2(event.currentTarget);
- };
-
- const handleClose2 = () => {
- setAnchorEl2(null);
- };
-
- return (
-
-
- {/* ------------------------------------------- */}
- {/* Message Dropdown */}
- {/* ------------------------------------------- */}
-
-
- );
-};
-
-export default Notifications;
diff --git a/frontend/src/app/(app)/layout/vertical/header/Profile.tsx b/frontend/src/app/(app)/layout/vertical/header/Profile.tsx
index 6805748..44fe683 100644
--- a/frontend/src/app/(app)/layout/vertical/header/Profile.tsx
+++ b/frontend/src/app/(app)/layout/vertical/header/Profile.tsx
@@ -45,7 +45,7 @@ const Profile = () => {