diff --git a/apps/dokploy/__test__/setup/monitoring-setup.real.test.ts b/apps/dokploy/__test__/setup/monitoring-setup.real.test.ts index d16a75a40..89b8b390d 100644 --- a/apps/dokploy/__test__/setup/monitoring-setup.real.test.ts +++ b/apps/dokploy/__test__/setup/monitoring-setup.real.test.ts @@ -64,6 +64,21 @@ const serviceExists = async (name: string) => { } }; +// Swarm keeps converging a service for a bit after it's created (scheduling +// tasks, resolving endpoints), which bumps Version.Index on its own. Calling +// setupMonitoring again before that settles races that internal bump, so wait +// for two consecutive reads to agree before treating the service as stable. +const waitForServiceConvergence = async (name: string, timeoutMs = 5000) => { + const deadline = Date.now() + timeoutMs; + let lastIndex: string | null = null; + while (Date.now() < deadline) { + const inspect = await docker.getService(name).inspect(); + if (inspect.Version.Index === lastIndex) return; + lastIndex = inspect.Version.Index; + await new Promise((resolve) => setTimeout(resolve, 50)); + } +}; + const swarmTaskNames = async () => { const list = await docker.listContainers({ all: true }); return list @@ -193,6 +208,7 @@ describe.skipIf(hasRealMonitoring())( expect(await containerExists(SERVICE_NAME)).toBe(false); await expect(setupMonitoring("test-server")).resolves.not.toThrow(); + await waitForServiceConvergence(SERVICE_NAME); await expect(setupMonitoring("test-server")).resolves.not.toThrow(); expect(await serviceExists(SERVICE_NAME)).toBe(true); diff --git a/apps/dokploy/components/dashboard/requests/requests-table.tsx b/apps/dokploy/components/dashboard/requests/requests-table.tsx index 802b60e46..1e496a68b 100644 --- a/apps/dokploy/components/dashboard/requests/requests-table.tsx +++ b/apps/dokploy/components/dashboard/requests/requests-table.tsx @@ -17,11 +17,13 @@ import { Download, Globe, InfoIcon, + Loader2, Server, TrendingUpIcon, } from "lucide-react"; import { useMemo, useState } from "react"; import { toast } from "sonner"; +import { AlertBlock } from "@/components/shared/alert-block"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { @@ -100,7 +102,12 @@ export const RequestsTable = ({ dateRange }: RequestsTableProps) => { pageSize: 10, }); - const { data: statsLogs } = api.settings.readStatsLogs.useQuery( + const { + data: statsLogs, + isLoading, + isError, + error, + } = api.settings.readStatsLogs.useQuery( { sort: sorting[0], page: pagination, @@ -273,7 +280,18 @@ export const RequestsTable = ({ dateRange }: RequestsTableProps) => { colSpan={columns.length} className="h-24 text-center" > - {statsLogs?.data.length === 0 && ( + {isLoading ? ( +
+ + Loading requests... +
+ ) : isError ? ( +
+ + {error?.message} + +
+ ) : (
No results. diff --git a/apps/dokploy/components/layouts/dashboard-layout.tsx b/apps/dokploy/components/layouts/dashboard-layout.tsx index 222f69b9e..77a63765b 100644 --- a/apps/dokploy/components/layouts/dashboard-layout.tsx +++ b/apps/dokploy/components/layouts/dashboard-layout.tsx @@ -1,4 +1,6 @@ +import Head from "next/head"; import { api } from "@/utils/api"; +import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling"; import { ImpersonationBar } from "../dashboard/impersonation/impersonation-bar"; import { HubSpotWidget } from "../shared/HubSpotWidget"; import Page from "./side"; @@ -8,9 +10,11 @@ interface Props { metaName?: string; } -export const DashboardLayout = ({ children }: Props) => { +export const DashboardLayout = ({ children, metaName }: Props) => { const { data: haveRootAccess } = api.user.haveRootAccess.useQuery(); const { data: isCloud } = api.settings.isCloud.useQuery(); + const { config: whitelabeling } = useWhitelabeling(); + const appName = whitelabeling?.appName || "Dokploy"; const { data: currentPlan } = api.stripe.getCurrentPlan.useQuery(undefined, { enabled: isCloud === true, refetchOnWindowFocus: false, @@ -22,6 +26,13 @@ export const DashboardLayout = ({ children }: Props) => { return ( <> + {metaName && ( + + + {metaName} | {appName} + + + )} {children} {isChatEnabled && ( <>