╭ Repos.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 const std = @import("std"); 2 const evt = @import("../../event.zig"); 3 const ui = @import("../../ui.zig"); 4 const xit = @import("xit"); 5 const hash = xit.hash; 6 const xitui = xit.xitui; 7 const wgt = xitui.widget; 8 const layout = xitui.layout; 9 const inp = xitui.input; 10 const Grid = xitui.grid.Grid; 11 const Focus = xitui.focus.Focus; 12 13 repos: []const evt.Repo, 14 owner_names: []const []const u8, 15 16 const Self = @This(); 17 18 pub fn init( 19 arena: *std.heap.ArenaAllocator, 20 haxy_moment: evt.AdminDB.HashMap(.read_only), 21 ) !Self { 22 const DB = evt.AdminDB; 23 const hash_kind = evt.admin_repo_opts.hash; 24 25 var repos: std.ArrayList(evt.Repo) = .empty; 26 var owner_names: std.ArrayList([]const u8) = .empty; 27 28 const event_id_to_repo_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, "event-id->repo")) orelse return error.NotFound; 29 const event_id_to_repo = try DB.HashMap(.read_only).init(event_id_to_repo_cursor); 30 31 var repos_iter = try event_id_to_repo.iterator(); 32 while (try repos_iter.next()) |kv_cursor| { 33 const kv = try kv_cursor.readKeyValuePair(); 34 const repo_map = try DB.HashMap(.read_only).init(kv.value_cursor); 35 const repo_event = try evt.read(evt.Repo, DB, hash_kind, arena, repo_map); 36 try repos.append(arena.allocator(), repo_event); 37 38 const owner = try evt.User.readById(DB, hash_kind, haxy_moment, arena, repo_event.user_id); 39 try owner_names.append(arena.allocator(), if (owner) |o| o.name else ""); 40 } 41 42 return .{ 43 .repos = repos.items, 44 .owner_names = owner_names.items, 45 }; 46 } 47 48 pub const View = struct { 49 list: ui.FlowBox.Scroll, 50 data: *const Self, 51 52 pub fn init(allocator: std.mem.Allocator, data: *const Self) !View { 53 var self = blk: { 54 var list = try ui.FlowBox.Scroll.init(allocator, .{}); 55 errdefer list.deinit(allocator); 56 57 break :blk View{ 58 .list = list, 59 .data = data, 60 }; 61 }; 62 errdefer self.deinit(allocator); 63 64 var arena = std.heap.ArenaAllocator.init(allocator); 65 defer arena.deinit(); 66 const aa = arena.allocator(); 67 68 const lines = try aa.alloc([]const u8, data.repos.len); 69 const links = try aa.alloc([]const u8, data.repos.len); 70 for (data.repos, 0..) |repo, i| { 71 lines[i] = try std.fmt.allocPrint(aa, "{s} - {s}", .{ repo.name, repo.description }); 72 // clicking a repo opens its page; the "a:" prefix makes the web 73 // renderer emit an <a href="/repo/alice/foo"> anchor. skip the link 74 // when the owner is unknown so it isn't a dead route. 75 const owner = data.owner_names[i]; 76 links[i] = if (owner.len > 0) try std.fmt.allocPrint(aa, "a:/repo/{s}/{s}", .{ owner, repo.name }) else ""; 77 } 78 try self.list.setItems(allocator, lines, links); 79 80 return self; 81 } 82 83 pub fn deinit(self: *View, allocator: std.mem.Allocator) void { 84 self.list.deinit(allocator); 85 } 86 87 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 88 try self.list.build(allocator, constraint, root_focus); 89 } 90 91 pub fn input(self: *View, allocator: std.mem.Allocator, key: inp.Key, root_focus: *Focus) !void { 92 try self.list.input(allocator, key, root_focus); 93 } 94 95 pub fn clearGrid(self: *View) void { 96 self.list.clearGrid(); 97 } 98 99 pub fn getGrid(self: View) ?Grid { 100 return self.list.getGrid(); 101 } 102 103 pub fn getFocus(self: *View) *Focus { 104 return self.list.getFocus(); 105 } 106 107 pub fn getSelectedIndex(self: View) ?usize { 108 return self.list.getSelectedIndex(); 109 } 110 }; 111