From 6204415dc54631e38a22826da7c9171f8ac6aad5 Mon Sep 17 00:00:00 2001
From: Shivam Gupta <9.shivamgupta.6@gmail.com>
Date: Sun, 9 Aug 2026 01:01:41 +0530
Subject: [PATCH 1/3] fix: honour metaName for page titles and show a loading
state in requests
Two cases where the UI silently did nothing:
- DashboardLayout declared a `metaName` prop and 18 settings pages pass
it, but the component only destructured `children`, so the value was
discarded. None of those pages render their own
either, so every
settings page fell back to the default title from _app. The layout now
renders a , using the whitelabeling app name so the suffix is
correct on rebranded instances.
- The requests table's fallback cell only rendered its message when
`statsLogs?.data.length === 0`. While the query is in flight statsLogs
is undefined, so that guard is false and the cell rendered nothing at
all -- a blank panel, indistinguishable from a broken page. The query's
isLoading flag wasn't even destructured. It now shows a spinner, matching
the queue and deployments tables.
---
.../dashboard/requests/requests-table.tsx | 10 ++++++++--
.../dokploy/components/layouts/dashboard-layout.tsx | 13 ++++++++++++-
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/apps/dokploy/components/dashboard/requests/requests-table.tsx b/apps/dokploy/components/dashboard/requests/requests-table.tsx
index 802b60e46..63f674e6c 100644
--- a/apps/dokploy/components/dashboard/requests/requests-table.tsx
+++ b/apps/dokploy/components/dashboard/requests/requests-table.tsx
@@ -17,6 +17,7 @@ import {
Download,
Globe,
InfoIcon,
+ Loader2,
Server,
TrendingUpIcon,
} from "lucide-react";
@@ -100,7 +101,7 @@ export const RequestsTable = ({ dateRange }: RequestsTableProps) => {
pageSize: 10,
});
- const { data: statsLogs } = api.settings.readStatsLogs.useQuery(
+ const { data: statsLogs, isLoading } = api.settings.readStatsLogs.useQuery(
{
sort: sorting[0],
page: pagination,
@@ -273,7 +274,12 @@ export const RequestsTable = ({ dateRange }: RequestsTableProps) => {
colSpan={columns.length}
className="h-24 text-center"
>
- {statsLogs?.data.length === 0 && (
+ {isLoading ? (
+
+
+ Loading requests...
+
+ ) : (
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 && (
<>
From 7e9b77e93f9bae7a5dd8d156066339d55614dd6b Mon Sep 17 00:00:00 2001
From: Shivam Gupta <9.shivamgupta.6@gmail.com>
Date: Mon, 31 Aug 2026 22:47:37 +0530
Subject: [PATCH 2/3] fix: surface the error state instead of "No results."
when the log query fails
The loading branch added in the previous commit split the fallback cell
two ways: spinner while in flight, "No results." otherwise. That second
branch also catches the failure case -- when readStatsLogs errors,
statsLogs stays undefined and isLoading goes false, so a failed request
renders as a successful empty response.
The query's isError/error were not destructured. The cell now branches
three ways and reports the error through AlertBlock, matching how
ShowTraefikSystem surfaces a failed readDirectories query.
---
.../dashboard/requests/requests-table.tsx | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/apps/dokploy/components/dashboard/requests/requests-table.tsx b/apps/dokploy/components/dashboard/requests/requests-table.tsx
index 63f674e6c..1e496a68b 100644
--- a/apps/dokploy/components/dashboard/requests/requests-table.tsx
+++ b/apps/dokploy/components/dashboard/requests/requests-table.tsx
@@ -23,6 +23,7 @@ import {
} 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 {
@@ -101,7 +102,12 @@ export const RequestsTable = ({ dateRange }: RequestsTableProps) => {
pageSize: 10,
});
- const { data: statsLogs, isLoading } = api.settings.readStatsLogs.useQuery(
+ const {
+ data: statsLogs,
+ isLoading,
+ isError,
+ error,
+ } = api.settings.readStatsLogs.useQuery(
{
sort: sorting[0],
page: pagination,
@@ -279,6 +285,12 @@ export const RequestsTable = ({ dateRange }: RequestsTableProps) => {
Loading requests...
+ ) : isError ? (
+
) : (
From 880bb55272bf35b3752955187a914d4f704eef70 Mon Sep 17 00:00:00 2001
From: Narciso
Date: Mon, 31 Aug 2026 16:42:26 -0400
Subject: [PATCH 3/3] fix failing test
---
.../__test__/setup/monitoring-setup.real.test.ts | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
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);