╭ changed ──────────────╮ │src/ui/Repo/Threads.zig│ ╰───────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────╮ │← previous│ ╰──────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │1522 - // one, else the resolve button on a conflicted issue, the │ │1457 + // one, else the resolve button on a conflicted thread, the │ │1458 // open/close button when present, the edit button otherwise │ │1459 row.getFocus().child_id = row.children.keys()[first_in_row_index];│ │1460 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1463 if (comment_page) |page| { │ │1464 var back_label_buf: ["← back to ".len + thread_name.len]u8 = undefined; │ │1465 const back_label = try std.fmt.bufPrint(&back_label_buf, "← back to {s}", .{thread_name}); │ │1531 - var back = try Comment.linkBox(allocator, self.session, back_label, commentsRoute(self.data.identity, entry.id, 0) orelse return error.RouteTooLong); │ │1466 + var back = try Comment.linkBox(allocator, self.session, back_label, ui.RoutablePage.repoThreadCommentsRoute(kind, self.data.identity, entry.id, 0) orelse return error.RouteTooLong);│ │1467 errdefer back.deinit(allocator); │ │1468 try inner.children.put(allocator, back.getFocus().id, .{ .widget = .{ .text_box = back }, .rect = null, .min_size = null }); │ │1469 │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1495 tb.getFocus().kind = .{ .custom = try listLink(self.session.page_arena, self.data.identity, entryStatus(entry), "", entry.id) }; │ │1496 try inner.children.put(allocator, tb.getFocus().id, .{ .widget = .{ .text_box = tb }, .rect = null, .min_size = null }); │ │1497 } else { │ │1563 - // the issue's title as a focusable word-wrapped text box. │ │1498 + // the thread's title as a focusable word-wrapped text box. │ │1499 { │ │1500 var tb = try wgt.TextBox(ui.Widget).init(allocator, entry.record.event.title, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .word, .label = " title " });│ │1501 errdefer tb.deinit(allocator); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │1510 break :blk tb.getFocus().id; │ │1511 }; │ │1512 │ │1578 - // the issue's tags, each linking to this status's list filtered to │ │1513 + // the thread's tags, each linking to this status's list filtered to│ │1514 // that tag. │ │1515 { │ │1516 var items: std.ArrayList(ui.TagFlow.Item) = .empty; │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1550 }); │ │1551 errdefer tb.deinit(allocator); │ │1552 tb.getFocus().focusable = true; │ │1618 - if (cut_short) tb.getFocus().kind = .{ .custom = try descriptionLink(self.session.page_arena, self.data.identity, entry.id) }; │ │1553 + if (cut_short) { │ │1554 + const route = ui.RoutablePage.repoThreadDescriptionRoute(kind, self.data.identity, entry.id) orelse return error.RouteTooLong; │ │1555 + tb.getFocus().kind = .{ .custom = try std.fmt.allocPrint(self.session.page_arena.allocator(), "a:{s}", .{try route.toUrl(self.session.page_arena)}) };│ │1556 + } │ │1557 try inner.children.put(allocator, tb.getFocus().id, .{ .widget = .{ .text_box = tb }, .rect = null, .min_size = null }); │ │1558 break :blk tb.getFocus().id; │ │1559 }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1572 return; │ │1573 } │ │1574 │ │1637 - const parent_route = commentsRoute(self.data.identity, entry.id, 0) orelse return error.RouteTooLong; │ │1575 + const parent_route = ui.RoutablePage.repoThreadCommentsRoute(kind, self.data.identity, entry.id, 0) orelse return error.RouteTooLong; │ │1576 try Attachment.appendRows(allocator, inner, self.session, self.data.identity, try parent_route.toUrl(self.session.page_arena), entry.attachments);│ │1577 │ │1578 if (!description_page) { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1641 - var reply = try Comment.linkBox(allocator, self.session, "new comment", newCommentRoute(self.data.identity, entry.id, "") orelse return error.RouteTooLong); │ │1579 + var reply = try Comment.linkBox(allocator, self.session, "new comment", ui.RoutablePage.repoThreadCommentNewRoute(kind, self.data.identity, entry.id, "") orelse return error.RouteTooLong);│ │1580 errdefer reply.deinit(allocator); │ │1581 try inner.children.put(allocator, reply.getFocus().id, .{ .widget = .{ .text_box = reply }, .rect = null, .min_size = null }); │ │1582 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │1592 // select the title by default │ │1593 inner.getFocus().child_id = inner.children.keys()[title_child_index]; │ │1594 │ │1657 - // reset the scroll to the top for the newly-shown issue: directly on the │ │1595 + // reset the scroll to the top for the newly-shown thread: directly on the│ │1596 // terminal (the wasm offset), and via a version bump on the web (so the │ │1597 // renderer's scroll id changes and JS drops the preserved position). │ │1598 const sc = self.detailScroll(index); │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────╮ │1644 if (self.detailActive(i)) { │ │1645 try self.detailInput(allocator, i, key, root_focus);│ │1646 } else { │ │1709 - try self.listInput(i, key, root_focus); │ │1647 + self.listInput(i, key, root_focus); │ │1648 } │ │1649 } │ │1650 │ ╰──────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────╮ │1666 } │ │1667 } │ │1668 │ │1731 - fn listInput(self: *This, index: usize, key: Key, root_focus: *Focus) !void {│ │1669 + fn listInput(self: *This, index: usize, key: Key, root_focus: *Focus) void { │ │1670 // up/down (and the scroll wheel) move the selection a row; page up/down │ │1671 // jump a fixed amount. right/Enter cross into the detail pane. up from │ │1672 // the top row crosses into the header tabs. │ ╰───────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯