╭ changed ─────────────╮ │src/ui/Repo/Issues.zig│ ╰──────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────╮ │15 // how many issues one window shows before a "next" link appears. │ │16 pub const page_size = 20; │ │17 │ │18 -// one issue from the repo's consumed event database. │ │19 -pub const Issue = struct { │ │20 - id: []const u8, // hex event id │ │21 - title: []const u8, │ │22 - description: []const u8, │ │18 +// one issue from the repo's consumed event database, with its hex event id│ │19 +// (the id lives in the event envelope, not the payload). │ │20 +pub const IssueWithId = struct { │ │21 + id: []const u8, │ │22 + issue: evt.Issue, │ │23 }; │ │24 │ │25 // "owner/name", so the view can build /repo/owner/name/issues/... links. │ ╰───────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │27 // the hex event id of the issue this window is rooted at ("" = the first │ │28 // window), mirrored into the url. │ │29 selected_id: []const u8, │ │30 -issues: []const Issue, │ │30 +issues: []const IssueWithId, │ │31 // the id of the previous window's first issue ("" = the bare first window), or│ │32 // null when this window is already the first. │ │33 prev_id: ?[]const u8, │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │141 // the next window's start). the set's keys are orderKey │ │142 // ([timestamp][event-id]); the trailing bytes of each key are the issue│ │143 // event id. │ │144 - var issues: std.ArrayList(Issue) = .empty; │ │144 + var issues: std.ArrayList(IssueWithId) = .empty; │ │145 var next_id: ?[]const u8 = null; │ │146 while (try iter.next()) |id_cursor_val| { │ │147 var id_cursor = id_cursor_val; │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │155 } │ │156 const issue_cursor = try event_id_to_issue.getCursor(hash.hashInt(repo_opts.hash, order_key[@sizeOf(u64)..])) orelse continue;│ │157 const issue_map = try DB.HashMap(.read_only).init(issue_cursor); │ │158 - const issue_event = try evt.read(evt.Issue, DB, repo_opts.hash, arena, issue_map); │ │158 try issues.append(aa, .{ │ │159 .id = try aa.dupe(u8, &id_hex), │ │161 - .title = issue_event.title, │ │162 - .description = issue_event.description, │ │160 + .issue = try evt.read(evt.Issue, DB, repo_opts.hash, arena, issue_map), │ │161 }); │ │162 } │ │163 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │196 errdefer list_box.deinit(allocator); │ │197 if (data.prev_id) |prev| │ │198 try addRow(allocator, &list_box, "← previous", try issuesLink(session.page_arena, data.identity, prev)); │ │201 - for (data.issues) |issue| │ │202 - try addRow(allocator, &list_box, issue.title, try issueRowLink(session.page_arena, data.identity, issue.id)); │ │199 + for (data.issues) |entry| │ │200 + try addRow(allocator, &list_box, entry.issue.title, try issueRowLink(session.page_arena, data.identity, entry.id));│ │201 if (data.next_id) |next| │ │202 try addRow(allocator, &list_box, "next →", try issuesLink(session.page_arena, data.identity, next)); │ │203 // select the window's first issue (past a leading "previous" │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │358 } │ │359 │ │360 fn populateDetail(self: *View, allocator: std.mem.Allocator, sel: usize) !void {│ │363 - const issue = self.data.issues[sel]; │ │361 + const entry = self.data.issues[sel]; │ │362 const inner = self.detailInner(); │ │363 │ │364 for (inner.children.values()) |*child| child.widget.deinit(allocator); │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │369 // border reserves the space the border occupies when focused, so │ │370 // focusing doesn't shift layout. │ │371 { │ │374 - var tb = try wgt.TextBox(ui.Widget).init(allocator, issue.description, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .word }); │ │372 + var tb = try wgt.TextBox(ui.Widget).init(allocator, entry.issue.description, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .word });│ │373 errdefer tb.deinit(allocator); │ │374 tb.getFocus().focusable = true; │ │375 try inner.children.put(allocator, tb.getFocus().id, .{ .widget = .{ .text_box = tb }, .rect = null, .min_size = null }); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯