@@ -24,6 +24,7 @@ import {
2424 LogIn ,
2525 type LucideIcon ,
2626 Package ,
27+ Palette ,
2728 PieChart ,
2829 Rocket ,
2930 Server ,
@@ -422,6 +423,14 @@ const MENU: Menu = {
422423 isEnabled : ( { auth } ) =>
423424 ! ! ( auth ?. role === "owner" || auth ?. role === "admin" ) ,
424425 } ,
426+ {
427+ isSingle : true ,
428+ title : "Whitelabeling" ,
429+ url : "/dashboard/settings/whitelabeling" ,
430+ icon : Palette ,
431+ // Only enabled for owners in non-cloud environments (enterprise)
432+ isEnabled : ( { auth, isCloud } ) => ! ! ( auth ?. role === "owner" && ! isCloud ) ,
433+ } ,
425434 ] ,
426435
427436 help : [
@@ -445,38 +454,39 @@ const MENU: Menu = {
445454function createMenuForAuthUser ( opts : {
446455 auth ?: AuthQueryOutput ;
447456 isCloud : boolean ;
457+ whitelabeling ?: {
458+ docsUrl ?: string | null ;
459+ supportUrl ?: string | null ;
460+ } | null ;
448461} ) : Menu {
449- return {
450- // Filter the home items based on the user's role and permissions
451- // Calls the `isEnabled` function if it exists to determine if the item should be displayed
452- home : MENU . home . filter ( ( item ) =>
453- ! item . isEnabled
454- ? true
455- : item . isEnabled ( {
456- auth : opts . auth ,
457- isCloud : opts . isCloud ,
458- } ) ,
459- ) ,
460- // Filter the settings items based on the user's role and permissions
461- // Calls the `isEnabled` function if it exists to determine if the item should be displayed
462- settings : MENU . settings . filter ( ( item ) =>
463- ! item . isEnabled
464- ? true
465- : item . isEnabled ( {
466- auth : opts . auth ,
467- isCloud : opts . isCloud ,
468- } ) ,
469- ) ,
470- // Filter the help items based on the user's role and permissions
471- // Calls the `isEnabled` function if it exists to determine if the item should be displayed
472- help : MENU . help . filter ( ( item ) =>
462+ const filterEnabled = <
463+ T extends {
464+ isEnabled ?: ( o : { auth ?: AuthQueryOutput ; isCloud : boolean } ) => boolean ;
465+ } ,
466+ > (
467+ items : readonly T [ ] ,
468+ ) : T [ ] =>
469+ items . filter ( ( item ) =>
473470 ! item . isEnabled
474471 ? true
475- : item . isEnabled ( {
476- auth : opts . auth ,
477- isCloud : opts . isCloud ,
478- } ) ,
479- ) ,
472+ : item . isEnabled ( { auth : opts . auth , isCloud : opts . isCloud } ) ,
473+ ) as T [ ] ;
474+
475+ // Apply whitelabeling URL overrides to help items
476+ const helpItems = filterEnabled ( MENU . help ) . map ( ( item ) => {
477+ if ( opts . whitelabeling ?. docsUrl && item . name === "Documentation" ) {
478+ return { ...item , url : opts . whitelabeling . docsUrl } ;
479+ }
480+ if ( opts . whitelabeling ?. supportUrl && item . name === "Support" ) {
481+ return { ...item , url : opts . whitelabeling . supportUrl } ;
482+ }
483+ return item ;
484+ } ) ;
485+
486+ return {
487+ home : filterEnabled ( MENU . home ) ,
488+ settings : filterEnabled ( MENU . settings ) ,
489+ help : helpItems ,
480490 } ;
481491}
482492
@@ -885,6 +895,10 @@ export default function Page({ children }: Props) {
885895 const pathname = usePathname ( ) ;
886896 const { data : auth } = api . user . get . useQuery ( ) ;
887897 const { data : dokployVersion } = api . settings . getDokployVersion . useQuery ( ) ;
898+ const { data : whitelabeling } = api . whitelabeling . get . useQuery ( undefined , {
899+ staleTime : 5 * 60 * 1000 ,
900+ refetchOnWindowFocus : false ,
901+ } ) ;
888902
889903 const includesProjects = pathname ?. includes ( "/dashboard/project" ) ;
890904 const { data : isCloud } = api . settings . isCloud . useQuery ( ) ;
@@ -893,7 +907,7 @@ export default function Page({ children }: Props) {
893907 home : filteredHome ,
894908 settings : filteredSettings ,
895909 help,
896- } = createMenuForAuthUser ( { auth, isCloud : ! ! isCloud } ) ;
910+ } = createMenuForAuthUser ( { auth, isCloud : ! ! isCloud , whitelabeling } ) ;
897911
898912 const activeItem = findActiveNavItem (
899913 [ ...filteredHome , ...filteredSettings ] ,
@@ -1141,6 +1155,11 @@ export default function Page({ children }: Props) {
11411155 < SidebarMenuItem >
11421156 < UserNav />
11431157 </ SidebarMenuItem >
1158+ { whitelabeling ?. footerText && (
1159+ < div className = "px-3 text-xs text-muted-foreground text-center group-data-[collapsible=icon]:hidden" >
1160+ { whitelabeling . footerText }
1161+ </ div >
1162+ ) }
11441163 { dokployVersion && (
11451164 < >
11461165 < div className = "px-3 text-xs text-muted-foreground text-center group-data-[collapsible=icon]:hidden" >
0 commit comments