1
0

feat: 版本管理,package.json 唯一版本源、/api/meta 返回版本、Dashboard Header 展示版本号

This commit is contained in:
2026-05-20 19:14:37 +08:00
parent f3df3a203b
commit 8eac814cc6
25 changed files with 490 additions and 20 deletions

View File

@@ -28,6 +28,7 @@ export interface BootstrapOptions {
configPath: string;
mode: RuntimeMode;
staticAssets?: StaticAssets;
version: string;
}
type BootstrapEngine = Pick<ProbeEngine, "start" | "stop">;
@@ -73,6 +74,7 @@ export async function bootstrap(options: BootstrapOptions, dependencies: Bootstr
mode: options.mode,
staticAssets: options.staticAssets,
store,
version: options.version,
});
} catch (error) {
engine?.stop();

View File

@@ -1,9 +1,11 @@
import { bootstrap } from "./bootstrap";
import { readRuntimeConfig } from "./config";
import { readAppVersion } from "./version";
async function main() {
const { configPath } = readRuntimeConfig();
await bootstrap({ configPath, mode: "development" });
const version = await readAppVersion();
await bootstrap({ configPath, mode: "development", version });
}
void main().catch((error) => {

View File

@@ -1,9 +1,11 @@
import { bootstrap } from "./bootstrap";
import { readRuntimeConfig } from "./config";
import { readAppVersion } from "./version";
async function main() {
const { configPath } = readRuntimeConfig();
await bootstrap({ configPath, mode: "production" });
const version = await readAppVersion();
await bootstrap({ configPath, mode: "production", version });
}
void main().catch((error) => {

View File

@@ -3,9 +3,10 @@ import type { MetaResponse, RuntimeMode } from "../../shared/api";
import { checkerRegistry } from "../checker/runner";
import { jsonResponse } from "../helpers";
export function handleMeta(mode: RuntimeMode): Response {
export function handleMeta(mode: RuntimeMode, version: string): Response {
const response: MetaResponse = {
checkerTypes: checkerRegistry.supportedTypes,
version,
};
return jsonResponse(response, { mode });

View File

@@ -16,10 +16,11 @@ export interface StartServerOptions {
mode: RuntimeMode;
staticAssets?: StaticAssets;
store: ProbeStore;
version: string;
}
export function startServer(options: StartServerOptions) {
const { config, mode, staticAssets, store } = options;
const { config, mode, staticAssets, store, version } = options;
const server = Bun.serve({
fetch(req) {
@@ -36,7 +37,7 @@ export function startServer(options: StartServerOptions) {
GET: (req) => handleDashboard(new URL(req.url), store, mode),
},
"/api/meta": {
GET: () => handleMeta(mode),
GET: () => handleMeta(mode, version),
},
"/api/targets/:id/history": {
GET: (req) => handleHistory(req.params.id, new URL(req.url), store, mode),

17
src/server/version.ts Normal file
View File

@@ -0,0 +1,17 @@
import { resolve } from "node:path";
import { validateVersion } from "../../scripts/bump-version-logic";
const PACKAGE_JSON_PATH = resolve(import.meta.dir, "..", "..", "package.json");
export async function readAppVersion(): Promise<string> {
const packageJson = (await Bun.file(PACKAGE_JSON_PATH).json()) as { version: string };
const version = packageJson.version;
if (typeof version !== "string") {
throw new Error("package.json does not have a valid version field");
}
validateVersion(version);
return version;
}

View File

@@ -58,6 +58,7 @@ export interface HistoryResponse {
export interface MetaResponse {
checkerTypes: string[];
version: string;
}
export interface RecentSample {

View File

@@ -6,7 +6,7 @@ import { Alert, Layout, Menu, RadioGroup, Skeleton } from "tdesign-react";
import { RefreshCountdown } from "./components/RefreshCountdown";
import { SummaryCards } from "./components/SummaryCards";
import { TargetBoard } from "./components/TargetBoard";
import { useDashboard } from "./hooks/use-queries";
import { useDashboard, useMeta } from "./hooks/use-queries";
import { useTargetDetail } from "./hooks/use-target-detail";
import { type ThemePreference, useThemePreference } from "./hooks/use-theme-preference";
@@ -46,6 +46,7 @@ export function App() {
isLoading: dashboardLoading,
refetch: refetchDashboard,
} = useDashboard(dashboardRefetchInterval);
const { data: meta } = useMeta();
const {
activeTab,
closeDrawer,
@@ -62,6 +63,7 @@ export function App() {
timeTo,
} = useTargetDetail();
const isManualRefresh = refreshInterval === 0;
const versionDisplay = meta?.version ? `v${meta.version}` : null;
const handleIntervalChange = (value: number) => {
void refetchDashboard();
@@ -80,6 +82,7 @@ export function App() {
<span className="dashboard-brand">
<span className="dashboard-logo">DiAL</span>
<span className="dashboard-subtitle"></span>
{versionDisplay && <span className="dashboard-version">{versionDisplay}</span>}
</span>
}
operations={

View File

@@ -46,6 +46,12 @@
font-weight: 400;
}
.dashboard-version {
color: var(--td-text-color-placeholder);
font-size: var(--td-font-size-body-small);
font-weight: 400;
}
.dashboard-header-controls {
display: inline-flex;
align-items: center;