mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-05 14:05:30 +02:00
Replace permanent (301) redirects with temporary (302) redirects across all pages that check authentication state in getServerSideProps. Permanent redirects are cached by the browser indefinitely, causing a bug where users had to manually refresh after login: the browser would cache the unauthenticated redirect (dashboard → login page) and replay it even after a successful login, preventing navigation to the dashboard. Fixes #4220
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 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: false,
|
|
destination: "/",
|
|
},
|
|
};
|
|
}
|
|
|
|
const canView = await hasPermission(
|
|
{
|
|
user: { id: user.id },
|
|
session: { activeOrganizationId: session?.activeOrganizationId || "" },
|
|
},
|
|
{ deployment: ["read"] },
|
|
);
|
|
|
|
if (!canView) {
|
|
return {
|
|
redirect: {
|
|
permanent: false,
|
|
destination: "/dashboard/home",
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
props: {},
|
|
};
|
|
}
|