╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Header.zig│ ╰──────────────────────╯ ╭──────────────────────────────────────────────────────────────────────╮ │298 }); │ │299 } │ │300 │ │298 - // spacer pushes settings + auth to the right │ │301 + // spacer pushes settings, new repo and auth to the right│ │302 { │ │303 var spacer = try ui.widget.Spacer.init(allocator); │ │304 errdefer spacer.deinit(allocator); │ ╰──────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │307 .rect = null, │ │308 .min_size = null, │ │309 .flex = .grow, │ │310 + }); │ │311 + } │ │312 + │ │313 + // new repo tab. repos are created for the logged-in user. │ │314 + if (session.data.user_id != null) { │ │315 + var text_box = try wgt.TextBox.init(allocator, new_repo_tab_label, .{ .border_style = .single, .round_corners = true, .wrap_kind = .none });│ │316 + errdefer text_box.deinit(allocator); │ │317 + text_box.getFocus().mode = .all; │ │318 + text_box.getFocus().kind = .{ .custom = new_repo_link }; │ │319 + try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │320 + if (current_tag == .repo_new_repo) selected_tab = text_box.getFocus().id; │ │321 + try tabs_box.children.put(allocator, text_box.getFocus().id, .{ │ │322 + .widget = .{ .text_box = text_box }, │ │323 + .rect = null, │ │324 + .min_size = .{ .width = new_repo_tab_label.len + 2, .height = null }, │ │325 }); │ │326 } │ │327 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Patches.zig│ ╰───────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │385 const patch_id = evt.parseEventId(id) catch return error.NotFound; │ │386 │ │387 const id_hex = std.fmt.bytesToHex(patch_id, .lower); │ │388 - var target_repo = try rp.Repo(.xit, .{}).open(io, allocator, repo_source.localInitOpts()); │ │388 + var target_repo = try rp.AnyRepo(.xit, .{}).open(io, allocator, repo_source.localInitOpts()); │ │389 defer target_repo.deinit(io, allocator); │ │390 - try pch.publish(.{}, io, allocator, users_dir, admin_repo, &target_repo, .{ │ │391 - .id = id_hex, │ │392 - .user_id = user_id, │ │393 - .repo_id = repo_id, │ │394 - .author = author, │ │395 - .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │396 - }); │ │390 + switch (target_repo) { │ │391 + inline else => |*repo| try pch.publish(repo.self_repo_opts, io, allocator, users_dir, admin_repo, repo, .{ │ │392 + .id = id_hex, │ │393 + .user_id = user_id, │ │394 + .repo_id = repo_id, │ │395 + .author = author, │ │396 + .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │397 + }), │ │398 + } │ │399 } │ │400 │ │401 pub fn mergePatch(data: *const Self, session: *ui.Session, allocator: std.mem.Allocator, author: evt.CommitAuthor, id: []const u8, revision: evt.Patch.MergeRevision) !void {│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │406 const patch_id = evt.parseEventId(id) catch return error.NotFound; │ │407 │ │408 const id_hex = std.fmt.bytesToHex(patch_id, .lower); │ │407 - var target_repo = try rp.Repo(.xit, .{}).open(io, allocator, repo_source.localInitOpts()); │ │409 + var target_repo = try rp.AnyRepo(.xit, .{}).open(io, allocator, repo_source.localInitOpts()); │ │410 defer target_repo.deinit(io, allocator); │ │409 - try pch.mergeAndRemoveFork(.{}, io, allocator, users_dir, &target_repo, .{ │ │410 - .id = id_hex, │ │411 - .revision = revision, │ │412 - .author = author, │ │413 - .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │414 - }); │ │411 + switch (target_repo) { │ │412 + inline else => |*repo| try pch.mergeAndRemoveFork(repo.self_repo_opts, io, allocator, users_dir, repo, .{│ │413 + .id = id_hex, │ │414 + .revision = revision, │ │415 + .author = author, │ │416 + .timestamp = @intCast(std.Io.Timestamp.now(io, .real).toSeconds()), │ │417 + }), │ │418 + } │ │419 } │ │420 │ │421 pub fn editDraft( │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │866 break; │ │867 } │ │868 const path = try fork.forkPath(aa, users_dir, &user_id, &id); │ │865 - var fork_repo = rp.Repo(.xit, .{}).open(io, arena.child_allocator, .{ .path = path, .require_repo_root = true }) catch continue; │ │869 + // a fork shares its target's hash kind │ │870 + var fork_repo = rp.Repo(.xit, .{ .hash = repo_opts.hash }).open(io, arena.child_allocator, .{ .path = path, .require_repo_root = true }) catch continue;│ │871 defer fork_repo.deinit(io, arena.child_allocator); │ │872 const entry = (try loadDraftEntry(repo_kind, repo_opts, arena, io, admin_moment, &fork_repo, target_repo, id, user_name)) orelse continue; │ │873 try items.append(aa, entry); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────╮ │886 arena: *std.heap.ArenaAllocator, │ │887 io: std.Io, │ │888 admin_moment: ?evt.AdminDB.HashMap(.read_only), │ │884 - fork_repo: *rp.Repo(.xit, .{}), │ │889 + fork_repo: *rp.Repo(.xit, .{ .hash = repo_opts.hash }),│ │890 target_repo: *rp.Repo(repo_kind, repo_opts), │ │891 id: [evt.event_id_size]u8, │ │892 forker: []const u8, │ ╰────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │894 const aa = arena.allocator(); │ │895 const id_hex = std.fmt.bytesToHex(id, .lower); │ │896 const fork_oid = (try fork_repo.readRef(io, fork.ref)) orelse return null; │ │892 - const moment = evt.currentMoment(.{}, fork_repo) catch return null; │ │893 - const patch = (try evt.Patch.readById(evt.EventDB(.sha1), .sha1, moment, arena, &id)) orelse return null; │ │897 + const moment = evt.currentMoment(.{ .hash = repo_opts.hash }, fork_repo) catch return null; │ │898 + const patch = (try evt.Patch.readById(evt.EventDB(repo_opts.hash), repo_opts.hash, moment, arena, &id)) orelse return null;│ │899 const target_branch = patch.event.target_branch; │ │900 const target_oid = try target_repo.readRef(io, .{ .kind = .head, .name = target_branch }); │ │901 const commit_count: ?u64 = blk: { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │897 - const newest = evt.PatchRev.readNewest(evt.EventDB(.sha1), .sha1, moment, arena) catch break :blk null; │ │902 + const newest = evt.PatchRev.readNewest(evt.EventDB(repo_opts.hash), repo_opts.hash, moment, arena) catch break :blk null;│ │903 break :blk if (newest) |revision| revision.record.commit_count else 0; │ │904 }; │ │905 return .{ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/User.zig│ ╰───────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │142 │ │143 var title: []const u8 = "(unavailable)"; │ │144 const path = try fork.forkPath(arena.allocator(), users_dir, &user_id, &fork_id); │ │145 - if (rp.Repo(.xit, .{}).open(io, gpa, .{ .path = path, .require_repo_root = true })) |opened| { │ │146 - var fork_repo = opened; │ │147 - defer fork_repo.deinit(io, gpa); │ │148 - if (evt.currentMoment(.{}, &fork_repo)) |fork_moment| { │ │149 - if (try evt.Patch.readById(evt.EventDB(.sha1), .sha1, fork_moment, arena, &fork_id)) |patch| title = patch.event.title; │ │150 - } else |_| {} │ │145 + if (rp.AnyRepo(.xit, .{}).open(io, gpa, .{ .path = path, .require_repo_root = true })) |opened| { │ │146 + var any_fork = opened; │ │147 + defer any_fork.deinit(io, gpa); │ │148 + switch (any_fork) { │ │149 + inline else => |*fork_repo| if (evt.currentMoment(fork_repo.self_repo_opts, fork_repo)) |fork_moment| { │ │150 + const kind = fork_repo.self_repo_opts.hash; │ │151 + if (try evt.Patch.readById(evt.EventDB(kind), kind, fork_moment, arena, &fork_id)) |patch| title = patch.event.title;│ │152 + } else |_| {}, │ │153 + } │ │154 } else |_| {} │ │155 try forks.append(arena.allocator(), .{ │ │156 .id = try arena.allocator().dupe(u8, &fork_id_hex), │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │233 try stack.children.put(allocator, list.getFocus().id, .{ .flow_box_scroll = list }); │ │234 } │ │235 │ │233 - // the header has no settings tab without a login, so keep the │ │234 - // stack's children 1:1 with the tabs by skipping the view too │ │236 + // the header has no new repo or settings tab without a login, so keep the │ │237 + // stack's children 1:1 with the tabs by skipping those views too │ │238 + if (session.data.user_id != null) { │ │239 + const route = ui.RoutablePage{ .user_new_repo = ui.RoutablePage.Array(evt.User.name_max_len).from(data.user.name) orelse return error.RouteTooLong };│ │240 + var new_repo_view = try ui.NewRepo.View.init(allocator, session, route); │ │241 + errdefer new_repo_view.deinit(allocator); │ │242 + try stack.children.put(allocator, new_repo_view.getFocus().id, .{ .new_repo = new_repo_view }); │ │243 + } │ │244 + │ │245 if (session.data.user_id != null) { │ │246 var settings_view = try Settings.View.init(allocator, session); │ │247 errdefer settings_view.deinit(allocator); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯