╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │519 return std.fmt.allocPrint(arena.allocator(), repo_segment ++ "{s}", .{identity}); │ │520 } │ │521 │ │522 + // the "owner/name" a repo route carries, null for any other route. the │ │523 + // result borrows the route, so it must outlive the slice. │ │524 + pub fn repoIdentity(self: *const RoutablePage) ?[]const u8 { │ │525 + return switch (self.*) { │ │526 + .repo_files => |*f| f.name.slice(), │ │527 + .repo_commits => |*c| c.name.slice(), │ │528 + .repo_refs => |*r| r.name.slice(), │ │529 + .repo_issues => |*i| i.name.slice(), │ │530 + .repo_settings, .repo_auth => |*name| name.slice(), │ │531 + else => null, │ │532 + }; │ │533 + } │ │534 + │ │535 + // the route this route's page lands on, with no tab or params: the users │ │536 + // list, a user's repos, or a repo's files root. │ │537 + pub fn pageRoot(self: RoutablePage) RoutablePage { │ │538 + return switch (self.parent()) { │ │539 + .home => .default, │ │540 + .user => switch (self) { │ │541 + .user_repos => |u| .{ .user_repos = .{ .name = u.name } }, │ │542 + .user_settings, .user_auth => |name| .{ .user_repos = .{ .name = name } }, │ │543 + else => self, │ │544 + }, │ │545 + // every repo route stores the same identity, so it always fits │ │546 + .repo => repoFilesRoute(self.repoIdentity() orelse return self, null, "", "", 0) orelse self,│ │547 + }; │ │548 + } │ │549 + │ │550 pub fn parent(self: RoutablePage) PageKind { │ │551 return switch (self) { │ │552 .home_users, .home_repos, .home_settings, .home_auth => .home, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │846 // serializable data sent down to web client │ │847 pub const Data = struct { │ │848 user_id: ?[]const u8 = null, │ │849 + // the logged-in user's name, for the views that show it │ │850 + user_name: ?[]const u8 = null, │ │851 // a transient outcome to surface from the last /login POST attempt│ │852 login_failure: ?Home.Auth.Login.Failure = null, │ │853 current_page: RoutablePage = .default, │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │883 .page_arena = arena, │ │884 .haxy_moment = try evt.currentMoment(evt.admin_repo_opts, repo),│ │885 }; │ │856 - try session.loadUserPrefs(); │ │886 + try session.loadUser(); │ │887 return session; │ │888 } │ │889 │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │860 - // load the logged-in user's persisted preferences from the db │ │861 - pub fn loadUserPrefs(self: *Self) !void { │ │890 + // load the logged-in user's name and persisted preferences from the db │ │891 + pub fn loadUser(self: *Self) !void { │ │892 const user_id = self.data.user_id orelse return; │ │893 const moment = self.haxy_moment orelse return; │ │894 if (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, self.arena, user_id)) |user| {│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────╮ │895 + self.data.user_name = user.event.name; │ │896 self.data.enable_ansi = user.event.enable_ansi;│ │897 } │ │898 } │ ╰────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │899 │ │869 - // the user's email, for authoring event commits │ │870 - pub fn userEmail(self: *Self) ![]const u8 { │ │871 - const user_id = self.data.user_id orelse return "user@haxy"; │ │872 - const moment = self.haxy_moment orelse return "user@haxy"; │ │873 - const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, self.page_arena, user_id)) orelse unreachable;│ │900 + // the author for an event this session creates, or null when it may not │ │901 + // create one. local mode has no accounts, so it authors anonymously. │ │902 + pub fn eventAuthorEmail(self: *Self) !?[]const u8 { │ │903 + if (self.data.is_local) return "user@haxy"; // TODO: try the repo's git config user.email first │ │904 + const user_id = self.data.user_id orelse return null; │ │905 + const moment = self.haxy_moment orelse return null; │ │906 + const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, moment, self.page_arena, user_id)) orelse return null;│ │907 return user.event.email; │ │908 } │ │909 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯