@@ -6,6 +6,9 @@ import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
66import { Tooltip } from "@mui/material" ;
77import Typography from "@mui/material/Typography" ;
88import Box from "@mui/material/Box" ;
9+ import { Link } from '@mui/material' ;
10+ import { List , ListItem } from '@mui/material' ;
11+
912
1013function LinearProgressWithLabel ( props ) {
1114 return (
@@ -27,7 +30,68 @@ function LinearProgressWithLabel(props) {
2730 ) ;
2831}
2932
30- function AssignmentProblems ( { history, allProblemDisplayNames, numSolved } ) {
33+ const ProblemJumpLink = ( { lineNumber, editorRef, label } ) => {
34+ const handleJump = ( event ) => {
35+ // Prevent default link behavior if necessary
36+ event . preventDefault ( ) ;
37+
38+ const editorInstance = editorRef . current ;
39+ if ( ! editorInstance ) return ;
40+
41+ const targetEditor = editorInstance . getModifiedEditor
42+ ? editorInstance . getModifiedEditor ( )
43+ : editorInstance ;
44+
45+ targetEditor . revealLineInCenter ( lineNumber ) ;
46+ targetEditor . setPosition ( { lineNumber : lineNumber , column : 1 } ) ;
47+ targetEditor . focus ( ) ;
48+ } ;
49+
50+ return (
51+ < Link
52+ component = "button"
53+ variant = "body2"
54+ onClick = { handleJump }
55+ sx = { {
56+ textAlign : 'left' ,
57+ verticalAlign : 'baseline' ,
58+ textDecoration : 'none' ,
59+ '&:hover' : {
60+ textDecoration : 'underline' ,
61+ } ,
62+ cursor : 'pointer' ,
63+ color : 'primary.main' ,
64+ fontWeight : 500 ,
65+ } }
66+ >
67+ { label || `Line ${ lineNumber } ` }
68+ </ Link >
69+ ) ;
70+ } ;
71+
72+
73+ function AssignmentProblems ( {
74+ history,
75+ allProblemDisplayNames,
76+ numSolved,
77+ editorRef,
78+ problemLines,
79+ } ) {
80+ function goToLine ( lineNumber ) {
81+ const editor = editorRef . current ;
82+ if ( ! editor ) return ;
83+
84+ // 1. Check if it's a Diff Editor (has getModifiedEditor method)
85+ // 2. Otherwise treat as a standard editor
86+ const targetEditor = editor . getModifiedEditor
87+ ? editor . getModifiedEditor ( )
88+ : editor ;
89+
90+ targetEditor . revealLineInCenter ( lineNumber ) ;
91+ targetEditor . setPosition ( { lineNumber : lineNumber , column : 1 } ) ;
92+ targetEditor . focus ( ) ;
93+ }
94+
3195 function getIcon ( problemDisplayName ) {
3296 const problemData = history . find (
3397 ( p ) => p . display_name === problemDisplayName ,
@@ -51,11 +115,61 @@ function AssignmentProblems({ history, allProblemDisplayNames, numSolved }) {
51115 return ( numSolved / allProblemDisplayNames . length ) * 100 ;
52116 }
53117
54- const problems = allProblemDisplayNames . map ( ( problemDisplayName ) => (
55- < div >
56- { getIcon ( problemDisplayName ) } { problemDisplayName }
57- </ div >
58- ) ) ;
118+
119+ // TODO span styling and improve accessibility?
120+ const problems = allProblemDisplayNames . map ( ( problemDisplayName ) => {
121+ const lines = problemLines [ problemDisplayName ] ;
122+
123+ if ( problemLines [ problemDisplayName ] . length === 0 ) {
124+ return (
125+ < Box key = { problemDisplayName } sx = { { display : 'flex' , alignItems : 'center' , my : 0.5 } } >
126+ { getIcon ( problemDisplayName ) }
127+ < Typography variant = "body2" sx = { { ml : 1 , color : 'text.disabled' } } >
128+ { problemDisplayName } (Not found)
129+ </ Typography >
130+ </ Box >
131+ ) ;
132+ } else if ( problemLines [ problemDisplayName ] . length === 1 ) {
133+ return (
134+ < Box key = { problemDisplayName } sx = { { display : 'flex' , alignItems : 'center' , my : 0.5 } } >
135+ { getIcon ( problemDisplayName ) }
136+ < Box sx = { { ml : 1 } } >
137+ < ProblemJumpLink
138+ lineNumber = { lines [ 0 ] }
139+ editorRef = { editorRef }
140+ label = { problemDisplayName }
141+ />
142+ </ Box >
143+ </ Box >
144+ ) ;
145+ } else {
146+ return (
147+ < Box key = { problemDisplayName } sx = { { my : 1 } } >
148+ < Box sx = { { display : 'flex' , alignItems : 'center' } } >
149+ { getIcon ( problemDisplayName ) }
150+ < Typography variant = "body2" sx = { { ml : 1 } } >
151+ { problemDisplayName }
152+ </ Typography >
153+ </ Box >
154+ < Box sx = { { pl : 4 , display : 'flex' , flexDirection : 'column' , flexWrap : 'wrap' } } >
155+
156+ < List sx = { { listStyleType : 'disc' , pl : '1rem' } } >
157+ { lines . map ( ( lineNumber ) => (
158+ < ListItem disablePadding sx = { { display : 'list-item' } } >
159+ < ProblemJumpLink
160+ key = { `${ problemDisplayName } -${ lineNumber } ` }
161+ lineNumber = { lineNumber }
162+ editorRef = { editorRef }
163+ label = { `Line ${ lineNumber } ` }
164+ />
165+ </ ListItem >
166+ ) ) }
167+ </ List >
168+ </ Box >
169+ </ Box >
170+ ) ;
171+ }
172+ } ) ;
59173
60174 return (
61175 < div style = { { paddingTop : "1rem" , paddingBottom : "1rem" } } >
@@ -71,6 +185,8 @@ function Graphs({
71185 currBackupHistory,
72186 allProblemDisplayNames,
73187 selectedBackup,
188+ problemLines,
189+ editorRef,
74190} ) {
75191 return (
76192 < div >
@@ -79,6 +195,8 @@ function Graphs({
79195 history = { currBackupHistory }
80196 allProblemDisplayNames = { allProblemDisplayNames }
81197 numSolved = { numQuestionsSolved [ selectedBackup ] }
198+ problemLines = { problemLines }
199+ editorRef = { editorRef }
82200 />
83201 </ div >
84202 ) ;
0 commit comments