feat: 顶栏显示后端应用版本号
后端 /api/health 返回 BuildVersion(由 ldflags 注入的 main.version), 前端顶栏设置按钮左侧展示 v<版本>。
This commit is contained in:
1 parent
ff3d41ea35
commit
82c6d4a06b
4 files changed
+26
-2
No files matched your search
@@ -48,6 +48,10 @@ func main() {
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
// hand the build version to the server package so GET /api/health can report it
|
||||
// to the frontend top bar.
|
||||
server.BuildVersion = version
|
||||
|
||||
printBanner(*addr)
|
||||
|
||||
// capture backend logs into the in-memory sink (still to stderr) so the /logs
|
||||
|
||||
+6
-1
@@ -27,6 +27,11 @@ import (
|
||||
"github.com/Autumn-27/norma/transcript"
|
||||
)
|
||||
|
||||
// BuildVersion is the backend application version, injected from cmd/artex at
|
||||
// startup (which in turn gets it from -ldflags "-X main.version=<tag>").
|
||||
// Defaults to "dev" for local builds. Exposed to the frontend via GET /api/health.
|
||||
var BuildVersion = "dev"
|
||||
|
||||
// Server exposes the ARTEX backend over a JSON HTTP API for the shadcn/ui
|
||||
// frontend.
|
||||
type Server struct {
|
||||
@@ -741,7 +746,7 @@ func (s *Server) Handler() http.Handler {
|
||||
// --- handlers ---
|
||||
|
||||
func (s *Server) health(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, 200, map[string]any{"ok": true, "service": "artex"})
|
||||
writeJSON(w, 200, map[string]any{"ok": true, "service": "artex", "version": BuildVersion})
|
||||
}
|
||||
|
||||
func (s *Server) stats(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { type ReactNode, useEffect, useState } from "react";
|
||||
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { SidebarTrigger } from "@/components/ui/sidebar";
|
||||
import { api } from "@/lib/api";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useCurrentUser } from "@/hooks/use-current-user";
|
||||
|
||||
@@ -29,6 +30,14 @@ function isFullBleed(pathname: string) {
|
||||
export function MainContent({ children }: { children: ReactNode }) {
|
||||
const currentUser = useCurrentUser();
|
||||
const pathname = usePathname();
|
||||
const [version, setVersion] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
api
|
||||
.health()
|
||||
.then((h) => setVersion(h.version ?? ""))
|
||||
.catch(() => setVersion(""));
|
||||
}, []);
|
||||
|
||||
if (isFullBleed(pathname)) {
|
||||
return <>{children}</>;
|
||||
@@ -52,6 +61,9 @@ export function MainContent({ children }: { children: ReactNode }) {
|
||||
<SearchDialog />
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{version && (
|
||||
<span className="text-muted-foreground text-xs font-medium tabular-nums">版本·v{version}</span>
|
||||
)}
|
||||
<LayoutControls />
|
||||
<ThemeSwitcher />
|
||||
<AccountSwitcher users={[currentUser]} />
|
||||
|
||||
@@ -99,6 +99,9 @@ const arr = <T>(x: T[] | null | undefined): T[] => x ?? [];
|
||||
const tq = (task?: string, sep: "?" | "&" = "?") => (task ? `${sep}task=${encodeURIComponent(task)}` : "");
|
||||
|
||||
export const api = {
|
||||
// 后端应用版本号(release 时由 ldflags 注入,默认 "dev")。
|
||||
health: () => get<{ ok: boolean; service: string; version: string }>("/health"),
|
||||
|
||||
// ---- auth ----
|
||||
authStatus: () => get<{ initialized: boolean }>("/auth/status"),
|
||||
login: (username: string, password: string) =>
|
||||
|
||||
Reference in new issue
Block a user