╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Discussions.zig ──────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
237 try discussions.append(aa, .{ 238 .id = try aa.dupe(u8, &id_hex), 239 .record = record, 240 .author = try ui.Author.initFromEmail(admin_moment, arena, record.author_email), 241 .comments = try Comment.loadWindow( 242 hash_kind, 243 arena, 244 admin_moment, 245 haxy_moment, 246 evt.Comment.thread_id_to_comment_id_set_key, 247 &id_hex, 248 if (std.mem.eql(u8, &id_hex, selected_id)) comments_start else 0, 249 ), 250 .attachments = try Attachment.load(hash_kind, arena, haxy_moment, &id_hex), 251 }); 252 } 253 254 return .{ 255 .items = discussions.items, 256 .prev_id = prev_id, 257 .next_id = next_id, 258 .count = @intCast(try set.count()), 259 }; 260 } 261 pub const View = thread.View(.discuss, Self); 262 pub const Detail = thread.Detail(.discuss, Self); 263 pub const detail_widget_name = "repo_discussion_detail"; 264 265 pub const Header = thread.Header; 266 267 // tabs switching between the discussions page's views 268 pub fn initHeader(allocator: std.mem.Allocator, session: *ui.Session, data: *const Self) !Header { 269 var header = try Header.init(allocator); 270 errdefer header.deinit(allocator); 271 const aa = session.page_arena.allocator(); 272 const selected_index = View.viewIndex(data.view); 273 const page_selected = std.meta.activeTag(session.data.current_page) == .repo_discussions; 274 275 // recent discussions 276 { 277 const route = ui.RoutablePage.repoDiscussionsRoute(data.identity, data.tag, "") orelse return error.RouteTooLong; 278 const link = try ui.inPageTabLink(session, route, page_selected and selected_index == 0); 279 var label_buf: [64]u8 = undefined; 280 const label = try std.fmt.bufPrint(&label_buf, "recent ({d})", .{data.recent.count}); 281 try header.addTab(allocator, label, link, 0); 282 } 283 284 // tags tab, labeled with the active tag filter 285 { 286 const tags_route = ui.RoutablePage.repoThreadTagsRoute(.discuss, data.identity, data.tag) orelse return error.RouteTooLong; 287 const tags_link = try ui.inPageTabLink(session, tags_route, page_selected and selected_index == View.viewIndex(.tags)); 288 const label = if (data.tag.len == 0) "tags" else blk: { 289 const decoded = std.Uri.percentDecodeInPlace(try aa.dupe(u8, data.tag)); 290 break :blk try std.fmt.allocPrint(aa, "tags ({s})", .{decoded}); 291 }; 292 try header.addTab(allocator, label, tags_link, View.viewIndex(.tags)); 293 } 294 295 // new-discussion tab; an edit or comment url shows its tab in this place 296 { 297 const route = switch (data.view) { 298 .edit => ui.RoutablePage.repoThreadEditRoute(.discuss, data.identity, data.selected_id) orelse return error.RouteTooLong, 299 .new_comment => ui.RoutablePage.repoThreadCommentNewRoute(.discuss, data.identity, data.selected_id, data.comment_id) orelse return error.RouteTooLong, 300 .edit_comment => ui.RoutablePage.repoThreadCommentEditRoute(.discuss, data.identity, data.selected_id, data.comment_id) orelse return error.RouteTooLong, 301 .remove => ui.RoutablePage.repoThreadRemoveRoute(.discuss, data.identity, data.selected_id, data.comment_id) orelse return error.RouteTooLong, 302 else => ui.RoutablePage.repoThreadNewRoute(.discuss, data.identity) orelse return error.RouteTooLong, 303 }; 304 const link = try ui.inPageTabLink(session, route, page_selected and selected_index == View.viewIndex(.new)); 305 const label: []const u8 = switch (data.view) { 306 .edit => "edit", 307 .new_comment => "reply", 308 .edit_comment => "edit", 309 .remove => "remove", 310 else => "new", 311 }; 312 try header.addTab(allocator, label, link, View.viewIndex(.new)); 313 } 314 315 header.select(View.viewIndex(data.view)); 316 return header; 317 } 318