╭ changed ──────────────╮ │src/ui/Repo/Patches.zig│ ╰───────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────╮ │ 5 const xit = @import("xit"); │ │ 6 const rp = xit.repo; │ │ 7 const hash = xit.hash; │ │ 8 -const rf = xit.ref; │ │ 8 const xitui = xit.xitui; │ │ 9 const wgt = xitui.widget; │ │10 const diff3 = @import("../../diff3.zig");│ ╰─────────────────────────────────────────────╯ ╭───────────────────────────────────────╮ │42 fork_oid: []const u8 = "", │ │43 target_branch: []const u8 = "",│ │44 no_changes: bool = false, │ │45 + fork_exists: bool = false, │ │46 }; │ │47 │ │48 pub const Entry = PatchWithId; │ ╰───────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │133 │ │134 pub fn listRoute(identity: []const u8, status: Status, tag: []const u8, selected: []const u8) ?ui.RoutablePage {│ │135 return ui.RoutablePage.repoPatchesRoute(identity, status, tag, selected); │ │136 +} │ │137 + │ │138 +pub fn forkRoute(identity: []const u8, id: []const u8) ?ui.RoutablePage { │ │139 + return ui.RoutablePage.forkPatchRoute(identity, id); │ │140 } │ │141 │ │142 pub fn draftsRoute(identity: []const u8) ?ui.RoutablePage { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │307 }; │ │308 } │ │309 │ │310 +pub fn detailResult(aa: std.mem.Allocator, identity: []const u8, entry: PatchWithId) !Self { │ │311 + var result = try emptyResult(aa, identity, "", entry.id, "", 0, "", .open); │ │312 + const items = try aa.dupe(PatchWithId, &.{entry}); │ │313 + const detail_window = Window{ .items = items, .prev_id = null, .next_id = null, .count = 1 };│ │314 + if (entry.draft) { │ │315 + result.drafts = detail_window; │ │316 + result.view = .drafts; │ │317 + } else switch (entry.record.event.status) { │ │318 + .open => result.open = detail_window, │ │319 + .closed => { │ │320 + result.closed = detail_window; │ │321 + result.view = .closed; │ │322 + }, │ │323 + .merged => { │ │324 + result.merged = detail_window; │ │325 + result.view = .merged; │ │326 + }, │ │327 + } │ │328 + return result; │ │329 +} │ │330 + │ │331 // read one window per status of an opened repo's patches (filtered to `tag` │ │332 // when set), ordered by creation (newest first). the window of the patch │ │333 // `selected_id` names starts at it ("" = the beginning). a git repo reads the │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │493 } │ │494 } │ │495 const thread_comments_start = if (empty.comment_id.len == 0) comments_start else 0; │ │471 - const open_window = try thread.loadWindow(Self, repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_patch, open_set, open_root, conflict_set, empty.selected_id, thread_comments_start); │ │472 - const closed_window = try thread.loadWindow(Self, repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_patch, closed_set, closed_root, conflict_set, empty.selected_id, thread_comments_start); │ │473 - const merged_window = try thread.loadWindow(Self, repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_patch, merged_set, merged_root, conflict_set, empty.selected_id, thread_comments_start); │ │474 - const conflicts_window = try thread.loadWindow(Self, repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_patch, conflict_set, conflicts_root, conflict_set, empty.selected_id, thread_comments_start);│ │496 + var open_window = try thread.loadWindow(Self, repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_patch, open_set, open_root, conflict_set, empty.selected_id, thread_comments_start); │ │497 + var closed_window = try thread.loadWindow(Self, repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_patch, closed_set, closed_root, conflict_set, empty.selected_id, thread_comments_start); │ │498 + var merged_window = try thread.loadWindow(Self, repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_patch, merged_set, merged_root, conflict_set, empty.selected_id, thread_comments_start); │ │499 + var conflicts_window = try thread.loadWindow(Self, repo_opts.hash, arena, admin_moment, haxy_moment, event_id_to_patch, conflict_set, conflicts_root, conflict_set, empty.selected_id, thread_comments_start); │ │500 + try setForkAvailability(arena, admin_moment, &open_window); │ │501 + try setForkAvailability(arena, admin_moment, &closed_window); │ │502 + try setForkAvailability(arena, admin_moment, &merged_window); │ │503 + try setForkAvailability(arena, admin_moment, &conflicts_window); │ │504 if (view == .conflicts and conflicts_window.count > 0) resolved_view = .conflicts; │ │505 │ │506 const comment_page = if (empty.comment_id.len == 0) │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │530 }; │ │531 } │ │532 │ │533 +fn setForkAvailability(arena: *std.heap.ArenaAllocator, admin_moment: ?evt.AdminDB.HashMap(.read_only), target: *Window) !void {│ │534 + const moment = admin_moment orelse return; │ │535 + if (target.items.len == 0) return; │ │536 + const items = try arena.allocator().dupe(PatchWithId, target.items); │ │537 + for (items) |*item| { │ │538 + const id = try evt.parseEventId(item.id); │ │539 + const record = try evt.Fork.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, arena, &id); │ │540 + item.fork_exists = if (record) |value| !value.removed else false; │ │541 + } │ │542 + target.items = items; │ │543 +} │ │544 + │ │545 fn loadDraftWindow( │ │546 comptime repo_kind: rp.RepoKind, │ │547 comptime repo_opts: rp.RepoOpts(repo_kind), │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │603 const path = try fork.forkPath(aa, repos_dir, &id_hex); │ │604 var fork_repo = rp.Repo(.xit, .{}).open(io, arena.child_allocator, .{ .path = path, .require_repo_root = true }) catch continue; │ │605 defer fork_repo.deinit(io, arena.child_allocator); │ │565 - const fork_oid = (try fork_repo.readRef(io, fork.ref)) orelse continue; │ │566 - const moment = evt.currentMoment(.{}, &fork_repo) catch continue; │ │567 - const patch = (try evt.Patch.readById(evt.EventDB(.sha1), .sha1, moment, arena, &id)) orelse continue; │ │568 - var revision_ready = false; │ │569 - var target_branch = default_target_branch; │ │570 - if (patch.event.revision) |revision| { │ │571 - const target_ref = rf.Ref.initFromPath(revision.target_ref, null) orelse continue; │ │572 - target_branch = switch (target_ref.kind) { │ │573 - .head => target_ref.name, │ │574 - else => continue, │ │575 - }; │ │576 - const revision_id = evt.parseEventId(&revision.id) catch continue; │ │577 - if (try evt.PatchRev.readById(evt.EventDB(.sha1), .sha1, moment, arena, &revision_id)) |record| │ │578 - revision_ready = revision.matches(record); │ │579 - } │ │580 - const target_oid = if (target_branch.len != 0) │ │581 - try target_repo.readRef(io, .{ .kind = .head, .name = target_branch }) │ │582 - else │ │583 - null; │ │584 - try items.append(aa, .{ │ │585 - .id = try aa.dupe(u8, &id_hex), │ │586 - .record = patch, │ │587 - .author = try ui.Author.initFromEmail(admin_moment, arena, patch.author_email), │ │588 - .draft = true, │ │589 - .revision_ready = revision_ready, │ │590 - .fork_oid = try aa.dupe(u8, &fork_oid), │ │591 - .target_branch = try aa.dupe(u8, target_branch), │ │592 - .no_changes = if (target_oid) |oid| std.mem.eql(u8, &oid, &fork_oid) else false, │ │593 - }); │ │606 + const entry = (try loadDraftEntry(repo_kind, repo_opts, arena, io, admin_moment, &fork_repo, target_repo, id, default_target_branch)) orelse continue;│ │607 + try items.append(aa, entry); │ │608 } │ │609 return .{ │ │610 .items = items.items, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │614 }; │ │615 } │ │616 │ │617 +pub fn loadDraftEntry( │ │618 + comptime repo_kind: rp.RepoKind, │ │619 + comptime repo_opts: rp.RepoOpts(repo_kind), │ │620 + arena: *std.heap.ArenaAllocator, │ │621 + io: std.Io, │ │622 + admin_moment: ?evt.AdminDB.HashMap(.read_only), │ │623 + fork_repo: *rp.Repo(.xit, .{}), │ │624 + target_repo: *rp.Repo(repo_kind, repo_opts), │ │625 + id: [evt.event_id_size]u8, │ │626 + default_target_branch: []const u8, │ │627 +) !?PatchWithId { │ │628 + const aa = arena.allocator(); │ │629 + const id_hex = std.fmt.bytesToHex(id, .lower); │ │630 + const fork_oid = (try fork_repo.readRef(io, fork.ref)) orelse return null; │ │631 + const moment = evt.currentMoment(.{}, fork_repo) catch return null; │ │632 + const patch = (try evt.Patch.readById(evt.EventDB(.sha1), .sha1, moment, arena, &id)) orelse return null;│ │633 + var revision_ready = false; │ │634 + var target_branch = default_target_branch; │ │635 + if (patch.event.revision) |revision| { │ │636 + target_branch = revision.targetBranch() orelse return null; │ │637 + const revision_id = evt.parseEventId(&revision.id) catch return null; │ │638 + if (try evt.PatchRev.readById(evt.EventDB(.sha1), .sha1, moment, arena, &revision_id)) |record| │ │639 + revision_ready = revision.matches(record); │ │640 + } │ │641 + const target_oid = if (target_branch.len != 0) │ │642 + try target_repo.readRef(io, .{ .kind = .head, .name = target_branch }) │ │643 + else │ │644 + null; │ │645 + return .{ │ │646 + .id = try aa.dupe(u8, &id_hex), │ │647 + .record = patch, │ │648 + .author = try ui.Author.initFromEmail(admin_moment, arena, patch.author_email), │ │649 + .draft = true, │ │650 + .revision_ready = revision_ready, │ │651 + .fork_oid = try aa.dupe(u8, &fork_oid), │ │652 + .target_branch = try aa.dupe(u8, target_branch), │ │653 + .no_changes = if (target_oid) |oid| std.mem.eql(u8, &oid, &fork_oid) else false, │ │654 + .fork_exists = true, │ │655 + }; │ │656 +} │ │657 + │ │658 pub const View = thread.View(.patch, Self); │ │659 │ │660 pub const Header = thread.Header; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯