mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-15 20:25:23 +02:00
- Introduced new test files for permission checks, including `check-permission.test.ts`, `enterprise-only-resources.test.ts`, `resolve-permissions.test.ts`, and `service-access.test.ts`. - Implemented permission checks in various components to ensure actions are gated by user permissions, including `ShowTraefikConfig`, `UpdateTraefikConfig`, `ShowVolumes`, `ShowDomains`, and others. - Enhanced the logic for displaying UI elements based on user permissions, ensuring that only authorized users can access or modify resources.
114 lines
3.1 KiB
TypeScript
114 lines
3.1 KiB
TypeScript
import { validateRequest } from "@dokploy/server/lib/auth";
|
|
import { hasPermission } from "@dokploy/server/services/permission";
|
|
import { Rocket } from "lucide-react";
|
|
import type { GetServerSidePropsContext } from "next";
|
|
import { useRouter } from "next/router";
|
|
import type { ReactElement } from "react";
|
|
import { ShowDeploymentsTable } from "@/components/dashboard/deployments/show-deployments-table";
|
|
import { ShowQueueTable } from "@/components/dashboard/deployments/show-queue-table";
|
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
|
import {
|
|
Card,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
|
|
const TAB_VALUES = ["deployments", "queue"] as const;
|
|
type TabValue = (typeof TAB_VALUES)[number];
|
|
|
|
function isValidTab(t: string): t is TabValue {
|
|
return TAB_VALUES.includes(t as TabValue);
|
|
}
|
|
|
|
function DeploymentsPage() {
|
|
const router = useRouter();
|
|
const tab =
|
|
router.query.tab && isValidTab(router.query.tab as string)
|
|
? (router.query.tab as TabValue)
|
|
: "deployments";
|
|
|
|
const setTab = (value: string) => {
|
|
if (!isValidTab(value)) return;
|
|
router.replace(
|
|
{ pathname: "/dashboard/deployments", query: { tab: value } },
|
|
undefined,
|
|
{ shallow: true },
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className="w-full">
|
|
<Card className="h-full bg-sidebar p-2.5 rounded-xl max-w-8xl mx-auto min-h-[45vh]">
|
|
<div className="rounded-xl bg-background shadow-md h-full">
|
|
<CardHeader>
|
|
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
|
|
<div>
|
|
<CardTitle className="text-xl font-bold flex items-center gap-2">
|
|
<Rocket className="size-5" />
|
|
Deployments
|
|
</CardTitle>
|
|
<CardDescription>
|
|
All application and compose deployments in one place.
|
|
</CardDescription>
|
|
</div>
|
|
</div>
|
|
<Tabs value={tab} onValueChange={setTab} className="w-full">
|
|
<TabsList className="mt-2">
|
|
<TabsTrigger value="deployments">Deployments</TabsTrigger>
|
|
<TabsTrigger value="queue">Queue</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="deployments" className="mt-0 pt-4">
|
|
<ShowDeploymentsTable />
|
|
</TabsContent>
|
|
<TabsContent value="queue" className="mt-0 pt-4">
|
|
<ShowQueueTable />
|
|
</TabsContent>
|
|
</Tabs>
|
|
</CardHeader>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default DeploymentsPage;
|
|
|
|
DeploymentsPage.getLayout = (page: ReactElement) => {
|
|
return <DashboardLayout>{page}</DashboardLayout>;
|
|
};
|
|
|
|
export async function getServerSideProps(ctx: GetServerSidePropsContext) {
|
|
const { user, session } = await validateRequest(ctx.req);
|
|
if (!user) {
|
|
return {
|
|
redirect: {
|
|
permanent: true,
|
|
destination: "/",
|
|
},
|
|
};
|
|
}
|
|
|
|
const canView = await hasPermission(
|
|
{
|
|
user: { id: user.id },
|
|
session: { activeOrganizationId: session?.activeOrganizationId || "" },
|
|
},
|
|
{ deployment: ["read"] },
|
|
);
|
|
|
|
if (!canView) {
|
|
return {
|
|
redirect: {
|
|
permanent: false,
|
|
destination: "/dashboard/projects",
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
props: {},
|
|
};
|
|
}
|