╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────╮ │src/ui/NewRepo.zig│ ╰──────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │53 │ │54 { │ │55 - var hash_radio = try ui.widget.Radio.init(allocator, session, "hash", &.{ "sha1", "sha256" }, if (saved_fields) |saved| @tagName(saved.hash) else "sha1"); │ │55 + var hash_radio = try ui.widget.Radio.init(allocator, session, "hash", &.{ "sha1", "sha256" }, if (saved_fields) |saved| @tagName(saved.hash) else "sha1", null);│ │56 errdefer hash_radio.deinit(allocator); │ │57 try box.children.put(allocator, hash_radio.getFocus().id, .{ .widget = .{ .radio = hash_radio }, .rect = null, .min_size = .{ .width = null, .height = 3 } }); │ │58 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/Repo.zig│ ╰───────────────╯ ╭──────────────────────────────────────────────────────────────╮ │18 pub const Commits = @import("./Repo/Commits.zig"); │ │19 pub const Diff = @import("./Repo/Diff.zig"); │ │20 pub const Refs = @import("./Repo/Refs.zig"); │ │21 +pub const Discussions = @import("./Repo/Discussions.zig");│ │22 pub const Issues = @import("./Repo/Issues.zig"); │ │23 pub const Patches = @import("./Repo/Patches.zig"); │ │23 -pub const Discussions = @import("./Repo/Discussions.zig");│ │24 pub const Comment = @import("./Repo/Comment.zig"); │ │25 pub const Undo = @import("./Repo/Undo.zig"); │ │26 pub const Events = @import("./Repo/Events.zig"); │ ╰──────────────────────────────────────────────────────────────╯ ╭───────────────────────────────╮ │33 files: Files, │ │34 changes: Changes, │ │35 refs: Refs, │ │36 +discussions: Discussions, │ │37 issues: Issues, │ │38 patches: Patches, │ │38 -discussions: Discussions, │ │39 events: Events, │ │40 undo: ?Undo = null, │ │41 settings: ?Settings = null,│ ╰───────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │120 }; │ │121 const refs_search: []const u8 = switch (route) { │ │122 .repo_refs => |*r| r.search.slice(), │ │123 + else => "", │ │124 + }; │ │125 + const discussions_label: []const u8 = switch (route) { │ │126 + .repo_discussions => |*t| t.label.slice(), │ │127 + else => "", │ │128 + }; │ │129 + const discussions_search: []const u8 = switch (route) { │ │130 + .repo_discussions => |*t| t.search.slice(), │ │131 + else => "", │ │132 + }; │ │133 + const discussions_selected: []const u8 = switch (route) { │ │134 + .repo_discussions => |*t| t.selected.slice(), │ │135 else => "", │ │136 }; │ │137 + const discussions_comment: []const u8 = switch (route) { │ │138 + .repo_discussions => |*t| t.comment.slice(), │ │139 + else => "", │ │140 + }; │ │141 + const discussions_view: ui.RoutablePage.DiscussionsView = switch (route) { │ │142 + .repo_discussions => |t| t.view, │ │143 + else => .recent, │ │144 + }; │ │145 + const discussions_comments_start: usize = switch (route) { │ │146 + .repo_discussions => |t| t.comments_start, │ │147 + else => 0, │ │148 + }; │ │149 // the issues tab's label filter, the issue its window is rooted at, and the│ │150 // view it shows. │ │151 const issues_label: []const u8 = switch (route) { │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │202 }; │ │203 const patches_comments_start: usize = switch (route) { │ │204 .repo_patches => |p| p.comments_start, │ │181 - else => 0, │ │182 - }; │ │183 - const discussions_label: []const u8 = switch (route) { │ │184 - .repo_discussions => |*t| t.label.slice(), │ │185 - else => "", │ │186 - }; │ │187 - const discussions_search: []const u8 = switch (route) { │ │188 - .repo_discussions => |*t| t.search.slice(), │ │189 - else => "", │ │190 - }; │ │191 - const discussions_selected: []const u8 = switch (route) { │ │192 - .repo_discussions => |*t| t.selected.slice(), │ │193 - else => "", │ │194 - }; │ │195 - const discussions_comment: []const u8 = switch (route) { │ │196 - .repo_discussions => |*t| t.comment.slice(), │ │197 - else => "", │ │198 - }; │ │199 - const discussions_view: ui.RoutablePage.DiscussionsView = switch (route) {│ │200 - .repo_discussions => |t| t.view, │ │201 - else => .recent, │ │202 - }; │ │203 - const discussions_comments_start: usize = switch (route) { │ │204 - .repo_discussions => |t| t.comments_start, │ │205 else => 0, │ │206 }; │ │207 const events_kind: ?evt.EventKind = switch (route) { │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │234 source = local; │ │235 // local routes elide the identity, so the display name comes from the │ │236 // repo's directory rather than the route. │ │237 - repo = .{ .event = .{ │ │238 - .user_id = "", │ │239 - .name = try arena.allocator().dupe(u8, std.Io.Dir.path.basename(local.path)), │ │240 - .description = "", │ │241 - } }; │ │237 + repo = .{ │ │238 + .event = .{ │ │239 + .user_id = "", │ │240 + .name = try arena.allocator().dupe(u8, std.Io.Dir.path.basename(local.path)),│ │241 + .description = "", │ │242 + // local mode shows every tab │ │243 + .discuss_role = .read, │ │244 + .issue_role = .read, │ │245 + .patch_role = .read, │ │246 + }, │ │247 + }; │ │248 owner_name = ""; │ │249 } else { │ │250 const haxy_moment = session.haxy_moment orelse return error.NoMoment; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │277 // no filesystem (wasm), nowhere to look, or a failed open: empty tabs. │ │278 // the events tab needs write access, like undo │ │279 if (route == .repo_events and !handle.canWrite()) return error.NotFound; │ │280 + // a tab that is off doesn't exist │ │281 + const route_thread_kind: ?evt.EventKind = switch (route) { │ │282 + .repo_discussions => .discuss, │ │283 + .repo_issues => .issue, │ │284 + .repo_patches => .patch, │ │285 + else => null, │ │286 + }; │ │287 + if (route_thread_kind) |kind| if (repo.event.threadRole(kind) == null) return error.NotFound;│ │288 const undo_index = if (route == .repo_undo) route.repo_undo.index else null; │ │289 const undo_clear = route == .repo_undo and route.repo_undo.clear; │ │290 // only xit repos have undo history, so it's read in their branch below │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │291 var undo_data: ?Undo = null; │ │292 // only the owner sees the settings, which show the repo's hash kind │ │293 var settings: ?Settings = null; │ │280 - const files, const changes, const refs, var issues, var patches, var discussions, const events = blk: {│ │294 + const files, const changes, const refs, var discussions, var issues, var patches, const events = blk: {│ │295 read: { │ │296 const io = session.io orelse break :read; │ │297 const src = source orelse break :read; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │312 .name = repo.event.name, │ │313 .description = repo.event.description, │ │314 .access = repo.event.read_access, │ │315 + .discuss_role = repo.event.discuss_role, │ │316 + .issue_role = repo.event.issue_role, │ │317 + .patch_role = repo.event.patch_role, │ │318 .hash_kind = opened.self_repo_opts.hash, │ │319 }; │ │320 // tabs switch in-page, so every tab's data is read here│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │346 files_data, │ │347 changes_data, │ │348 try Refs.init(repo_kind, opened.self_repo_opts, arena, opened, io, gpa, repo_identity.identity, refs_kind, refs_from, refs_search), │ │332 - try Issues.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, issues_label, issues_search, issues_selected, issues_comment, issues_comments_start, issues_theirs, issues_view, handle.viewer), │ │333 - try Patches.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, session, repo_id_maybe, repo_identity.identity, target_branch, patches_label, patches_search, patches_selected, patches_comment, patches_comments_start, patches_theirs, patches_view, handle.viewer), │ │334 - try Discussions.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, discussions_label, discussions_search, discussions_selected, discussions_comment, discussions_comments_start, discussions_view, handle.viewer), │ │335 - try Events.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, events_view, events_kind, events_selected, events_moment, session.local != null, session.data.sync_failure), │ │349 + try Discussions.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, discussions_label, discussions_search, discussions_selected, discussions_comment, discussions_comments_start, discussions_view, tabViewer(handle, repo, .discuss)), │ │350 + try Issues.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, issues_label, issues_search, issues_selected, issues_comment, issues_comments_start, issues_theirs, issues_view, tabViewer(handle, repo, .issue)), │ │351 + try Patches.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, session, repo_id_maybe, repo_identity.identity, target_branch, patches_label, patches_search, patches_selected, patches_comment, patches_comments_start, patches_theirs, patches_view, tabViewer(handle, repo, .patch)),│ │352 + try Events.init(repo_kind, opened.self_repo_opts, arena, opened, io, session.haxy_moment, repo_identity.identity, repo.event, events_view, events_kind, events_selected, events_moment, session.local != null, session.data.sync_failure), │ │353 }; │ │354 }, │ │355 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯