╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │133 if (method == .POST) { │ │134 switch (host) { │ │135 .server => |server| { │ │136 - const PostRoute = enum { login, logout, ansi, new, edit, remove, open, close, resolve, publish, merge, squash, attach, undo }; │ │136 + const PostRoute = enum { login, logout, ansi, new, edit, remove, open, close, resolve, publish, merge, squash, attach, undo, clear };│ │137 inline for (@typeInfo(PostRoute).@"enum".fields) |field| { │ │138 const suffix = "/" ++ field.name; │ │139 if (std.mem.endsWith(u8, path, suffix)) { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │151 .publish => handlePatchPublish(io, request, allocator, base, host), │ │152 .merge => handlePatchMerge(io, request, allocator, base, host, .source), │ │153 .squash => handlePatchMerge(io, request, allocator, base, host, .squash),│ │154 - .undo => handleUndo(io, request, allocator, base, host), │ │154 + .undo => handleUndo(io, request, allocator, base, host, .undo), │ │155 + .clear => handleUndo(io, request, allocator, base, host, .clear), │ │156 .attach => handleAttach(io, request, allocator, base, host), │ │157 }; │ │158 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │159 } │ │160 }, │ │161 .local => |local| { │ │161 - const PostRoute = enum { new, edit, remove, open, close, resolve, sync, attach, undo }; │ │162 + const PostRoute = enum { new, edit, remove, open, close, resolve, sync, attach, undo, clear };│ │163 inline for (@typeInfo(PostRoute).@"enum".fields) |field| { │ │164 const suffix = "/" ++ field.name; │ │165 if (std.mem.endsWith(u8, path, suffix)) { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │172 .close => handleThreadStatus(io, request, allocator, base, host, false),│ │173 .resolve => handleThreadResolve(io, request, allocator, base, host), │ │174 .sync => handleSync(io, request, allocator, base, local), │ │174 - .undo => handleUndo(io, request, allocator, base, host), │ │175 + .undo => handleUndo(io, request, allocator, base, host, .undo), │ │176 + .clear => handleUndo(io, request, allocator, base, host, .clear), │ │177 .attach => handleAttach(io, request, allocator, base, host), │ │178 }; │ │179 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1712 }); │ │1713 } │ │1714 │ │1713 -fn handleUndo(io: std.Io, request: *std.http.Server.Request, allocator: std.mem.Allocator, base: []const u8, host: Host) !void { │ │1715 +// the posted path drops the action's own segment, so the route it parses is │ │1716 +// the undo page the action applies to, never the confirmation page itself │ │1717 +fn handleUndo(io: std.Io, request: *std.http.Server.Request, allocator: std.mem.Allocator, base: []const u8, host: Host, action: enum { undo, clear }) !void {│ │1718 const route = (switch (host) { │ │1719 .local => ui.RoutablePage.fromUrlLocal(base), │ │1720 .server => ui.RoutablePage.fromUrl(base), │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1721 }) orelse return respondRepoNotFound(request); │ │1722 if (route != .repo_undo) return respondRepoNotFound(request); │ │1723 const target = route.repo_undo; │ │1720 - const index = target.index orelse return respondRepoNotFound(request); │ │1724 var arena = std.heap.ArenaAllocator.init(allocator); │ │1725 defer arena.deinit(); │ │1726 const repo_base = if (target.name.len == 0) "" else try std.fmt.allocPrint(arena.allocator(), "/repo/{s}", .{target.name.slice()});│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1727 _ = (try authorizeWrite(io, allocator, &arena, request, host, repo_base, .owner)) orelse return; │ │1728 const resolved = (try requestRepoSource(io, allocator, host, repo_base)) orelse return respondRepoNotFound(request); │ │1729 defer resolved.deinit(allocator); │ │1727 - ui.Repo.Undo.execute(io, allocator, resolved.source, index) catch |err| switch (err) { │ │1730 + (switch (action) { │ │1731 + .undo => ui.Repo.Undo.execute(io, allocator, resolved.source, target.index orelse return respondRepoNotFound(request)),│ │1732 + .clear => ui.Repo.Undo.clearHistory(io, allocator, resolved.source), │ │1733 + }) catch |err| switch (err) { │ │1734 error.NotFound, error.InvalidHistoryIndex, error.TransactionNotFound => return respondRepoNotFound(request), │ │1735 else => return err, │ │1736 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯