@@ -38,14 +38,22 @@ import { useFeatureFlags } from '@/context/FeatureFlagsContext';
3838import { useAlerts } from '@/context/AlertContext' ;
3939import { useSideDrawer } from '@/context/SideDrawerContext' ;
4040import ThemePreference from '@/components/ThemePreference/ThemePreference' ;
41+ import DevFlagsBanner from '@/components/Banner/DevFlagsBanner' ;
4142import HelpDropdown from './HelpDropdown/HelpDropdown' ;
4243import UserMenu from './UserMenu/UserMenu' ;
4344
4445import '../styles/globals.scss' ;
4546
47+ export enum FeaturePages {
48+ Skill = 'Skill' ,
49+ Playground = 'Playground' ,
50+ Experimental = 'Experimental'
51+ }
52+
4653interface IAppLayout {
4754 children : React . ReactNode ;
4855 className ?: string ;
56+ requiredFeature ?: FeaturePages ;
4957}
5058
5159type Route = {
@@ -59,25 +67,57 @@ const isRouteActive = (pathname: string, route: Route) => {
5967 return pathname . startsWith ( route . path ) || route . altPaths ?. some ( ( altPath ) => pathname . startsWith ( altPath ) ) ;
6068} ;
6169
62- const AppLayout : React . FunctionComponent < IAppLayout > = ( { children, className } ) => {
70+ const AppLayout : React . FunctionComponent < IAppLayout > = ( { children, className, requiredFeature } ) => {
71+ const router = useRouter ( ) ;
72+ const pathname = usePathname ( ) ;
6373 const { data : session , status } = useSession ( ) ;
6474 const {
6575 loaded,
66- featureFlags : { playgroundFeaturesEnabled, experimentalFeaturesEnabled }
76+ featureFlags : { playgroundFeaturesEnabled, experimentalFeaturesEnabled, skillFeaturesEnabled }
6777 } = useFeatureFlags ( ) ;
6878 const { alerts, removeAlert } = useAlerts ( ) ;
6979 const sideDrawerContext = useSideDrawer ( ) ;
7080
71- const router = useRouter ( ) ;
72- const pathname = usePathname ( ) ;
73-
7481 React . useEffect ( ( ) => {
7582 if ( status === 'loading' ) return ; // Do nothing while loading
7683 if ( ! session && pathname !== '/login' ) {
7784 router . push ( '/login' ) ; // Redirect if not authenticated and not already on login page
7885 }
7986 } , [ session , status , pathname , router ] ) ;
8087
88+ const routes = React . useMemo (
89+ ( ) =>
90+ [
91+ { path : '/dashboard' , altPaths : [ '/contribute' ] , label : 'My contributions' } ,
92+ { path : '/documents' , label : 'Documents' } ,
93+ ...( playgroundFeaturesEnabled
94+ ? [
95+ {
96+ path : '/playground' ,
97+ label : 'Playground' ,
98+ children : [
99+ { path : '/playground/chat' , label : 'Chat with a model' } ,
100+ { path : '/playground/endpoints' , label : 'Custom model endpoints' }
101+ ]
102+ }
103+ ]
104+ : [ ] ) ,
105+ ...( experimentalFeaturesEnabled
106+ ? [
107+ {
108+ path : '/experimental' ,
109+ label : 'Experimental features' ,
110+ children : [
111+ { path : '/experimental/fine-tune' , label : 'Fine-tuning' } ,
112+ { path : '/experimental/chat-eval' , label : 'Model chat eval' }
113+ ]
114+ }
115+ ]
116+ : [ ] )
117+ ] . filter ( Boolean ) as Route [ ] ,
118+ [ experimentalFeaturesEnabled , playgroundFeaturesEnabled ]
119+ ) ;
120+
81121 if ( ! loaded || status === 'loading' ) {
82122 return (
83123 < Bullseye >
@@ -90,34 +130,17 @@ const AppLayout: React.FunctionComponent<IAppLayout> = ({ children, className })
90130 return null ; // Return nothing if not authenticated to avoid flicker
91131 }
92132
93- const routes = [
94- { path : '/dashboard' , altPaths : [ '/contribute' ] , label : 'My contributions' } ,
95- { path : '/documents' , label : 'Documents' } ,
96- ...( playgroundFeaturesEnabled
97- ? [
98- {
99- path : '/playground' ,
100- label : 'Playground' ,
101- children : [
102- { path : '/playground/chat' , label : 'Chat with a model' } ,
103- { path : '/playground/endpoints' , label : 'Custom model endpoints' }
104- ]
105- }
106- ]
107- : [ ] ) ,
108- ...( experimentalFeaturesEnabled
109- ? [
110- {
111- path : '/experimental' ,
112- label : 'Experimental features' ,
113- children : [
114- { path : '/experimental/fine-tune' , label : 'Fine-tuning' } ,
115- { path : '/experimental/chat-eval' , label : 'Model chat eval' }
116- ]
117- }
118- ]
119- : [ ] )
120- ] . filter ( Boolean ) as Route [ ] ;
133+ if ( requiredFeature ) {
134+ const featureEnabled =
135+ ( requiredFeature === FeaturePages . Playground && playgroundFeaturesEnabled ) ||
136+ ( requiredFeature === FeaturePages . Experimental && experimentalFeaturesEnabled ) ||
137+ ( requiredFeature === FeaturePages . Skill && skillFeaturesEnabled ) ;
138+
139+ if ( ! featureEnabled ) {
140+ router . push ( '/404' ) ;
141+ return null ;
142+ }
143+ }
121144
122145 const Header = (
123146 < Masthead >
@@ -200,6 +223,7 @@ const AppLayout: React.FunctionComponent<IAppLayout> = ({ children, className })
200223 skipToContent = { PageSkipToContent }
201224 isContentFilled
202225 >
226+ < DevFlagsBanner />
203227 { children }
204228 < AlertGroup isToast isLiveRegion >
205229 { alerts . map ( ( alert ) => (
0 commit comments