╭ changed ──────────╮ │src/ui/UserKeys.zig│ ╰───────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────╮ │← previous│ ╰──────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │187 + if (self.data.confirm) |confirmed| { │ │188 + const button_id = self.contentBox().getFocus().child_id orelse return; │ │189 + if (inp.activated(root_focus, button_id, key)) try self.removeKey(allocator, confirmed);│ │190 + return; │ │191 + } │ │192 // the add row keeps every key but the vertical ones, which move between rows │ │193 if (self.addActive() and inp.vertDirection(key) == .none) { │ │194 if (key == .enter) { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────╮ │195 const text = try self.addInput().text(allocator); │ │196 defer allocator.free(text); │ │163 - try self.act(allocator, .add, text); │ │197 + try self.addKey(allocator, text); │ │198 } else try self.addInput().input(allocator, key, root_focus);│ │199 return; │ │200 } │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │201 │ │202 const rows = self.contentBox(); │ │169 - const current = rows.children.getIndex(rows.getFocus().child_id orelse return) orelse return;│ │203 if (inp.rowDelta(key, @intCast(rows.children.count()))) |delta| { │ │204 ui.widget.moveRowFocus(rows, &self.scroll, root_focus, delta); │ │205 return; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │206 } │ │174 - switch (key) { │ │175 - .arrow_left, .arrow_right => _ = ui.widget.moveInSelectedRow(rows, root_focus, key == .arrow_right), │ │176 - else => { │ │177 - // the add row sits above the key rows │ │178 - if (current == add_index) return; │ │179 - const row = &rows.children.values()[current].widget.box; │ │180 - const remove_id = row.children.keys()[1]; │ │181 - if (row.getFocus().child_id != remove_id or !inp.activated(root_focus, remove_id, key)) return; │ │182 - try self.act(allocator, .remove, self.data.keys[current - 1]); │ │183 - }, │ │184 - } │ │207 + // a row's ✕ is a link the host follows │ │208 + if (key == .arrow_left or key == .arrow_right) _ = ui.widget.moveInSelectedRow(rows, root_focus, key == .arrow_right);│ │209 } │ │210 │ │211 // the terminal changes the keys itself; the web posts the form instead │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │188 - fn act(self: *View, allocator: std.mem.Allocator, action: evt.KeyAction, key: []const u8) !void {│ │212 + fn addKey(self: *View, allocator: std.mem.Allocator, key: []const u8) !void { │ │213 if (comptime wasm) return; │ │214 const io = self.session.io orelse return; │ │215 const users_dir = self.session.users_dir orelse return; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │216 const admin_repo = self.session.admin_repo orelse return; │ │217 const user_id = self.session.userId() orelse return; │ │194 - evt.changeUserKey(io, allocator, users_dir, admin_repo, &user_id, action, key) catch |err| switch (err) {│ │218 + evt.addUserKey(io, allocator, users_dir, admin_repo, &user_id, key) catch |err| switch (err) { │ │219 // the account was removed under them │ │220 error.NotFound => return ui.UserNotifications.logOut(self.session), │ │221 else => { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │229 try self.session.navigate(self.session.data.current_page); │ │230 } │ │231 │ │232 + // the terminal removes the key itself; the web posts the form instead │ │233 + fn removeKey(self: *View, allocator: std.mem.Allocator, key: []const u8) !void { │ │234 + if (comptime wasm) return; │ │235 + const io = self.session.io orelse return; │ │236 + const users_dir = self.session.users_dir orelse return; │ │237 + const admin_repo = self.session.admin_repo orelse return; │ │238 + const user_id = self.session.userId() orelse return; │ │239 + const fingerprint = evt.User.fingerprintOfKey(key) orelse unreachable; │ │240 + evt.removeUserKey(io, allocator, users_dir, admin_repo, &user_id, &fingerprint) catch |err| switch (err) {│ │241 + // the account was removed under them │ │242 + error.NotFound => return ui.UserNotifications.logOut(self.session), │ │243 + else => return err, │ │244 + }; │ │245 + self.session.haxy_moment = try evt.currentMoment(evt.admin_repo_opts, admin_repo); │ │246 + try self.session.navigate(self.session.data.current_page.withUserTab(.{ .view = .keys })); │ │247 + } │ │248 + │ │249 pub fn clearGrid(self: *View) void { │ │250 self.scroll.clearGrid(); │ │251 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────╮ │258 return self.scroll.getFocus(); │ │259 } │ │260 │ │220 - // up leaves the view from the add row │ │261 + // up leaves the view from the add row or the confirmation│ │262 pub fn atTop(self: *View) bool { │ │222 - return self.addActive(); │ │263 + return self.data.confirm != null or self.addActive(); │ │264 } │ │265 }; │ │266 │ ╰───────────────────────────────────────────────────────────────────╯