╭ changed ─────────────╮ │src/ui/Repo/Issues.zig│ ╰──────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────╮ │← previous│ ╰──────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │885 // the in-page "ai:" anchor for selecting issue `id` in `identity`'s list; the │ │886 // href is only followed with js off. │ │887 fn issueRowLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, id: []const u8) ![]const u8 { │ │745 - const route = ui.RoutablePage.repoIssuesRoute(identity, "", id) orelse return error.RouteTooLong; │ │888 + const route = ui.RoutablePage.repoIssuesRoute(identity, .open, "", id) orelse return error.RouteTooLong;│ │889 const url = try route.urlAlloc(page_arena); │ │890 return std.fmt.allocPrint(page_arena.allocator(), "ai:{s}", .{url}); │ │891 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │892 │ │750 -// the "a:" link to the issues list filtered to `tag` (raw; encoded here). │ │751 -fn tagLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, tag: []const u8) ![]const u8 { │ │893 +// the "a:" link to `status`'s issues list filtered to `tag` (raw; encoded here). │ │894 +fn tagLink(page_arena: *std.heap.ArenaAllocator, identity: []const u8, status: evt.Issue.Status, tag: []const u8) ![]const u8 {│ │895 const encoded = try ui.urlEncodeRef(page_arena.allocator(), tag); │ │753 - const route = ui.RoutablePage.repoIssuesRoute(identity, encoded, "") orelse return error.RouteTooLong; │ │896 + const route = ui.RoutablePage.repoIssuesRoute(identity, status, encoded, "") orelse return error.RouteTooLong; │ │897 const url = try route.urlAlloc(page_arena); │ │898 return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{url}); │ │899 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │903 box: wgt.Box(ui.Widget), │ │904 tab_ids: std.AutoArrayHashMapUnmanaged(usize, void), │ │905 │ │763 - // `tag` is the url-encoded tag filter ("" = unfiltered). │ │764 - pub fn init(allocator: std.mem.Allocator, session: *ui.Session, identity: []const u8, count: usize, tag: []const u8) !Header { │ │906 + pub fn init(allocator: std.mem.Allocator, session: *ui.Session, data: *const Self) !Header { │ │907 var box = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = .hidden, .rounded_corners = true, .direction = .horiz });│ │908 errdefer box.deinit(allocator); │ │909 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │912 │ │913 const aa = session.page_arena.allocator(); │ │914 │ │773 - const results_route = ui.RoutablePage.repoIssuesRoute(identity, tag, "") orelse return error.RouteTooLong; │ │774 - const results_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try results_route.urlAlloc(session.page_arena)}); │ │775 - const tags_route = ui.RoutablePage.repoIssuesTagsRoute(identity) orelse return error.RouteTooLong; │ │776 - const tags_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try tags_route.urlAlloc(session.page_arena)}); │ │777 - │ │778 - // results tab, labeled with the listing's issue count │ │779 - { │ │780 - const label = try std.fmt.allocPrint(aa, "results ({d})", .{count}); │ │915 + // a list tab per status, labeled with its listing's issue count │ │916 + for ([_]evt.Issue.Status{ .open, .closed }) |status| { │ │917 + const route = ui.RoutablePage.repoIssuesRoute(data.identity, status, data.tag, "") orelse return error.RouteTooLong; │ │918 + const link = try std.fmt.allocPrint(aa, "ai:{s}", .{try route.urlAlloc(session.page_arena)}); │ │919 + const label = try std.fmt.allocPrint(aa, "{s} ({d})", .{ @tagName(status), data.window(status).count }); │ │920 var text_box = try wgt.TextBox(ui.Widget).init(allocator, label, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none });│ │921 errdefer text_box.deinit(allocator); │ │922 text_box.getFocus().focusable = true; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────╮ │784 - text_box.getFocus().kind = .{ .custom = results_link }; │ │923 + text_box.getFocus().kind = .{ .custom = link }; │ │924 try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │925 try box.children.put(allocator, text_box.getFocus().id, .{│ │926 .widget = .{ .text_box = text_box }, │ ╰───────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │931 │ │932 // tags tab, labeled with the active tag filter │ │933 { │ │795 - const label = if (tag.len == 0) "tags" else blk: { │ │796 - const decoded = std.Uri.percentDecodeInPlace(try aa.dupe(u8, tag)); │ │934 + const tags_route = ui.RoutablePage.repoIssuesTagsRoute(data.identity, data.tag) orelse return error.RouteTooLong; │ │935 + const tags_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try tags_route.urlAlloc(session.page_arena)}); │ │936 + const label = if (data.tag.len == 0) "tags" else blk: { │ │937 + const decoded = std.Uri.percentDecodeInPlace(try aa.dupe(u8, data.tag)); │ │938 break :blk try std.fmt.allocPrint(aa, "tags ({s})", .{decoded}); │ │939 }; │ │940 var text_box = try wgt.TextBox(ui.Widget).init(allocator, label, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none });│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │950 } │ │951 │ │952 var self = Header{ .box = box, .tab_ids = tab_ids }; │ │812 - // the tab matching the incoming route's view is selected initially. │ │813 - const selected_index: usize = switch (session.data.current_page) { │ │814 - .repo_issues => |i| switch (i.view) { │ │815 - .results => 0, │ │816 - .tags => 1, │ │817 - }, │ │818 - else => 0, │ │819 - }; │ │820 - self.getFocus().child_id = self.tab_ids.keys()[selected_index]; │ │953 + // the tab matching the page's view is selected initially. │ │954 + self.getFocus().child_id = self.tab_ids.keys()[View.viewIndex(data.view)];│ │955 return self; │ │956 } │ │957 │ ╰───────────────────────────────────────────────────────────────────────────────────────╯