╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │194 repo_user_new: Array(repo_route_max_len), │ │195 repo_settings: Array(repo_route_max_len), │ │196 repo_members: RepoMembersRoute, │ │197 + repo_branches: RepoBranchesRoute, │ │198 repo_user: struct { name: Array(repo_route_max_len), tab: UserTab = .{} },│ │199 fork_patch: ForkRoute, │ │200 fork_diff: ForkDiffRoute, │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │335 const merge_seg = @tagName(Params.ParamKey.merge) ++ ":"; │ │336 const theirs_seg = @tagName(Params.ParamKey.theirs) ++ ":"; │ │337 const user_seg = @tagName(Params.ParamKey.user) ++ ":"; │ │338 + const branch_seg = @tagName(Params.ParamKey.branch) ++ ":"; │ │339 const key_seg = @tagName(Params.ParamKey.key) ++ ":"; │ │340 // ends a key removal's confirmation url, so its form posts to the removal│ │341 const remove_key_word = "removekey"; │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │449 confirm: ?Repo.Members.Action = null, │ │450 }; │ │451 │ │452 + pub const RepoBranchesRoute = struct { │ │453 + name: Array(repo_identity_max_len), │ │454 + // the url-encoded branch a row's form acts on ("" = none) │ │455 + branch: Array(ref_route_max_len) = .{}, │ │456 + }; │ │457 + │ │458 pub fn repoSettingsRoute(identity: []const u8) ?RoutablePage { │ │459 return .{ .repo_settings = Array(repo_route_max_len).from(identity) orelse return null };│ │460 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │461 │ │462 pub fn repoMembersRoute(identity: []const u8, start: usize) ?RoutablePage { │ │463 return .{ .repo_members = .{ .name = Array(repo_identity_max_len).from(identity) orelse return null, .start = start } };│ │464 + } │ │465 + │ │466 + pub fn repoBranchesRoute(identity: []const u8) ?RoutablePage { │ │467 + return .{ .repo_branches = .{ .name = Array(repo_identity_max_len).from(identity) orelse return null } }; │ │468 } │ │469 │ │470 pub fn repoUndoRoute(identity: []const u8, index: ?u64) ?RoutablePage { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1290 if (r.confirm) |action| try out.writer.print("/{s}", .{@tagName(action)}); │ │1291 break :blk out.written(); │ │1292 }, │ │1293 + .repo_branches => |b| blk: { │ │1294 + var out: std.Io.Writer.Allocating = .init(arena.allocator()); │ │1295 + try out.writer.print("{s}/repo/branches", .{try repoUrlPrefix(arena, b.name.slice())}); │ │1296 + if (b.branch.len != 0) try out.writer.print("/" ++ branch_seg ++ "{s}", .{b.branch.slice()});│ │1297 + break :blk out.written(); │ │1298 + }, │ │1299 .repo_user => |u| try userTabUrl(arena, try repoUrlPrefix(arena, u.name.slice()), u.tab), │ │1300 .fork_patch => |f| try arena.allocator().print("/{s}+{s}", .{ f.name.slice(), f.id.slice() }), │ │1301 .fork_diff => |d| blk: { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │1475 .repo_events => |*e| e.name.slice(), │ │1476 .repo_undo => |*u| u.name.slice(), │ │1477 .repo_members => |*r| r.name.slice(), │ │1478 + .repo_branches => |*b| b.name.slice(), │ │1479 .repo_user => |*u| u.name.slice(), │ │1480 .repo_settings, .repo_repo_new, .repo_user_new => |*name| name.slice(),│ │1481 else => null, │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1521 return switch (self) { │ │1522 .home_about, .home_users, .home_repo_new, .home_user_new, .home_user => .home, │ │1523 .user_repos, .user_forks, .user_repo_new, .user_user_new, .user_user => .user, │ │1505 - .repo_files, .repo_commits, .repo_diff, .repo_refs, .repo_issues, .repo_patches, .repo_discussions, .repo_events, .repo_undo, .repo_settings, .repo_members, .repo_repo_new, .repo_user_new, .repo_user => .repo, │ │1524 + .repo_files, .repo_commits, .repo_diff, .repo_refs, .repo_issues, .repo_patches, .repo_discussions, .repo_events, .repo_undo, .repo_settings, .repo_members, .repo_branches, .repo_repo_new, .repo_user_new, .repo_user => .repo,│ │1525 .fork_patch, .fork_diff, .fork_files, .fork_commits, .fork_repo_new, .fork_user_new, .fork_user => .fork, │ │1526 .not_found => .not_found, │ │1527 }; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1618 if ((action != .revoke and action != .demote) or route.repo_members.user.len == 0) return null; │ │1619 route.repo_members.confirm = action; │ │1620 } │ │1621 + return route; │ │1622 + } │ │1623 + if (std.mem.eql(u8, word, "branches")) { │ │1624 + _ = segments.next(); │ │1625 + if ((params.scanTail(&segments) catch return null) != null) return null; │ │1626 + if (!params.only(&.{.branch})) return null; │ │1627 + var route = repoBranchesRoute(pair) orelse return null; │ │1628 + if (params.values.get(.branch)) |branch| route.repo_branches.branch = Array(ref_route_max_len).from(branch) orelse return null;│ │1629 return route; │ │1630 } │ │1631 return if (isNewTail(&segments)) .{ .repo_repo_new = Array(repo_route_max_len).from(pair) orelse return null } else null; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1945 a_r.start == b.repo_members.start and │ │1946 std.mem.eql(u8, a_r.user.slice(), b.repo_members.user.slice()) and │ │1947 a_r.confirm == b.repo_members.confirm, │ │1948 + .repo_branches => |a_b| std.mem.eql(u8, a_b.name.slice(), b.repo_branches.name.slice()) and │ │1949 + std.mem.eql(u8, a_b.branch.slice(), b.repo_branches.branch.slice()), │ │1950 .repo_user => |a_u| std.mem.eql(u8, a_u.name.slice(), b.repo_user.name.slice()) and a_u.tab.eql(b.repo_user.tab), │ │1951 .fork_patch => |a_f| std.mem.eql(u8, a_f.name.slice(), b.fork_patch.name.slice()) and std.mem.eql(u8, a_f.id.slice(), b.fork_patch.id.slice()),│ │1952 .fork_diff => |a_d| std.mem.eql(u8, a_d.fork.name.slice(), b.fork_diff.fork.name.slice()) and │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────╮ │2398 }; │ │2399 │ │2400 pub const MembersFailure = enum { not_found, already_added }; │ │2401 + │ │2402 + pub const BranchesFailure = enum { │ │2403 + not_found, │ │2404 + already_added, │ │2405 + too_many, │ │2406 + too_long, │ │2407 │ │2408 + pub fn fromError(err: anyerror) ?BranchesFailure { │ │2409 + return switch (err) { │ │2410 + error.BranchProtected => .already_added, │ │2411 + error.TooManyProtectedBranches => .too_many, │ │2412 + else => null, │ │2413 + }; │ │2414 + } │ │2415 + }; │ │2416 + │ │2417 pub const AssignmentFailure = enum { not_found, not_an_email, already_assigned };│ │2418 │ │2419 pub const KeyFailure = enum { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯