╭ changed ──────╮ │src/ui/User.zig│ ╰───────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │20 │ │21 pub const ForkItem = struct { │ │22 id: []const u8, │ │23 - // the target repo, whose name and access the fork shares │ │24 - target: evt.Repo, │ │23 + // the repo name the fork was made under │ │24 + repo_name: []const u8, │ │25 + // the target's access, which the fork shares, or null once the target is gone│ │26 + access: ?evt.Repo.Access, │ │27 title: []const u8, │ │28 }; │ │29 │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │137 │ │138 // the target lives in its owner's user repo │ │139 const owner_id = try evt.parseEventId(&record.event.repo_user_id); │ │138 - const target = (try evt.readRepoById(io, gpa, arena, users_dir, &owner_id, &try evt.parseEventId(&record.event.repo_id), session.userId())) orelse continue;│ │139 - if (target.role == null) continue; │ │140 - // patches that are off take their drafts with them │ │141 - if (target.repo.event.patch_role == null) continue; │ │142 - const target_repo = target.repo; │ │140 + // a deleted target, or one whose owner was deleted, leaves the fork to its forker │ │141 + const target = try evt.readRepoById(io, gpa, arena, users_dir, &owner_id, &try evt.parseEventId(&record.event.repo_id), session.userId()); │ │142 + if (target) |value| { │ │143 + if (value.role == null) continue; │ │144 + // patches that are off take their drafts with them │ │145 + if (value.repo.event.patch_role == null) continue; │ │146 + } else { │ │147 + const viewer_id = session.userId() orelse continue; │ │148 + if (!std.mem.eql(u8, &viewer_id, &user_id)) continue; │ │149 + } │ │150 │ │151 var title: []const u8 = "(unavailable)"; │ │152 const path = try fork.forkPath(arena.allocator(), users_dir, &user_id, &fork_id); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │162 } else |_| {} │ │163 try forks.append(arena.allocator(), .{ │ │164 .id = try arena.allocator().dupe(u8, &fork_id_hex), │ │158 - .target = target_repo.event, │ │165 + .repo_name = record.event.repo_name, │ │166 + .access = if (target) |value| value.repo.event.read_access else null,│ │167 .title = title, │ │168 }); │ │169 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │245 try items.append(aa, .{ .text = "← previous", .link = try aa.print("a:/{s}/forks/start:{d}", .{ data.user.name, data.forks_start -| page_size }) });│ │246 for (data.forks) |fork_item| { │ │247 // the fork route names the forker │ │240 - const identity = try aa.print("{s}:{s}", .{ data.user.name, fork_item.target.name }); │ │248 + const identity = try aa.print("{s}:{s}", .{ data.user.name, fork_item.repo_name }); │ │249 const route = ui.RoutablePage.forkPatchRoute(identity, fork_item.id) orelse return error.RouteTooLong; │ │250 try items.append(aa, .{ │ │243 - .text = try aa.print("{s} - {s}", .{ fork_item.target.name, fork_item.title }), │ │251 + .text = try aa.print("{s} - {s}", .{ fork_item.repo_name, fork_item.title }), │ │252 .link = try aa.print("a:{s}", .{try route.toUrl(session.page_arena)}), │ │245 - .bottom_label = if (fork_item.target.read_access == .private) "(private)" else "", │ │253 + .bottom_label = if (fork_item.access) |access| if (access == .private) "(private)" else "" else "(repo deleted)", │ │254 }); │ │255 } │ │256 if (data.forks_next_start) |next_start| │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯