mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-19 22:25:22 +02:00
refactor: update whitelabeling hooks and API usage for improved access control and consistency
This commit is contained in:
@@ -45,12 +45,12 @@ import {
|
||||
import { authClient } from "@/lib/auth-client";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { api } from "@/utils/api";
|
||||
import { useWhitelabelingPublic } from "@/utils/hooks/use-whitelabeling";
|
||||
import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling";
|
||||
|
||||
type User = typeof authClient.$Infer.Session.user;
|
||||
|
||||
export const ImpersonationBar = () => {
|
||||
const { config: whitelabeling } = useWhitelabelingPublic();
|
||||
const { config: whitelabeling } = useWhitelabeling();
|
||||
const [users, setUsers] = useState<User[]>([]);
|
||||
const [selectedUser, setSelectedUser] = useState<User | null>(null);
|
||||
const [isImpersonating, setIsImpersonating] = useState(false);
|
||||
|
||||
@@ -23,8 +23,8 @@ import {
|
||||
Loader2,
|
||||
LogIn,
|
||||
type LucideIcon,
|
||||
Palette,
|
||||
Package,
|
||||
Palette,
|
||||
PieChart,
|
||||
Rocket,
|
||||
Server,
|
||||
@@ -895,10 +895,10 @@ export default function Page({ children }: Props) {
|
||||
const pathname = usePathname();
|
||||
const { data: auth } = api.user.get.useQuery();
|
||||
const { data: dokployVersion } = api.settings.getDokployVersion.useQuery();
|
||||
const { data: whitelabeling } = api.whitelabeling.getPublic.useQuery(
|
||||
undefined,
|
||||
{ staleTime: 5 * 60 * 1000, refetchOnWindowFocus: false },
|
||||
);
|
||||
const { data: whitelabeling } = api.whitelabeling.get.useQuery(undefined, {
|
||||
staleTime: 5 * 60 * 1000,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
const includesProjects = pathname?.includes("/dashboard/project");
|
||||
const { data: isCloud } = api.settings.isCloud.useQuery();
|
||||
|
||||
@@ -37,6 +37,8 @@ const formSchema = z.object({
|
||||
faviconUrl: z.string(),
|
||||
customCss: z.string(),
|
||||
loginLogoUrl: z.string(),
|
||||
supportUrl: z.string(),
|
||||
docsUrl: z.string(),
|
||||
errorPageTitle: z.string(),
|
||||
errorPageDescription: z.string(),
|
||||
metaTitle: z.string(),
|
||||
@@ -173,6 +175,8 @@ export function WhitelabelingSettings() {
|
||||
faviconUrl: "",
|
||||
customCss: "",
|
||||
loginLogoUrl: "",
|
||||
supportUrl: "",
|
||||
docsUrl: "",
|
||||
errorPageTitle: "",
|
||||
errorPageDescription: "",
|
||||
metaTitle: "",
|
||||
@@ -190,6 +194,8 @@ export function WhitelabelingSettings() {
|
||||
faviconUrl: data.faviconUrl ?? "",
|
||||
customCss: data.customCss ?? "",
|
||||
loginLogoUrl: data.loginLogoUrl ?? "",
|
||||
supportUrl: data.supportUrl ?? "",
|
||||
docsUrl: data.docsUrl ?? "",
|
||||
errorPageTitle: data.errorPageTitle ?? "",
|
||||
errorPageDescription: data.errorPageDescription ?? "",
|
||||
metaTitle: data.metaTitle ?? "",
|
||||
@@ -219,8 +225,8 @@ export function WhitelabelingSettings() {
|
||||
primaryColor: null,
|
||||
customCss: values.customCss || null,
|
||||
loginLogoUrl: values.loginLogoUrl || null,
|
||||
supportUrl: null,
|
||||
docsUrl: null,
|
||||
supportUrl: values.supportUrl || null,
|
||||
docsUrl: values.docsUrl || null,
|
||||
errorPageTitle: values.errorPageTitle || null,
|
||||
errorPageDescription: values.errorPageDescription || null,
|
||||
metaTitle: values.metaTitle || null,
|
||||
@@ -231,6 +237,7 @@ export function WhitelabelingSettings() {
|
||||
toast.success("Whitelabeling settings updated");
|
||||
await refetch();
|
||||
await utils.whitelabeling.getPublic.invalidate();
|
||||
await utils.whitelabeling.get.invalidate();
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(
|
||||
@@ -245,6 +252,7 @@ export function WhitelabelingSettings() {
|
||||
toast.success("Whitelabeling settings reset to defaults");
|
||||
await refetch();
|
||||
await utils.whitelabeling.getPublic.invalidate();
|
||||
await utils.whitelabeling.get.invalidate();
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(error?.message || "Failed to reset whitelabeling settings");
|
||||
@@ -423,9 +431,9 @@ export function WhitelabelingSettings() {
|
||||
{/* Metadata & Links Section */}
|
||||
<Card className="bg-transparent">
|
||||
<CardHeader>
|
||||
<CardTitle>Metadata</CardTitle>
|
||||
<CardTitle>Metadata & Links</CardTitle>
|
||||
<CardDescription>
|
||||
Customize the page title and footer text.
|
||||
Customize the page title, footer text, and sidebar links.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
@@ -462,6 +470,46 @@ export function WhitelabelingSettings() {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="supportUrl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Support URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="https://support.example.com"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
Custom URL for the "Support" link in the sidebar.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="docsUrl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Documentation URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="https://docs.example.com"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
Custom URL for the "Documentation" link in the sidebar.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ import {
|
||||
import { cn } from "@/lib/utils";
|
||||
import { appRouter } from "@/server/api/root";
|
||||
import { api } from "@/utils/api";
|
||||
import { useWhitelabelingPublic } from "@/utils/hooks/use-whitelabeling";
|
||||
import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling";
|
||||
|
||||
export type Services = {
|
||||
serverId?: string | null;
|
||||
@@ -371,7 +371,7 @@ const EnvironmentPage = (
|
||||
{ projectId: selectedTargetProject },
|
||||
{ enabled: !!selectedTargetProject },
|
||||
);
|
||||
const { config: whitelabeling } = useWhitelabelingPublic();
|
||||
const { config: whitelabeling } = useWhitelabeling();
|
||||
const appName = whitelabeling?.appName || "Dokploy";
|
||||
|
||||
const emptyServices =
|
||||
|
||||
@@ -56,7 +56,7 @@ import {
|
||||
import { UseKeyboardNav } from "@/hooks/use-keyboard-nav";
|
||||
import { appRouter } from "@/server/api/root";
|
||||
import { api } from "@/utils/api";
|
||||
import { useWhitelabelingPublic } from "@/utils/hooks/use-whitelabeling";
|
||||
import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling";
|
||||
|
||||
type TabState =
|
||||
| "projects"
|
||||
@@ -96,7 +96,7 @@ const Service = (
|
||||
const { data: environments } = api.environment.byProjectId.useQuery({
|
||||
projectId: data?.environment?.project?.projectId || "",
|
||||
});
|
||||
const { config: whitelabeling } = useWhitelabelingPublic();
|
||||
const { config: whitelabeling } = useWhitelabeling();
|
||||
const appName = whitelabeling?.appName || "Dokploy";
|
||||
const environmentDropdownItems =
|
||||
environments?.map((env) => ({
|
||||
|
||||
@@ -52,7 +52,7 @@ import {
|
||||
import { UseKeyboardNav } from "@/hooks/use-keyboard-nav";
|
||||
import { appRouter } from "@/server/api/root";
|
||||
import { api } from "@/utils/api";
|
||||
import { useWhitelabelingPublic } from "@/utils/hooks/use-whitelabeling";
|
||||
import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling";
|
||||
|
||||
type TabState =
|
||||
| "projects"
|
||||
@@ -85,7 +85,7 @@ const Service = (
|
||||
const { data: environments } = api.environment.byProjectId.useQuery({
|
||||
projectId: data?.environment?.projectId || "",
|
||||
});
|
||||
const { config: whitelabeling } = useWhitelabelingPublic();
|
||||
const { config: whitelabeling } = useWhitelabeling();
|
||||
const appName = whitelabeling?.appName || "Dokploy";
|
||||
const environmentDropdownItems =
|
||||
environments?.map((env) => ({
|
||||
|
||||
@@ -45,7 +45,7 @@ import { UseKeyboardNav } from "@/hooks/use-keyboard-nav";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { appRouter } from "@/server/api/root";
|
||||
import { api } from "@/utils/api";
|
||||
import { useWhitelabelingPublic } from "@/utils/hooks/use-whitelabeling";
|
||||
import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling";
|
||||
|
||||
type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced";
|
||||
|
||||
@@ -66,7 +66,7 @@ const Mariadb = (
|
||||
const { data: environments } = api.environment.byProjectId.useQuery({
|
||||
projectId: data?.environment?.projectId || "",
|
||||
});
|
||||
const { config: whitelabeling } = useWhitelabelingPublic();
|
||||
const { config: whitelabeling } = useWhitelabeling();
|
||||
const appName = whitelabeling?.appName || "Dokploy";
|
||||
const environmentDropdownItems =
|
||||
environments?.map((env) => ({
|
||||
|
||||
@@ -45,7 +45,7 @@ import { UseKeyboardNav } from "@/hooks/use-keyboard-nav";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { appRouter } from "@/server/api/root";
|
||||
import { api } from "@/utils/api";
|
||||
import { useWhitelabelingPublic } from "@/utils/hooks/use-whitelabeling";
|
||||
import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling";
|
||||
|
||||
type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced";
|
||||
|
||||
@@ -65,7 +65,7 @@ const Mongo = (
|
||||
const { data: environments } = api.environment.byProjectId.useQuery({
|
||||
projectId: data?.environment?.projectId || "",
|
||||
});
|
||||
const { config: whitelabeling } = useWhitelabelingPublic();
|
||||
const { config: whitelabeling } = useWhitelabeling();
|
||||
const appName = whitelabeling?.appName || "Dokploy";
|
||||
const environmentDropdownItems =
|
||||
environments?.map((env) => ({
|
||||
|
||||
@@ -45,7 +45,7 @@ import { UseKeyboardNav } from "@/hooks/use-keyboard-nav";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { appRouter } from "@/server/api/root";
|
||||
import { api } from "@/utils/api";
|
||||
import { useWhitelabelingPublic } from "@/utils/hooks/use-whitelabeling";
|
||||
import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling";
|
||||
|
||||
type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced";
|
||||
|
||||
@@ -64,7 +64,7 @@ const MySql = (
|
||||
const { data: environments } = api.environment.byProjectId.useQuery({
|
||||
projectId: data?.environment?.projectId || "",
|
||||
});
|
||||
const { config: whitelabeling } = useWhitelabelingPublic();
|
||||
const { config: whitelabeling } = useWhitelabeling();
|
||||
const appName = whitelabeling?.appName || "Dokploy";
|
||||
const environmentDropdownItems =
|
||||
environments?.map((env) => ({
|
||||
|
||||
@@ -45,7 +45,7 @@ import { UseKeyboardNav } from "@/hooks/use-keyboard-nav";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { appRouter } from "@/server/api/root";
|
||||
import { api } from "@/utils/api";
|
||||
import { useWhitelabelingPublic } from "@/utils/hooks/use-whitelabeling";
|
||||
import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling";
|
||||
|
||||
type TabState = "projects" | "monitoring" | "settings" | "backups" | "advanced";
|
||||
|
||||
@@ -64,7 +64,7 @@ const Postgresql = (
|
||||
const { data: environments } = api.environment.byProjectId.useQuery({
|
||||
projectId: data?.environment?.projectId || "",
|
||||
});
|
||||
const { config: whitelabeling } = useWhitelabelingPublic();
|
||||
const { config: whitelabeling } = useWhitelabeling();
|
||||
const appName = whitelabeling?.appName || "Dokploy";
|
||||
const environmentDropdownItems =
|
||||
environments?.map((env) => ({
|
||||
|
||||
@@ -44,7 +44,7 @@ import { UseKeyboardNav } from "@/hooks/use-keyboard-nav";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { appRouter } from "@/server/api/root";
|
||||
import { api } from "@/utils/api";
|
||||
import { useWhitelabelingPublic } from "@/utils/hooks/use-whitelabeling";
|
||||
import { useWhitelabeling } from "@/utils/hooks/use-whitelabeling";
|
||||
|
||||
type TabState = "projects" | "monitoring" | "settings" | "advanced";
|
||||
|
||||
@@ -64,7 +64,7 @@ const Redis = (
|
||||
const { data: environments } = api.environment.byProjectId.useQuery({
|
||||
projectId: data?.environment?.projectId || "",
|
||||
});
|
||||
const { config: whitelabeling } = useWhitelabelingPublic();
|
||||
const { config: whitelabeling } = useWhitelabeling();
|
||||
const appName = whitelabeling?.appName || "Dokploy";
|
||||
const environmentDropdownItems =
|
||||
environments?.map((env) => ({
|
||||
|
||||
@@ -8,11 +8,12 @@ import { apiUpdateWhitelabeling } from "@/server/db/schema";
|
||||
import {
|
||||
createTRPCRouter,
|
||||
enterpriseProcedure,
|
||||
protectedProcedure,
|
||||
publicProcedure,
|
||||
} from "../../trpc";
|
||||
|
||||
export const whitelabelingRouter = createTRPCRouter({
|
||||
get: enterpriseProcedure.query(async () => {
|
||||
get: protectedProcedure.query(async () => {
|
||||
if (IS_CLOUD) {
|
||||
return null;
|
||||
}
|
||||
@@ -80,13 +81,28 @@ export const whitelabelingRouter = createTRPCRouter({
|
||||
return { success: true };
|
||||
}),
|
||||
|
||||
// Public endpoint so the whitelabeling config can be applied globally
|
||||
// (including on the login page before auth)
|
||||
// Public endpoint only for unauthenticated pages (login, register, error)
|
||||
// Returns only the fields needed for public pages
|
||||
getPublic: publicProcedure.query(async () => {
|
||||
if (IS_CLOUD) {
|
||||
return null;
|
||||
}
|
||||
const settings = await getWebServerSettings();
|
||||
return settings?.whitelabelingConfig ?? null;
|
||||
const config = settings?.whitelabelingConfig;
|
||||
if (!config) return null;
|
||||
|
||||
return {
|
||||
appName: config.appName,
|
||||
appDescription: config.appDescription,
|
||||
logoUrl: config.logoUrl,
|
||||
loginLogoUrl: config.loginLogoUrl,
|
||||
faviconUrl: config.faviconUrl,
|
||||
primaryColor: config.primaryColor,
|
||||
customCss: config.customCss,
|
||||
metaTitle: config.metaTitle,
|
||||
errorPageTitle: config.errorPageTitle,
|
||||
errorPageDescription: config.errorPageDescription,
|
||||
footerText: config.footerText,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
import { api } from "@/utils/api";
|
||||
|
||||
/**
|
||||
* Hook to access whitelabeling config for authenticated pages (dashboard, services, etc.).
|
||||
* Requires the user to be logged in.
|
||||
*/
|
||||
export function useWhitelabeling() {
|
||||
const { data, ...rest } = api.whitelabeling.get.useQuery(undefined, {
|
||||
staleTime: 5 * 60 * 1000,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
return { config: data ?? null, ...rest };
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to access the public whitelabeling config.
|
||||
* Can be used on any page (including login) since it uses the public endpoint.
|
||||
* Only for unauthenticated pages (login, register, error, invitation, password reset).
|
||||
*/
|
||||
export function useWhitelabelingPublic() {
|
||||
const { data, ...rest } = api.whitelabeling.getPublic.useQuery(undefined, {
|
||||
|
||||
Reference in New Issue
Block a user