╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │315 .kind = refsKind(query), │ │316 .after = after, │ │317 } }; │ │318 + if (std.mem.eql(u8, sub, "issues")) return repoIssuesRoute(pair, ""); │ │319 + if (std.mem.startsWith(u8, sub, "issues/")) { │ │320 + // "issues/<issue event id>" │ │321 + const id = sub["issues/".len..]; │ │322 + if (id.len == 0) return null; │ │323 + return repoIssuesRoute(pair, id); │ │324 + } │ │325 if (std.mem.eql(u8, sub, "settings")) return .{ .repo_settings = Array(repo_route_max_len).from(pair) orelse return null }; │ │326 if (std.mem.eql(u8, sub, "auth")) return .{ .repo_auth = Array(repo_route_max_len).from(pair) orelse return null }; │ │327 if (std.mem.eql(u8, sub, files_seg)) return repoFilesRoute(pair, null, "", "", after); // trailing /files == default-branch root│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │389 .repo_files => |a_f| std.mem.eql(u8, a_f.name.slice(), b.repo_files.name.slice()) and a_f.after == b.repo_files.after, │ │390 .repo_commits => |a_c| std.mem.eql(u8, a_c.name.slice(), b.repo_commits.name.slice()) and a_c.after == b.repo_commits.after, │ │391 .repo_refs => |a_r| std.mem.eql(u8, a_r.name.slice(), b.repo_refs.name.slice()) and a_r.kind == b.repo_refs.kind and a_r.after == b.repo_refs.after, │ │392 + .repo_issues => |a_i| std.mem.eql(u8, a_i.name.slice(), b.repo_issues.name.slice()) and std.mem.eql(u8, a_i.selected.slice(), b.repo_issues.selected.slice()),│ │393 .repo_settings => |a_name| std.mem.eql(u8, a_name.slice(), b.repo_settings.slice()), │ │394 .repo_auth => |a_name| std.mem.eql(u8, a_name.slice(), b.repo_auth.slice()), │ │395 else => true, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────╮ │459 try jw.objectField("name"); │ │460 try jw.write(name.slice()); │ │461 }, │ │462 + .repo_issues => |i| { │ │463 + try jw.objectField("name"); │ │464 + try jw.write(i.name.slice()); │ │465 + try jw.objectField("selected"); │ │466 + try jw.write(i.selected.slice());│ │467 + }, │ │468 .repo_files => |f| { │ │469 try jw.objectField("name"); │ │470 try jw.write(f.name.slice()); │ ╰──────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │497 } │ │498 │ │499 pub fn jsonParse(allocator: std.mem.Allocator, source: anytype, options: std.json.ParseOptions) !RoutablePage { │ │472 - const Helper = struct { kind: std.meta.Tag(RoutablePage), name: ?[]const u8 = null, after: usize = 0, ref_kind: ?[]const u8 = null }; │ │500 + const Helper = struct { kind: std.meta.Tag(RoutablePage), name: ?[]const u8 = null, after: usize = 0, ref_kind: ?[]const u8 = null, selected: ?[]const u8 = null };│ │501 const helper = try std.json.innerParse(Helper, allocator, source, options); │ │502 const parseName = struct { │ │503 // errors must stay within std.json's ParseError set; ValueTooLong │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │521 .kind = if (helper.ref_kind) |k| (if (std.mem.eql(u8, k, "tag")) .tag else .branch) else .branch, │ │522 .after = helper.after, │ │523 } }, │ │524 + .repo_issues => .{ .repo_issues = .{ │ │525 + .name = try parseName(repo_route_max_len, helper.name), │ │526 + .selected = Array(evt.event_id_size * 2).from(helper.selected orelse "") orelse return error.ValueTooLong,│ │527 + } }, │ │528 .repo_settings => .{ .repo_settings = try parseName(repo_route_max_len, helper.name) }, │ │529 .repo_auth => .{ .repo_auth = try parseName(repo_route_max_len, helper.name) }, │ │530 }; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────╮ │1090 repo_files: Repo.Files.View, │ │1091 repo_commits: Repo.Commits.View, │ │1092 repo_refs: Repo.Refs.View, │ │1093 + repo_issues: Repo.Issues.View, │ │1094 home_users: Home.Users.View, │ │1095 home_repos: Home.Repos.View, │ │1096 auth_tab: Home.Header.AuthTab.View,│ ╰─────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/Repo.zig│ ╰───────────────╯ ╭──────────────────────────────────────────────────────╮ │15 pub const Files = @import("./Repo/Files.zig"); │ │16 pub const Commits = @import("./Repo/Commits.zig");│ │17 pub const Refs = @import("./Repo/Refs.zig"); │ │18 +pub const Issues = @import("./Repo/Issues.zig"); │ │19 pub const Settings = @import("./Settings.zig"); │ │20 pub const Auth = @import("./Auth.zig"); │ │21 pub const Quit = @import("./Quit.zig"); │ ╰──────────────────────────────────────────────────────╯ ╭───────────────────────╮ │27 files: Files, │ │28 commits: Commits, │ │29 refs: Refs, │ │30 +issues: Issues, │ │31 settings: Settings,│ │32 auth: Auth, │ │33 quit: Quit, │ ╰───────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │64 .repo_settings, .repo_auth => |n| n.slice(), │ │65 .repo_commits => |c| c.name.slice(), │ │66 .repo_refs => |r| r.name.slice(), │ │67 + .repo_issues => |i| i.name.slice(), │ │68 else => return error.UnexpectedRoute, │ │69 }; │ │70 const rf = ui.RoutablePage.RepoFiles.parse(name_str) orelse return error.NotFound;│ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │107 const refs_after: usize = switch (route) { │ │108 .repo_refs => |r| r.after, │ │109 else => 0, │ │110 + }; │ │111 + // the issue the issues tab's window is rooted at ("" = the first window). │ │112 + const issues_selected: []const u8 = switch (route) { │ │113 + .repo_issues => |i| i.selected.slice(), │ │114 + else => "", │ │115 }; │ │116 │ │117 const found = (try evt.Repo.readByOwnerAndName(DB, hash_kind, haxy_moment, arena, rf.owner, rf.name)) orelse return error.NotFound;│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯