8
8
useMediaQuery ,
9
9
useTheme ,
10
10
} from "@mui/material" ;
11
- import { useSession } from "next-auth/react" ;
11
+ import { signIn , useSession } from "next-auth/react" ;
12
12
import { useCallback , useEffect , useRef , useState } from "react" ;
13
13
import AISpinner from "./AISpinner" ;
14
14
import { ChatHistorySidebar } from "./TorchAgentPage/ChatHistorySidebar" ;
@@ -75,7 +75,7 @@ export const TorchAgentPage = () => {
75
75
const isMobile = useMediaQuery ( theme . breakpoints . down ( "lg" ) ) ; // Below 1200px
76
76
77
77
// Constants
78
- const typingSpeed = 30 ;
78
+ const typingSpeed = 3 ; // ms per character
79
79
const sidebarWidth = 300 ;
80
80
81
81
const featureRequestUrl =
@@ -106,6 +106,9 @@ export const TorchAgentPage = () => {
106
106
const [ error , setError ] = useState ( "" ) ;
107
107
const [ debugVisible , setDebugVisible ] = useState ( false ) ;
108
108
const [ currentSessionId , setCurrentSessionId ] = useState < string | null > ( null ) ;
109
+ const [ permissionState , setPermissionState ] = useState <
110
+ "unchecked" | "checking" | "sufficient" | "insufficient"
111
+ > ( "unchecked" ) ;
109
112
110
113
const [ chatHistory , setChatHistory ] = useState < ChatSession [ ] > ( [ ] ) ;
111
114
const [ selectedSession , setSelectedSession ] = useState < string | null > ( null ) ;
@@ -202,6 +205,38 @@ export const TorchAgentPage = () => {
202
205
}
203
206
} , [ session . data ?. user ] ) ;
204
207
208
+ const checkUserPermissions = useCallback ( async ( ) => {
209
+ if (
210
+ ! session . data ?. user ||
211
+ hasAuthCookie ( ) ||
212
+ permissionState !== "unchecked"
213
+ )
214
+ return ;
215
+
216
+ setPermissionState ( "checking" ) ;
217
+ try {
218
+ // Make a simple API call to check permissions
219
+ const response = await fetch ( "/api/torchagent-check-permissions" , {
220
+ method : "GET" ,
221
+ headers : {
222
+ "Content-Type" : "application/json" ,
223
+ } ,
224
+ } ) ;
225
+
226
+ if ( response . status === 403 ) {
227
+ setPermissionState ( "insufficient" ) ;
228
+ } else if ( ! response . ok ) {
229
+ // For 500 errors or other issues, also show insufficient permissions
230
+ setPermissionState ( "insufficient" ) ;
231
+ } else {
232
+ setPermissionState ( "sufficient" ) ;
233
+ }
234
+ } catch ( error ) {
235
+ console . error ( "Error checking permissions:" , error ) ;
236
+ setPermissionState ( "insufficient" ) ;
237
+ }
238
+ } , [ session . data ?. user , permissionState ] ) ;
239
+
205
240
const loadChatSession = async ( sessionId : string ) => {
206
241
// Cancel any active stream first
207
242
if ( fetchControllerRef . current && isLoading ) {
@@ -326,8 +361,17 @@ export const TorchAgentPage = () => {
326
361
useEffect ( ( ) => {
327
362
if ( session . data ?. user ) {
328
363
fetchChatHistory ( ) ;
364
+ // Only check permissions if we haven't checked yet
365
+ if ( permissionState === "unchecked" ) {
366
+ checkUserPermissions ( ) ;
367
+ }
329
368
}
330
- } , [ session . data ?. user , fetchChatHistory ] ) ;
369
+ } , [
370
+ session . data ?. user ,
371
+ fetchChatHistory ,
372
+ permissionState ,
373
+ checkUserPermissions ,
374
+ ] ) ;
331
375
332
376
useEffect ( ( ) => {
333
377
if ( ! session . data ?. user ) return ;
@@ -610,6 +654,8 @@ export const TorchAgentPage = () => {
610
654
"Authentication required. Please sign in to continue."
611
655
) ;
612
656
} else if ( response . status === 403 ) {
657
+ // Set the insufficient permissions flag for authenticated users
658
+ setPermissionState ( "insufficient" ) ;
613
659
throw new Error (
614
660
"Access denied. You need write permissions to pytorch/pytorch repository to use this tool."
615
661
) ;
@@ -671,13 +717,15 @@ export const TorchAgentPage = () => {
671
717
672
718
const hasCookieAuth = hasAuthCookie ( ) ;
673
719
674
- if ( session . status === "loading" ) {
720
+ if ( session . status === "loading" || permissionState === "checking" ) {
675
721
return (
676
722
< TorchAgentPageContainer >
677
723
< QuerySection sx = { { padding : "20px" , textAlign : "center" } } >
678
724
< AISpinner />
679
725
< Typography variant = "h6" sx = { { mt : 2 } } >
680
- Checking authentication...
726
+ { session . status === "loading"
727
+ ? "Checking authentication..."
728
+ : "Checking permissions..." }
681
729
</ Typography >
682
730
</ QuerySection >
683
731
</ TorchAgentPageContainer >
@@ -700,9 +748,98 @@ export const TorchAgentPage = () => {
700
748
You must be logged in with write permissions to pytorch/pytorch to
701
749
access this tool.
702
750
</ Typography >
703
- < Typography variant = "body2" color = "text.secondary" >
704
- Please sign in to continue.
751
+ < Typography variant = "body2" color = "text.secondary" sx = { { mb : 3 } } >
752
+ Please sign in with GitHub to continue.
753
+ </ Typography >
754
+ < Box
755
+ sx = { {
756
+ display : "flex" ,
757
+ flexDirection : "column" ,
758
+ alignItems : "center" ,
759
+ gap : 2 ,
760
+ } }
761
+ >
762
+ < Button
763
+ variant = "contained"
764
+ color = "primary"
765
+ size = "large"
766
+ onClick = { ( ) => signIn ( ) }
767
+ sx = { { minWidth : "200px" } }
768
+ >
769
+ Sign In
770
+ </ Button >
771
+ < Typography
772
+ variant = "body2"
773
+ color = "text.secondary"
774
+ component = "a"
775
+ href = "https://forms.gle/SoLgaCucjJqc6F647"
776
+ target = "_blank"
777
+ rel = "noopener noreferrer"
778
+ sx = { {
779
+ textDecoration : "underline" ,
780
+ "&:hover" : {
781
+ textDecoration : "none" ,
782
+ } ,
783
+ } }
784
+ >
785
+ no GitHub account? request access here
786
+ </ Typography >
787
+ </ Box >
788
+ </ QuerySection >
789
+ </ TorchAgentPageContainer >
790
+ ) ;
791
+ }
792
+
793
+ // Check if user is authenticated but has insufficient permissions
794
+ if (
795
+ session . data ?. user &&
796
+ ! hasAuthCookie ( ) &&
797
+ permissionState === "insufficient"
798
+ ) {
799
+ return (
800
+ < TorchAgentPageContainer >
801
+ < QuerySection sx = { { padding : "20px" , textAlign : "center" } } >
802
+ < Typography variant = "h4" gutterBottom >
803
+ Insufficient Permissions
804
+ </ Typography >
805
+ < Typography variant = "body1" sx = { { mb : 2 } } >
806
+ You are signed in as{ " " }
807
+ < strong > { session . data . user . name || session . data . user . email } </ strong >
808
+ , but you need write permissions to pytorch/pytorch to access this
809
+ tool.
705
810
</ Typography >
811
+ < Typography variant = "body2" color = "text.secondary" sx = { { mb : 3 } } >
812
+ Please request access to continue using TorchAgent.
813
+ </ Typography >
814
+ < Box
815
+ sx = { {
816
+ display : "flex" ,
817
+ gap : 2 ,
818
+ justifyContent : "center" ,
819
+ flexWrap : "wrap" ,
820
+ } }
821
+ >
822
+ < Button
823
+ variant = "contained"
824
+ color = "primary"
825
+ component = "a"
826
+ href = "https://forms.gle/SoLgaCucjJqc6F647"
827
+ target = "_blank"
828
+ rel = "noopener noreferrer"
829
+ >
830
+ Request Access
831
+ </ Button >
832
+ < Button
833
+ variant = "outlined"
834
+ color = "secondary"
835
+ onClick = { ( ) => {
836
+ setPermissionState ( "unchecked" ) ;
837
+ checkUserPermissions ( ) ;
838
+ } }
839
+ >
840
+ Try Again
841
+ </ Button >
842
+ </ Box >
706
843
</ QuerySection >
707
844
</ TorchAgentPageContainer >
708
845
) ;
0 commit comments