╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │2302 io: ?std.Io = null, │ │2303 admin_repo: ?*rp.Repo(.xit, evt.admin_repo_opts) = null, │ │2304 users_dir: ?[]const u8 = null, │ │2305 + // the notify worker's queue, null where no worker runs │ │2306 + dirty_repos: ?*notify.DirtyRepos = null, │ │2307 // the single on-disk repo this session views, when running in local mode │ │2308 // (haxy invoked with no arguments inside a repo). null on the server paths,│ │2309 // which resolve repos from the admin db instead. │ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────╮ │2484 // the logged-in user's name and email, for the views that show them │ │2485 user_name: ?[]const u8 = null, │ │2486 user_email: ?[]const u8 = null, │ │2487 + // the logged-in user's unread notifications, refreshed on each page build│ │2488 + unread_notifs: u64 = 0, │ │2489 // a failed form retained long enough to render it for correction │ │2490 form_feedback: ?FormFeedback = null, │ │2491 // a transient local event-sync error │ ╰────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2592 }; │ │2593 } │ │2594 │ │2510 - // where this session's event writes go. a server session always has a users dir │ │2595 + // where this session's event writes go. a server session always has a users dir and an admin repo│ │2596 pub fn eventHost(self: *const Self) evt.Host { │ │2597 return switch (self.data.host_kind) { │ │2598 .local => .local, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │2514 - .server => .{ .server = .{ .users_dir = self.users_dir orelse unreachable } },│ │2599 + .server => .{ .server = .{ │ │2600 + .users_dir = self.users_dir orelse unreachable, │ │2601 + .dirty_repos = self.dirty_repos, │ │2602 + .admin_repo_path = (self.admin_repo orelse unreachable).core.work_path, │ │2603 + } }, │ │2604 }; │ │2605 } │ │2606 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/Fork.zig│ ╰───────────────╯ ╭─────────────────────────────────────────────╮ │24 commits: Commits, │ │25 patch: Patches, │ │26 diff: Diff, │ │27 +user_notifications: ui.UserNotifications,│ │28 quit: Quit, │ │29 │ │30 const Self = @This(); │ ╰─────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │172 .path = diff_path, │ │173 .window = try Diff.render(.xit, repo_opts, io, arena.child_allocator, aa, fork_repo, if (diff_base) |*base| base else null, diff_head, diff_start, diff_path),│ │174 }, │ │175 + .user_notifications = try ui.UserNotifications.init(arena, session, route.userTab()), │ │176 .quit = Quit.init(), │ │177 }; │ │178 }, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │228 try stack.children.put(allocator, new_user.getFocus().id, .{ .new_user = new_user }); │ │229 } │ │230 if (session.data.host_kind == .server) { │ │229 - var user_view = try ui.UserSettings.initView(allocator, session); │ │231 + const route = ui.RoutablePage.forkUserRoute(identity, data.header.id) orelse return error.RouteTooLong;│ │232 + var user_view = try ui.UserSettings.initView(allocator, session, &data.user_notifications, route); │ │233 errdefer user_view.deinit(allocator); │ │234 try stack.children.put(allocator, user_view.getFocus().id, user_view); │ │235 } │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │278 .repo_patch_detail => |*view| if (view.focusFirst(root_focus)) return, │ │279 .repo_files => |*view| if (view.focusHeader(root_focus)) return, │ │280 .repo_commits => |*view| if (view.focusHeader(root_focus)) return, │ │281 + .user_notifications => |*view| if (view.focusHeader(root_focus)) return,│ │282 else => {}, │ │283 }; │ │284 next_index = stack_index; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Fork/Header.zig│ ╰──────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │162 │ │163 if (session.data.host_kind == .server) { │ │164 const label = ui.UserSettings.tabLabel(session); │ │165 - var user_tab = try wgt.TextBox.init(allocator, label, .{ .border = .single, .round_corners = true, .wrap_kind = .none }); │ │165 + const count_label = try ui.UserSettings.tabBottomLabel(session); │ │166 + var user_tab = try wgt.TextBox.init(allocator, label, .{ .border = .single, .round_corners = true, .wrap_kind = .none, .bottom_label = .{ .text = count_label } });│ │167 errdefer user_tab.deinit(allocator); │ │168 user_tab.getFocus().mode = .all; │ │169 user_tab.getFocus().kind = .{ .custom = user_link }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │170 try tab_ids.put(allocator, user_tab.getFocus().id, {}); │ │171 if (current_tag == .fork_user) selected_tab = user_tab.getFocus().id; │ │171 - try tabs_box.children.put(allocator, user_tab.getFocus().id, .{ .widget = .{ .text_box = user_tab }, .rect = null, .min_size = .{ .width = label.len + 2, .height = null } }); │ │172 + try tabs_box.children.put(allocator, user_tab.getFocus().id, .{ .widget = .{ .text_box = user_tab }, .rect = null, .min_size = .{ .width = @max(label.len, count_label.len) + 2, .height = null } });│ │173 } │ │174 │ │175 if (session.is_terminal) { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯