╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────────╮ │src/ui/Repo/Attachment.zig│ ╰──────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────╮ │11 name: []const u8, │ │12 }; │ │13 │ │14 -// every attachment on a parent event, oldest first. removed ones are│ │14 +// every attachment on a target event, oldest first. removed ones are│ │15 // left out. │ │16 pub fn load( │ │17 comptime hash_kind: hash.HashKind, │ ╰─────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │18 arena: *std.heap.ArenaAllocator, │ │19 haxy_moment: evt.EventDB(hash_kind).HashMap(.read_only), │ │20 - parent_id: []const u8, │ │20 + target_id: *const [evt.event_id_size]u8, │ │21 ) ![]const WithId { │ │22 const DB = evt.EventDB(hash_kind); │ │23 - const index_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, evt.Attachment.parent_id_to_attachment_id_set_key)) orelse return &.{};│ │23 + const index_cursor = try haxy_moment.getCursor(hash.hashInt(hash_kind, evt.Attachment.target_id_to_attachment_id_set_key)) orelse return &.{};│ │24 const index = try DB.HashMap(.read_only).init(index_cursor); │ │25 - const set_cursor = try index.getCursor(hash.hashInt(hash_kind, parent_id)) orelse return &.{}; │ │25 + const set_cursor = try index.getCursor(hash.hashInt(hash_kind, target_id)) orelse return &.{}; │ │26 const set = try DB.SortedSet(.read_only).init(set_cursor); │ │27 │ │28 var attachments: std.ArrayList(WithId) = .empty; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────╮ │46 box: *wgt.Box(ui.Widget), │ │47 session: *ui.Session, │ │48 identity: []const u8, │ │49 - parent_url: []const u8, │ │49 + target_url: []const u8, │ │50 attachments: []const WithId, │ │51 ) !void { │ │52 const pa = session.page_arena.allocator();│ ╰──────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │65 tb.getFocus().kind = .{ .custom = try pa.print("{s}{s}", .{ ui.raw_link_prefix, try url(session.page_arena, identity, &entry.id) }) };│ │66 try row.children.put(allocator, tb.getFocus().id, .{ .widget = .{ .text_box = tb }, .rect = null, .min_size = null }); │ │67 │ │68 - row.getFocus().kind = .{ .custom = try pa.print("form:{s}/attachment:{s}/remove", .{ parent_url, &entry.id }) }; │ │68 + row.getFocus().kind = .{ .custom = try pa.print("form:{s}/attachment:{s}/remove", .{ target_url, &entry.id }) }; │ │69 var remove = try wgt.TextBox.init(allocator, "✕", .{ .border = .single, .round_corners = true, .wrap_kind = .none }); │ │70 errdefer remove.deinit(allocator); │ │71 remove.getFocus().mode = .all; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Comment.zig│ ╰───────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │51 │ │52 return .{ │ │53 .selected = selected, │ │54 - .replies = try loadWindow(hash_kind, arena, admin_moment, haxy_moment, evt.Comment.parent_id_to_comment_id_set_key, selected_id, start, viewer), │ │54 + .replies = try loadWindow(hash_kind, arena, admin_moment, haxy_moment, evt.Comment.parent_id_to_comment_id_set_key, &try evt.parseEventId(selected_id), start, viewer),│ │55 }; │ │56 } │ │57 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────╮ │62 admin_moment: ?evt.AdminDB.HashMap(.read_only), │ │63 haxy_moment: evt.EventDB(hash_kind).HashMap(.read_only),│ │64 index_key: []const u8, │ │65 - owner_id: []const u8, │ │65 + owner_id: *const [evt.event_id_size]u8, │ │66 start: usize, │ │67 viewer: ?ui.Viewer, │ │68 ) !Window { │ ╰────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Repo/Events.zig│ ╰──────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │342 item.view_url = try route.toUrl(arena); │ │343 }, │ │344 .attach => { │ │345 - const record = (try evt.readRecordSubset(evt.Attachment, struct { author_email: ?[]const u8, event: struct { parent_id: [evt.event_id_size * 2]u8 } }, DB, hash_kind, haxy_moment, arena, id)) orelse return null;│ │345 + const record = (try evt.readRecordSubset(evt.Attachment, struct { author_email: ?[]const u8, event: struct { target_id: [evt.event_id_size * 2]u8 } }, DB, hash_kind, haxy_moment, arena, id)) orelse return null;│ │346 item.author = try ui.Author.initFromEmail(admin_moment, arena, record.author_email); │ │347 if (!include_view_url) return item; │ │348 - var parent_id: [evt.event_id_size]u8 = undefined; │ │349 - _ = std.fmt.hexToBytes(&parent_id, &record.event.parent_id) catch return error.InvalidEventId; │ │350 - const parent_kind = (try evt.readEventKind(hash_kind, kind_map, &parent_id)) orelse return item; │ │351 - if (repo_event.threadRole(parent_kind) == null) return item; │ │352 - const route = ui.RoutablePage.repoThreadCommentsRoute(parent_kind, identity, &record.event.parent_id, 0) orelse return item; │ │348 + const target_id = try evt.parseEventId(&record.event.target_id); │ │349 + const target_kind = (try evt.readEventKind(hash_kind, kind_map, &target_id)) orelse return item; │ │350 + if (repo_event.threadRole(target_kind) == null) return item; │ │351 + const route = ui.RoutablePage.repoThreadCommentsRoute(target_kind, identity, &record.event.target_id, 0) orelse return item; │ │352 item.view_url = try route.toUrl(arena); │ │353 }, │ │354 .assign => { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────────╮ │src/ui/widget/thread.zig│ ╰────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │430 ) !?Data.Entry { │ │431 const DB = evt.EventDB(hash_kind); │ │432 const aa = arena.allocator(); │ │433 + const id = order_key[@sizeOf(u64)..]; │ │434 const id_hex = keyIdHex(order_key); │ │434 - const record_cursor = try records.getCursor(hash.hashInt(hash_kind, order_key[@sizeOf(u64)..])) orelse return null; │ │435 + const record_cursor = try records.getCursor(hash.hashInt(hash_kind, id)) orelse return null; │ │436 const record = try evt.read(Data.Event.Record, DB, hash_kind, arena, try DB.HashMap(.read_only).init(record_cursor));│ │437 var entry: Data.Entry = .{ │ │438 .id = try aa.dupe(u8, &id_hex), │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │444 admin_moment, │ │445 haxy_moment, │ │446 evt.Comment.thread_id_to_comment_id_set_key, │ │446 - &id_hex, │ │447 + id, │ │448 if (std.mem.eql(u8, &id_hex, selected_id)) comments_start else 0,│ │449 viewer, │ │450 ), │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │450 - .attachments = try Attachment.load(hash_kind, arena, haxy_moment, &id_hex), │ │451 - .assignees = try loadAssignees(hash_kind, arena, admin_moment, haxy_moment, &id_hex), │ │451 + .attachments = try Attachment.load(hash_kind, arena, haxy_moment, id), │ │452 + .assignees = try loadAssignees(hash_kind, arena, admin_moment, haxy_moment, id), │ │453 .can_modify = if (viewer) |v| v.role.canModify(v.email, record.author_email) else false,│ │454 }; │ │455 if (comptime @hasField(Data.Entry, "conflicted")) { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯