feat(ui): metrikleri odaklanma ve gezinme durumunda yenile

Metriklerin güncel kalması için pencere odaklanıldığında ve sayfa
gezinildiğinde verilerin yeniden yüklenmesi eklendi. Backend deployment
servisinde tip tanımları güncellendi.
This commit is contained in:
2026-02-02 19:03:41 +00:00
parent 003ddfcbd1
commit a117275efe
4 changed files with 37 additions and 5 deletions

View File

@@ -88,6 +88,10 @@ router.get("/env-examples", async (req, res) => {
router.get("/metrics/summary", async (req, res) => {
authMiddleware(req, res, async () => {
const deploymentCount = await DeploymentProject.countDocuments();
if (deploymentCount === 0) {
await deploymentService.bootstrapFromFilesystem();
}
const since = new Date();
since.setDate(since.getDate() - 7);

View File

@@ -30,6 +30,10 @@ router.get("/", async (_req, res) => {
});
router.get("/metrics/summary", async (_req, res) => {
const jobCount = await Job.countDocuments();
if (jobCount === 0) {
await jobService.bootstrapFromFilesystem();
}
const since = new Date();
since.setDate(since.getDate() - 7);

View File

@@ -385,7 +385,7 @@ class DeploymentService {
this.io.except(`deployment:${deploymentId}`).emit("deployment:log", { deploymentId, line });
}
private emitRun(deploymentId: string, run: DeploymentRun) {
private emitRun(deploymentId: string, run: DeploymentRunDocument) {
if (!this.io) return;
this.io.to(`deployment:${deploymentId}`).emit("deployment:run", {
deploymentId,

View File

@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import {
Line,
LineChart,
@@ -18,6 +18,7 @@ import { JobStatusBadge } from "../components/JobStatusBadge";
import { RepoIcon } from "../components/RepoIcon";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faClockRotateLeft, faListCheck, faFlaskVial, faRocket } from "@fortawesome/free-solid-svg-icons";
import { useAuth } from "../providers/auth-provider";
function formatDuration(ms?: number) {
if (!ms || Number.isNaN(ms)) return "-";
@@ -41,9 +42,14 @@ export function HomePage() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const { jobStreams } = useLiveData();
const { token } = useAuth();
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const loadMetrics = useCallback(() => {
if (!token) return;
setLoading(true);
setError(null);
Promise.allSettled([fetchJobMetrics(), fetchDeploymentMetrics()])
.then(([jobResult, deployResult]) => {
if (jobResult.status === "fulfilled") {
@@ -65,7 +71,25 @@ export function HomePage() {
}
})
.finally(() => setLoading(false));
}, []);
}, [token]);
useEffect(() => {
loadMetrics();
}, [loadMetrics, location.key]);
useEffect(() => {
const handleFocus = () => {
if (document.visibilityState === "visible") {
loadMetrics();
}
};
window.addEventListener("focus", handleFocus);
document.addEventListener("visibilitychange", handleFocus);
return () => {
window.removeEventListener("focus", handleFocus);
document.removeEventListener("visibilitychange", handleFocus);
};
}, [loadMetrics]);
const chartData = useMemo(() => {
if (!metrics) {