diff --git a/apps/dokploy/components/dashboard/swarm/monitoring-card.tsx b/apps/dokploy/components/dashboard/swarm/monitoring-card.tsx index 9c6d196ad..01ee03e80 100644 --- a/apps/dokploy/components/dashboard/swarm/monitoring-card.tsx +++ b/apps/dokploy/components/dashboard/swarm/monitoring-card.tsx @@ -27,50 +27,16 @@ export default function SwarmMonitorCard({ serverId }: Props) { serverId, }); - if (isPending) { - return ( -
-
- {/*
*/} - -
- Loading... - -
- {/*
*/} -
-
- ); - } - - if (!nodes) { - return ( -
-
-
- Failed to load data -
-
-
- ); - } - - const totalNodes = nodes.length; - const activeNodesCount = nodes.filter( - (node) => node.Status === "Ready", - ).length; - const managerNodesCount = nodes.filter( - (node) => - node.ManagerStatus === "Leader" || node.ManagerStatus === "Reachable", - ).length; - const activeNodes = nodes.filter((node) => node.Status === "Ready"); - const managerNodes = nodes.filter( - (node) => - node.ManagerStatus === "Leader" || node.ManagerStatus === "Reachable", - ); + const totalNodes = nodes?.length ?? 0; + const activeNodes = nodes?.filter((node) => node.Status === "Ready") ?? []; + const managerNodes = + nodes?.filter( + (node) => + node.ManagerStatus === "Leader" || node.ManagerStatus === "Reachable", + ) ?? []; return ( - +
@@ -94,93 +60,114 @@ export default function SwarmMonitorCard({ serverId }: Props) { )}
-
- - - Total Nodes -
- -
-
- -
{totalNodes}
-
-
+ {isPending ? ( +
+ Loading... + +
+ ) : !nodes ? ( +
+ Failed to load data +
+ ) : ( + <> +
+ + + + Total Nodes + +
+ +
+
+ +
{totalNodes}
+
+
- - -
- - Active Nodes - - Online -
-
- -
-
- - - - -
- {activeNodesCount} / {totalNodes} -
-
- -
- {activeNodes.map((node) => ( -
- {node.Hostname} + + +
+ + Active Nodes + + Online +
+
+ +
+
+ + + + +
+ {activeNodes.length} / {totalNodes}
- ))} -
- - - - - - - - -
- - Manager Nodes - - Online -
-
- -
-
- - - - -
- {managerNodesCount} / {totalNodes} -
-
- -
- {managerNodes.map((node) => ( -
- {node.Hostname} + + +
+ {activeNodes.map((node) => ( +
+ {node.Hostname} +
+ ))}
- ))} -
- - - - - -
+
+
+
+
+
-
- {nodes.map((node) => ( - - ))} -
+ + +
+ + Manager Nodes + + Online +
+
+ +
+
+ + + + +
+ {managerNodes.length} / {totalNodes} +
+
+ +
+ {managerNodes.map((node) => ( +
+ {node.Hostname} +
+ ))} +
+
+
+
+
+
+
+ +
+ {nodes.map((node) => ( + + ))} +
+ + )}
); diff --git a/apps/dokploy/components/layouts/side.tsx b/apps/dokploy/components/layouts/side.tsx index e58256c63..3cb9e29a6 100644 --- a/apps/dokploy/components/layouts/side.tsx +++ b/apps/dokploy/components/layouts/side.tsx @@ -25,10 +25,8 @@ import { Loader2, LogIn, type LucideIcon, - Network, Package, Palette, - PieChart, Rocket, Server, ShieldCheck, @@ -202,28 +200,6 @@ const MENU: Menu = { // Only enabled for users with access to Docker isEnabled: ({ permissions }) => !!permissions?.docker.read, }, - { - isSingle: true, - title: "Swarm", - url: "/dashboard/swarm", - icon: PieChart, - // Only enabled for users with access to Docker - isEnabled: ({ permissions }) => !!permissions?.docker.read, - }, - { - isSingle: true, - title: "Networks", - url: "/dashboard/networks", - icon: Network, - // Only enabled for admins and users with access to Docker in non-cloud environments - isEnabled: ({ auth, isCloud }) => - !!( - (auth?.role === "owner" || - auth?.role === "admin" || - auth?.canAccessToDocker) && - !isCloud - ), - }, { isSingle: true, title: "Requests", diff --git a/apps/dokploy/pages/dashboard/docker.tsx b/apps/dokploy/pages/dashboard/docker.tsx index df1b2e5ed..11605d963 100644 --- a/apps/dokploy/pages/dashboard/docker.tsx +++ b/apps/dokploy/pages/dashboard/docker.tsx @@ -1,17 +1,79 @@ import { validateRequest } from "@dokploy/server/lib/auth"; import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; +import { useRouter } from "next/router"; import type { ReactElement } from "react"; import superjson from "superjson"; import { ShowContainers } from "@/components/dashboard/docker/show/show-containers"; +import { ShowNetworks } from "@/components/dashboard/networks/show-networks"; +import { ShowSwarmContainers } from "@/components/dashboard/swarm/containers/show-swarm-containers"; +import SwarmMonitorCard from "@/components/dashboard/swarm/monitoring-card"; import { DashboardLayout } from "@/components/layouts/dashboard-layout"; import { ServerFilter } from "@/components/shared/server-filter"; +import { Card } from "@/components/ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { appRouter } from "@/server/api/root"; +import { api } from "@/utils/api"; + +const DEFAULT_TAB = "containers"; const Dashboard = () => { + const router = useRouter(); + const { data: isCloud } = api.settings.isCloud.useQuery(); + + const queryTab = + typeof router.query.tab === "string" ? router.query.tab : DEFAULT_TAB; + const activeTab = isCloud && queryTab === "networks" ? DEFAULT_TAB : queryTab; + + const setTab = (value: string) => { + const { tab: _current, ...query } = router.query; + router.replace( + { + pathname: router.pathname, + query: value === DEFAULT_TAB ? query : { ...query, tab: value }, + }, + undefined, + { shallow: true }, + ); + }; + return ( - {(serverId) => } + {(serverId) => ( + + + Containers + Swarm + {!isCloud && Networks} + + + + + + + + Overview + Containers + + + + + + +
+ +
+
+
+
+
+ {!isCloud && ( + + + + )} +
+ )}
); }; diff --git a/apps/dokploy/pages/dashboard/networks.tsx b/apps/dokploy/pages/dashboard/networks.tsx index cf11fcd3d..f19de36ad 100644 --- a/apps/dokploy/pages/dashboard/networks.tsx +++ b/apps/dokploy/pages/dashboard/networks.tsx @@ -1,89 +1,21 @@ -import { IS_CLOUD } from "@dokploy/server/constants"; -import { validateRequest } from "@dokploy/server/lib/auth"; -import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import type { ReactElement } from "react"; -import superjson from "superjson"; -import { ShowNetworks } from "@/components/dashboard/networks/show-networks"; -import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { ServerFilter } from "@/components/shared/server-filter"; -import { appRouter } from "@/server/api/root"; -const Dashboard = () => { - return ( - - {(serverId) => } - - ); +const Networks = () => { + return null; }; -export default Dashboard; +export default Networks; -Dashboard.getLayout = (page: ReactElement) => { - return {page}; -}; +export async function getServerSideProps(ctx: GetServerSidePropsContext) { + const serverId = + typeof ctx.query.serverId === "string" ? ctx.query.serverId : undefined; -export async function getServerSideProps( - ctx: GetServerSidePropsContext<{ serviceId: string }>, -) { - if (IS_CLOUD) { - return { - redirect: { - permanent: true, - destination: "/dashboard/projects", - }, - }; - } - const { user, session } = await validateRequest(ctx.req); - if (!user) { - return { - redirect: { - permanent: true, - destination: "/", - }, - }; - } - const { req } = ctx; - - const helpers = createServerSideHelpers({ - router: appRouter, - ctx: { - req: req as any, - res: ctx.res as any, - db: null as any, - session: session as any, - user: user as any, + return { + redirect: { + permanent: false, + destination: `/dashboard/docker?tab=networks${ + serverId ? `&serverId=${encodeURIComponent(serverId)}` : "" + }`, }, - transformer: superjson, - }); - try { - await helpers.project.all.prefetch(); - - if (user.role === "member") { - const userR = await helpers.user.one.fetch({ - userId: user.id, - }); - - if (!userR?.canAccessToDocker) { - return { - redirect: { - permanent: true, - destination: "/", - }, - }; - } - } - - await helpers.network.all.prefetch({}); - - return { - props: { - trpcState: helpers.dehydrate(), - }, - }; - } catch { - return { - props: {}, - }; - } + }; } diff --git a/apps/dokploy/pages/dashboard/swarm.tsx b/apps/dokploy/pages/dashboard/swarm.tsx index 77fc2b309..03e34da45 100644 --- a/apps/dokploy/pages/dashboard/swarm.tsx +++ b/apps/dokploy/pages/dashboard/swarm.tsx @@ -1,94 +1,21 @@ -import { validateRequest } from "@dokploy/server/lib/auth"; -import { createServerSideHelpers } from "@trpc/react-query/server"; import type { GetServerSidePropsContext } from "next"; -import type { ReactElement } from "react"; -import superjson from "superjson"; -import { ShowSwarmContainers } from "@/components/dashboard/swarm/containers/show-swarm-containers"; -import SwarmMonitorCard from "@/components/dashboard/swarm/monitoring-card"; -import { DashboardLayout } from "@/components/layouts/dashboard-layout"; -import { ServerFilter } from "@/components/shared/server-filter"; -import { Card } from "@/components/ui/card"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { appRouter } from "@/server/api/root"; -const Dashboard = () => { - return ( - - {(serverId) => ( -
- - - Overview - Containers - - - - - - -
- -
-
-
-
-
- )} -
- ); +const Swarm = () => { + return null; }; -export default Dashboard; +export default Swarm; -Dashboard.getLayout = (page: ReactElement) => { - return {page}; -}; -export async function getServerSideProps( - ctx: GetServerSidePropsContext<{ serviceId: string }>, -) { - const { user, session } = await validateRequest(ctx.req); - if (!user) { - return { - redirect: { - permanent: false, - destination: "/", - }, - }; - } - const { req, res } = ctx; +export async function getServerSideProps(ctx: GetServerSidePropsContext) { + const serverId = + typeof ctx.query.serverId === "string" ? ctx.query.serverId : undefined; - const helpers = createServerSideHelpers({ - router: appRouter, - ctx: { - req: req as any, - res: res as any, - db: null as any, - session: session as any, - user: user as any, + return { + redirect: { + permanent: false, + destination: `/dashboard/docker?tab=swarm${ + serverId ? `&serverId=${encodeURIComponent(serverId)}` : "" + }`, }, - transformer: superjson, - }); - try { - await helpers.project.all.prefetch(); - - const userPermissions = await helpers.user.getPermissions.fetch(); - - if (!userPermissions?.docker.read) { - return { - redirect: { - permanent: false, - destination: "/", - }, - }; - } - return { - props: { - trpcState: helpers.dehydrate(), - }, - }; - } catch { - return { - props: {}, - }; - } + }; }