╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Header.zig│ ╰──────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │235 - .min_size = .{ .width = issues_tab_label.len + 2, .height = null }, │ │235 + .min_size = .{ .width = discuss_tab_label.len + 2, .height = null },│ │236 }); │ │237 } │ │238 │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │239 - // patches tab │ │240 - { │ │241 - var text_box = try wgt.TextBox.init(allocator, patches_tab_label, .{ .border = .single, .round_corners = true, .wrap_kind = .none });│ │239 + // issues tab, unless it is off │ │240 + if (page.repo.event.issue_role != null) { │ │241 + var text_box = try wgt.TextBox.init(allocator, issues_tab_label, .{ .border = .single, .round_corners = true, .wrap_kind = .none }); │ │242 errdefer text_box.deinit(allocator); │ │243 text_box.getFocus().mode = .all; │ │244 - text_box.getFocus().kind = .{ .custom = patches_link }; │ │244 + text_box.getFocus().kind = .{ .custom = issues_link }; │ │245 try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │246 - if (current_tag == .repo_patches) selected_tab = text_box.getFocus().id; │ │246 + if (current_tag == .repo_issues) selected_tab = text_box.getFocus().id; │ │247 try tabs_box.children.put(allocator, text_box.getFocus().id, .{ │ │248 .widget = .{ .text_box = text_box }, │ │249 .rect = null, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │250 - .min_size = .{ .width = patches_tab_label.len + 2, .height = null },│ │250 + .min_size = .{ .width = issues_tab_label.len + 2, .height = null }, │ │251 }); │ │252 } │ │253 │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │254 - // discuss tab │ │255 - { │ │256 - var text_box = try wgt.TextBox.init(allocator, discuss_tab_label, .{ .border = .single, .round_corners = true, .wrap_kind = .none });│ │254 + // patches tab, unless it is off │ │255 + if (page.repo.event.patch_role != null) { │ │256 + var text_box = try wgt.TextBox.init(allocator, patches_tab_label, .{ .border = .single, .round_corners = true, .wrap_kind = .none });│ │257 errdefer text_box.deinit(allocator); │ │258 text_box.getFocus().mode = .all; │ │259 - text_box.getFocus().kind = .{ .custom = discussions_link }; │ │259 + text_box.getFocus().kind = .{ .custom = patches_link }; │ │260 try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │261 - if (current_tag == .repo_discussions) selected_tab = text_box.getFocus().id; │ │261 + if (current_tag == .repo_patches) selected_tab = text_box.getFocus().id; │ │262 try tabs_box.children.put(allocator, text_box.getFocus().id, .{ │ │263 .widget = .{ .text_box = text_box }, │ │264 .rect = null, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │265 - .min_size = .{ .width = discuss_tab_label.len + 2, .height = null },│ │265 + .min_size = .{ .width = patches_tab_label.len + 2, .height = null },│ │266 }); │ │267 } │ │268 │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────────╮ │src/ui/Repo/Settings.zig│ ╰────────────────────────╯ ╭─────────────────────────────────╮ │22 name: []const u8, │ │23 description: []const u8, │ │24 access: evt.Repo.Access, │ │25 +discuss_role: ?evt.Repo.Role,│ │26 +issue_role: ?evt.Repo.Role, │ │27 +patch_role: ?evt.Repo.Role, │ │28 hash_kind: hash.HashKind, │ │29 │ │30 const Self = @This(); │ ╰─────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────╮ │31 │ │32 +// the tab role choices, in the order the form shows them │ │33 +const role_choices = [_]?evt.Repo.Role{ null, .owner, .write, .read }; │ │34 + │ │35 +const role_labels = blk: { │ │36 + var labels: [role_choices.len][]const u8 = undefined; │ │37 + for (&labels, role_choices) |*label, role| label.* = roleLabel(role);│ │38 + break :blk labels; │ │39 +}; │ │40 + │ │41 +pub fn roleLabel(role_maybe: ?evt.Repo.Role) []const u8 { │ │42 + const role = role_maybe orelse return "nobody"; │ │43 + return switch (role) { │ │44 + .owner => "owners", │ │45 + .write => "collaborators", │ │46 + .read => "anybody", │ │47 + }; │ │48 +} │ │49 + │ │50 +// the tab role a label names │ │51 +pub fn labelRole(label: []const u8) error{InvalidRole}!?evt.Repo.Role { │ │52 + for (role_choices) |role| { │ │53 + if (std.mem.eql(u8, label, roleLabel(role))) return role; │ │54 + } │ │55 + return error.InvalidRole; │ │56 +} │ │57 + │ │58 pub const View = struct { │ │30 - center: ui.widget.Center, │ │59 + // a centered form, scrolled when it outgrows the window │ │60 + scroll: wgt.Scroll(ui.Widget), │ │61 data: *const Self, │ │62 session: *ui.Session, │ │63 │ ╰─────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │34 - const access_index: usize = 2; │ │35 - const hash_index: usize = 3; │ │36 - │ │64 pub fn init(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session) !View { │ │65 var box = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .vert });│ │66 errdefer box.deinit(allocator); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │92 │ │93 { │ │94 const access = if (saved_fields) |saved| saved.access else data.access; │ │68 - var access_radio = try ui.widget.Radio.init(allocator, session, "access", &.{ "private", "public" }, @tagName(access)); │ │95 + var access_radio = try ui.widget.Radio.init(allocator, session, "access", &.{ "private", "public" }, @tagName(access), null); │ │96 errdefer access_radio.deinit(allocator); │ │97 try box.children.put(allocator, access_radio.getFocus().id, .{ .widget = .{ .radio = access_radio }, .rect = null, .min_size = .{ .width = null, .height = 3 } });│ │98 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │101 var hash_box = try wgt.TextBox.init(allocator, @tagName(data.hash_kind), .{ .border = .single, .round_corners = true, .wrap_kind = .none, .top_label = .{ .text = " hash " } });│ │102 errdefer hash_box.deinit(allocator); │ │103 try box.children.put(allocator, hash_box.getFocus().id, .{ .widget = .{ .text_box = hash_box }, .rect = null, .min_size = .{ .width = null, .height = 3 } }); │ │104 + } │ │105 + │ │106 + const roles = [_]struct { name: []const u8, label: []const u8, role: ?evt.Repo.Role }{ │ │107 + .{ .name = "discuss_role", .label = " who can create discussions ", .role = if (saved_fields) |saved| saved.discuss_role else data.discuss_role }, │ │108 + .{ .name = "issue_role", .label = " who can create issues ", .role = if (saved_fields) |saved| saved.issue_role else data.issue_role }, │ │109 + .{ .name = "patch_role", .label = " who can create patches ", .role = if (saved_fields) |saved| saved.patch_role else data.patch_role }, │ │110 + }; │ │111 + for (roles) |role| { │ │112 + var role_radio = try ui.widget.Radio.init(allocator, session, role.name, &role_labels, roleLabel(role.role), role.label); │ │113 + errdefer role_radio.deinit(allocator); │ │114 + try box.children.put(allocator, role_radio.getFocus().id, .{ .widget = .{ .radio = role_radio }, .rect = null, .min_size = null }); │ │115 } │ │116 │ │117 { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯