fix: don't crash and stay stuck on a subdir markdown link

Clicking a markdown link into a subdirectory's README threw
"Cannot read properties of undefined (reading 'sha')" and left the
viewer on Loading…. The route handler called updateContent() without
loading the new directory's file listing, so getSelectedFile() returned
undefined and getContent() then dereferenced fileInfo.sha.

Two fixes:
- getContent() falls back to sha "0" when fileInfo is undefined.
- The $routeUpdate handler walks the new path and loads any directory
  listings that aren't yet in $scope.files before rendering, so the
  selected file actually has its sha by the time we fetch.

Fixes #510.
This commit is contained in:
tdurieux
2026-05-04 11:10:12 +02:00
parent 117406f2ce
commit 5c7eb23336
2 changed files with 23 additions and 4 deletions
+22 -3
View File
@@ -1696,7 +1696,7 @@ angular
"f4b",
];
$scope.$on("$routeUpdate", function (event, current) {
$scope.$on("$routeUpdate", async function (event, current) {
if (($routeParams.path || "") == $scope.filePath) {
return;
}
@@ -1709,7 +1709,21 @@ angular
return init();
}
updateContent();
// #510 — when the user clicks a markdown link into a subdirectory,
// the file listing for that directory may not be loaded yet, so
// getSelectedFile() returns undefined and updateContent() fires a
// request without the right sha. Walk the new path and load any
// listings we don't have before rendering.
for (let i = 0; i < $scope.paths.length; i++) {
const dirPath = i > 0 ? $scope.paths.slice(0, i).join("/") : "";
const alreadyLoaded = $scope.files.some(
(f) => f.path === dirPath
);
if (!alreadyLoaded) {
await $scope.getFiles(dirPath);
}
}
$scope.$apply(updateContent);
});
function selectFile() {
@@ -1835,8 +1849,13 @@ angular
const originalType = $scope.type;
$scope.type = "loading";
$scope.content = "loading";
// fileInfo can be undefined when the user navigates (e.g. clicks a
// markdown link into a subdir whose file list hasn't loaded yet) —
// see #510. Fall back to "0" so the request still goes through; the
// server returns a fresh ETag on first hit either way.
const sha = (fileInfo && fileInfo.sha) || "0";
$http
.get(`/api/repo/${$scope.repoId}/file/${path}?v=` + fileInfo.sha, {
.get(`/api/repo/${$scope.repoId}/file/${path}?v=` + sha, {
transformResponse: (data) => {
return data;
},
+1 -1
View File
File diff suppressed because one or more lines are too long