From dd635a266f7f0e779289079deb32183751e015e9 Mon Sep 17 00:00:00 2001 From: Aayush Karki Date: Sun, 21 Jun 2026 16:41:51 -0400 Subject: [PATCH 1/4] pass file type to submission file panel when selecting file from annotations tab --- app/javascript/Components/Result/left_pane.jsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/javascript/Components/Result/left_pane.jsx b/app/javascript/Components/Result/left_pane.jsx index a86b11582d..47162ebe0b 100644 --- a/app/javascript/Components/Result/left_pane.jsx +++ b/app/javascript/Components/Result/left_pane.jsx @@ -55,11 +55,24 @@ export class LeftPane extends React.Component { } } + getFileTypeById = (fileData, id) => { + for (const file of fileData.files) { + if (file[1] === id) return file[2]; + } + for (const dir of Object.values(fileData.directories || {})) { + const type = this.getFileTypeById(dir, id); + if (type !== null) return type; + } + return null; + }; + // Display a given file. Used to changes files from the annotations panel. selectFile = (file, submission_file_id, focus_line, annotation_focus) => { + const type = this.getFileTypeById(this.props.submission_files, submission_file_id); this.submissionFilePanel.current.selectFile( file, submission_file_id, + type, focus_line, annotation_focus ); From da3d0fb15cd58af0b9b4b16b240d40d05f26283f Mon Sep 17 00:00:00 2001 From: Aayush Karki Date: Sun, 21 Jun 2026 17:19:10 -0400 Subject: [PATCH 2/4] added tests --- Changelog.md | 1 + .../Components/__tests__/left_pane.test.jsx | 131 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 app/javascript/Components/__tests__/left_pane.test.jsx diff --git a/Changelog.md b/Changelog.md index ff0ad39f09..1fa4bbbbe8 100644 --- a/Changelog.md +++ b/Changelog.md @@ -16,6 +16,7 @@ - Add pagination to Admin Users table for performance (#7997) ### 🐛 Bug fixes +- Fixed bug where clicking a file link in the annotations tab would show a blank or oversized error for PDF files (#8017) - Fixed bug where clicking MarkUs logo in navbar on mobile would open the sidebar instead of redirecting to courses page (#7990) - Fixed bug where merge commits were incorrectly flagged as making a new assignment submission when no assignment files were changed (#7988) - Fixed shift+up/shift+down keybinding being suppressed when a criterion input had focus; active criterion now scrolls into view when navigated to via keyboard (#7989) diff --git a/app/javascript/Components/__tests__/left_pane.test.jsx b/app/javascript/Components/__tests__/left_pane.test.jsx new file mode 100644 index 0000000000..cce97098b4 --- /dev/null +++ b/app/javascript/Components/__tests__/left_pane.test.jsx @@ -0,0 +1,131 @@ +import React from "react"; +import {render} from "@testing-library/react"; +import {LeftPane} from "../Result/left_pane"; +import {renderInResultContext} from "./result_context_renderer"; + +jest.mock("../Result/annotation_panel", () => ({AnnotationPanel: () =>
})); +jest.mock("../Result/feedback_file_panel", () => ({FeedbackFilePanel: () =>
})); +jest.mock("../Result/remark_panel", () => ({RemarkPanel: () =>
})); +jest.mock("../test_run_table", () => ({TestRunTable: () =>
})); + +const flatFileData = { + files: [ + ["report.pdf", 1, "pdf"], + ["notes.txt", 2, "text"], + ], + directories: {}, + name: "", + path: [], +}; + +const nestedFileData = { + files: [["root.pdf", 1, "pdf"]], + directories: { + subdir: { + files: [["image.png", 2, "image"]], + directories: { + nested: { + files: [["data.csv", 3, "text"]], + directories: {}, + name: "nested", + path: ["subdir", "nested"], + }, + }, + name: "subdir", + path: ["subdir"], + }, + }, + name: "", + path: [], +}; + +const basicProps = { + loading: false, + allow_remarks: false, + annotation_categories: [], + annotations: [], + assignment_remark_message: "", + update_overall_comment: jest.fn(), + can_run_tests: false, + detailed_annotations: false, + enable_test: false, + feedback_files: [], + instructor_run: false, + overall_comment: "", + past_remark_due_date: false, + released_to_students: false, + remark_due_date: null, + remark_overall_comment: "", + remark_request_text: "", + remark_request_timestamp: null, + remark_submitted: false, + revision_identifier: "1", + submission_files: flatFileData, + student_view: false, + newAnnotation: jest.fn(), + addExistingAnnotation: jest.fn(), + editAnnotation: jest.fn(), + removeAnnotation: jest.fn(), + rmd_convert_enabled: false, +}; + +describe("LeftPane", () => { + describe("getFileTypeById", () => { + let leftPaneRef; + + beforeEach(() => { + leftPaneRef = React.createRef(); + renderInResultContext(); + }); + + it("returns the file type for a file at the root level", () => { + expect(leftPaneRef.current.getFileTypeById(flatFileData, 1)).toBe("pdf"); + expect(leftPaneRef.current.getFileTypeById(flatFileData, 2)).toBe("text"); + }); + + it("returns the file type for a file in a nested subdirectory", () => { + expect(leftPaneRef.current.getFileTypeById(nestedFileData, 2)).toBe("image"); + expect(leftPaneRef.current.getFileTypeById(nestedFileData, 3)).toBe("text"); + }); + + it("returns null when no file with the given id exists", () => { + expect(leftPaneRef.current.getFileTypeById(flatFileData, 3)).toBeNull(); + }); + }); + + describe("selectFile", () => { + it("passes the file type for a file at the root level", () => { + const leftPaneRef = React.createRef(); + renderInResultContext( + + ); + + leftPaneRef.current.selectFile("report.pdf", 1, undefined, 42); + + expect(leftPaneRef.current.submissionFilePanel.current.selectFile).toHaveBeenCalledWith( + "report.pdf", + 1, + "pdf", + undefined, + 42 + ); + }); + + it("passes the correct file type for a file in a nested subdirectory", () => { + const leftPaneRef = React.createRef(); + renderInResultContext( + + ); + + leftPaneRef.current.selectFile("subdir/image.png", 2, undefined, 42); + + expect(leftPaneRef.current.submissionFilePanel.current.selectFile).toHaveBeenCalledWith( + "subdir/image.png", + 2, + "image", + undefined, + 42 + ); + }); + }); +}); From 6ed8c898327129b73bc84b7d126403f8ab8f26c6 Mon Sep 17 00:00:00 2001 From: Aayush Karki Date: Sun, 21 Jun 2026 17:33:33 -0400 Subject: [PATCH 3/4] mocked submission file panel to fix test errors --- app/javascript/Components/__tests__/left_pane.test.jsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/javascript/Components/__tests__/left_pane.test.jsx b/app/javascript/Components/__tests__/left_pane.test.jsx index cce97098b4..d782d7eb52 100644 --- a/app/javascript/Components/__tests__/left_pane.test.jsx +++ b/app/javascript/Components/__tests__/left_pane.test.jsx @@ -7,6 +7,14 @@ jest.mock("../Result/annotation_panel", () => ({AnnotationPanel: () =>
}) jest.mock("../Result/feedback_file_panel", () => ({FeedbackFilePanel: () =>
})); jest.mock("../Result/remark_panel", () => ({RemarkPanel: () =>
})); jest.mock("../test_run_table", () => ({TestRunTable: () =>
})); +jest.mock("../Result/submission_file_panel", () => ({ + SubmissionFilePanel: class extends React.Component { + selectFile = jest.fn(); + render() { + return
; + } + }, +})); const flatFileData = { files: [ From a8744e789c9e2dd15feeb151291aeb9e7aa10517 Mon Sep 17 00:00:00 2001 From: Aayush Karki Date: Sun, 21 Jun 2026 17:47:00 -0400 Subject: [PATCH 4/4] test fix --- .../Components/__tests__/left_pane.test.jsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/javascript/Components/__tests__/left_pane.test.jsx b/app/javascript/Components/__tests__/left_pane.test.jsx index d782d7eb52..a83d3cb9fd 100644 --- a/app/javascript/Components/__tests__/left_pane.test.jsx +++ b/app/javascript/Components/__tests__/left_pane.test.jsx @@ -7,14 +7,15 @@ jest.mock("../Result/annotation_panel", () => ({AnnotationPanel: () =>
}) jest.mock("../Result/feedback_file_panel", () => ({FeedbackFilePanel: () =>
})); jest.mock("../Result/remark_panel", () => ({RemarkPanel: () =>
})); jest.mock("../test_run_table", () => ({TestRunTable: () =>
})); -jest.mock("../Result/submission_file_panel", () => ({ - SubmissionFilePanel: class extends React.Component { - selectFile = jest.fn(); - render() { - return
; - } - }, -})); +jest.mock("../Result/submission_file_panel", () => { + const React = require("react"); + const MockSubmissionFilePanel = React.forwardRef((props, ref) => { + React.useImperativeHandle(ref, () => ({selectFile: jest.fn()})); + return null; + }); + MockSubmissionFilePanel.displayName = "MockSubmissionFilePanel"; + return {SubmissionFilePanel: MockSubmissionFilePanel}; +}); const flatFileData = { files: [