╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ thread.zig ───────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
2892 } 2893 2894 fn submitConfirmation(self: *This, allocator: std.mem.Allocator, button_index: usize) !void { 2895 switch (confirmation(self.data.view) orelse return) { 2896 .publish => if (comptime supports_drafts) { 2897 if (comptime wasm) return; 2898 const entry = self.data.selectedThread() orelse return; 2899 if (!entryDraft(entry.*)) return; 2900 const author = ((try self.session.authorize(self.data.identity, .read)) orelse return).author; 2901 try self.data.publishDraft(self.session, allocator, author, entry.id); 2902 const route = listRoute(self.data.identity, @enumFromInt(0), "", entry.id) orelse return; 2903 try self.session.navigate(route); 2904 } else unreachable, 2905 .merge => if (comptime supports_merge) { 2906 if (comptime wasm) return; 2907 const entry = self.data.selectedThread() orelse return; 2908 const revision: evt.Patch.MergeRevision = if (button_index > 1) .squash else .source; 2909 if (!Data.canMerge(entry.*, self.session) or entry.mergeability.get(revision) != .clean) return; 2910 const author = ((try self.session.authorize(self.data.identity, .write)) orelse return).author; 2911 self.data.mergePatch(self.session, allocator, author, entry.id, revision) catch |err| switch (err) { 2912 error.MergeConflict, error.MergeCheckUnavailable, error.PatchOutOfDate, error.PatchDataUnavailable => { 2913 const route = listRoute(self.data.identity, entryStatus(entry.*), "", entry.id) orelse return; 2914 try self.session.navigate(route); 2915 return; 2916 }, 2917 else => return err, 2918 }; 2919 const merged = std.meta.stringToEnum(Status, "merged") orelse return; 2920 const route = listRoute(self.data.identity, merged, "", entry.id) orelse return; 2921 try self.session.navigate(route); 2922 } else unreachable, 2923 .remove => try self.submitRemove(allocator), 2924 } 2925 } 2926 2927 fn submitRemove(self: *This, allocator: std.mem.Allocator) !void { 2928 const comment = self.data.comment_id.len != 0; 2929 const event_id = if (comment) self.data.comment_id else self.data.selected_id; 2930 const id = evt.parseEventId(event_id) catch return; 2931 try self.removeEvent(allocator, if (comment) .comment else kind, id); 2932 } 2933 2934 fn removeEvent(self: *This, allocator: std.mem.Allocator, event_kind: evt.EventKind, id: [evt.event_id_size]u8) !void { 2935 if (comptime wasm) return; 2936 const actor = (try self.session.authorize(self.data.identity, .read)) orelse return; 2937 const author = actor.author; 2938 2939 if (comptime supports_drafts) { 2940 const selected = self.data.selectedThread() orelse return; 2941 if (event_kind == kind and entryDraft(selected.*)) { 2942 try Data.removeDraft(self.session, allocator, author, &id); 2943 const route = draftsRoute(self.data.identity) orelse return; 2944 try self.session.navigate(route); 2945 return; 2946 } 2947 } 2948 2949 const io = self.session.io orelse return; 2950 const src = self.data.repo_source orelse return; 2951 if (!try src.canModify(io, allocator, actor, event_kind, &id)) return; 2952 2953 switch (src.repo_kind) { 2954 inline else => |repo_kind| { 2955 var any_repo = try rp.AnyRepo(repo_kind, .{}).open(io, allocator, src.localInitOpts()); 2956 defer any_repo.deinit(io, allocator); 2957 switch (any_repo) { 2958 inline else => |*repo| try evt.remove(self.session.eventHost(), .repo, repo_kind, repo.self_repo_opts, io, allocator, repo, &id, event_kind, author), 2959 } 2960 }, 2961 } 2962 2963 const id_hex = std.fmt.bytesToHex(id, .lower); 2964 const route = ui.RoutablePage.repoEventsRoute(self.data.identity, .removed, event_kind, &id_hex, null) orelse return; 2965 try self.session.navigate(route); 2966 } 2967 2968 // return to the list. 2969 fn focusList(self: *This, index: usize, root_focus: *Focus) void { 2970 root_focus.setFocus(self.listScroll(index).getFocus().id); 2971 } 2972 2973 // cross to the header tabs above the stack. 2974 fn focusHeader(self: *This, root_focus: *Focus) void { 2975 root_focus.setFocus(self.box.children.keys()[header_index]); 2976 } 2977 2978 pub fn clearGrid(self: *This) void { 2979 self.box.clearGrid(); 2980 } 2981 2982 pub fn getGrid(self: This) ?Grid { 2983 return self.box.getGrid(); 2984 } 2985 2986 pub fn getFocus(self: *This) *Focus { 2987 return self.box.getFocus(); 2988 } 2989 2990 // for the parent's "scroll up at the top jumps to the header" check: at the 2991 // top only while the header tabs hold focus, so up from the split 2992 // crosses into the tabs first. 2993 pub fn atTop(self: *This) bool { 2994 return self.headerActive(); 2995 } 2996 }; 2997 } 2998