╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Events.zig│ ╰──────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │262 const parent_kind = (try evt.readEventKind(hash_kind, kind_map, &parent_id)) orelse return item; │ │263 const route = switch (parent_kind) { │ │264 .issue => ui.RoutablePage.repoIssueCommentsRoute(identity, &record.event.parent_id, 0), │ │265 + .discussion => ui.RoutablePage.repoDiscussionCommentsRoute(identity, &record.event.parent_id, 0),│ │266 else => null, │ │267 } orelse return item; │ │268 item.view_url = try route.toUrl(arena); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Header.zig│ ╰──────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │25 // the issues tab's tag filter, url-encoded ("" = unfiltered), so the tab links│ │26 // back to the filtered list. │ │27 issues_tag: []const u8, │ │28 +discussions_tag: []const u8, │ │29 │ │30 const Self = @This(); │ │31 │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │31 -pub fn init(arena: *std.heap.ArenaAllocator, name: []const u8, owner_name: []const u8, ref_or_oid: RefOrOid, ref_or_oid_value: []const u8, issues_tag: []const u8) !Self { │ │32 +pub fn init(arena: *std.heap.ArenaAllocator, name: []const u8, owner_name: []const u8, ref_or_oid: RefOrOid, ref_or_oid_value: []const u8, issues_tag: []const u8, discussions_tag: []const u8) !Self {│ │33 return .{ │ │34 .name = name, │ │35 .owner_name = owner_name, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────╮ │38 .ref_or_oid = ref_or_oid, │ │39 .ref_or_oid_value = ref_or_oid_value,│ │40 .issues_tag = issues_tag, │ │41 + .discussions_tag = discussions_tag, │ │42 }; │ │43 } │ │44 │ ╰─────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │122 const refs_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try refs_route.toUrl(session.page_arena)}); │ │123 const issues_route = ui.RoutablePage.repoIssuesRoute(identity, .open, data.issues_tag, "") orelse return error.RouteTooLong; │ │124 const issues_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try issues_route.toUrl(session.page_arena)}); │ │125 + const discussions_route = ui.RoutablePage.repoDiscussionsRoute(identity, data.discussions_tag, "") orelse return error.RouteTooLong;│ │126 + const discussions_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try discussions_route.toUrl(session.page_arena)}); │ │127 const events_route = ui.RoutablePage.repoEventsRoute(identity, .active, null, "") orelse return error.RouteTooLong; │ │128 const events_link = try std.fmt.allocPrint(aa, "ai:{s}", .{try events_route.toUrl(session.page_arena)}); │ │129 const settings_route = ui.RoutablePage{ .repo_settings = Array.from(identity) orelse return error.RouteTooLong }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────╮ │137 .repo_commits => commits_link, │ │138 .repo_refs => refs_link, │ │139 .repo_issues => issues_link, │ │140 + .repo_discussions => discussions_link,│ │141 .repo_events => events_link, │ │142 .repo_settings => settings_link, │ │143 .repo_auth => auth_link, │ ╰───────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │202 .widget = .{ .text_box = text_box }, │ │203 .rect = null, │ │204 .min_size = .{ .width = "issues".len + 2, .height = null }, │ │205 + }); │ │206 + } │ │207 + │ │208 + // discussions tab │ │209 + { │ │210 + var text_box = try wgt.TextBox(ui.Widget).init(allocator, "discussions", .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none });│ │211 + errdefer text_box.deinit(allocator); │ │212 + text_box.getFocus().focusable = true; │ │213 + text_box.getFocus().kind = .{ .custom = discussions_link }; │ │214 + try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │215 + if (std.mem.eql(u8, discussions_link, current_link)) selected_tab = text_box.getFocus().id; │ │216 + try box.children.put(allocator, text_box.getFocus().id, .{ │ │217 + .widget = .{ .text_box = text_box }, │ │218 + .rect = null, │ │219 + .min_size = .{ .width = "discussions".len + 2, .height = null }, │ │220 }); │ │221 } │ │222 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Issues.zig│ ╰──────────────────────╯ ╭────────────────────────────────────────────────────╮ │15 const diff3 = @import("../../diff3.zig"); │ │16 const Comment = @import("Comment.zig"); │ │17 const Attachment = @import("Attachment.zig"); │ │18 +const Threads = @import("Threads.zig"); │ │19 │ │20 const wasm = builtin.target.cpu.arch == .wasm32;│ │21 │ ╰────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────╮ │33 // (the id lives in the event envelope, not the payload).│ │34 pub const IssueWithId = struct { │ │35 id: []const u8, │ │35 - issue: evt.Issue.Record, │ │36 + record: evt.Issue.Record, │ │37 // the creation commit's author │ │38 author: ui.Author = .unknown, │ │39 // whether the issue has an unresolved merge conflict│ ╰─────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────╮ │42 attachments: []const Attachment.WithId = &.{}, │ │43 }; │ │44 │ │45 +pub const Entry = IssueWithId; │ │46 + │ │47 // one side of a conflicted field: its value and who set it│ │48 pub const Side = struct { │ │49 text: []const u8, │ ╰───────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯