╭ changed ───────────────╮ │src/ui/widget/thread.zig│ ╰────────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────╮ │467 │ │468 fn draftsRoute(identity: []const u8) ?ui.RoutablePage { │ │469 return if (supports_drafts) Data.draftsRoute(identity) else null; │ │470 + } │ │471 + │ │472 + fn publishRoute(identity: []const u8, selected: []const u8) ?ui.RoutablePage { │ │473 + return if (supports_drafts) Data.publishRoute(identity, selected) else null;│ │474 } │ │475 │ │476 fn forkRoute(identity: []const u8, id: []const u8) ?ui.RoutablePage { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │532 } │ │533 │ │534 if (supports_drafts and entryDraft(entry)) { │ │531 - if (entry.revision_ready) { │ │532 - const route = listRoute(self.data.identity, @enumFromInt(0), "", entry.id) orelse return error.RouteTooLong; │ │533 - row.getFocus().kind = .{ .custom = try std.fmt.allocPrint(pa, "form:{s}/publish", .{try route.toUrl(self.session.page_arena)}) };│ │534 - try addToolButton(allocator, row, "publish", "submit"); │ │535 - } │ │535 + const route = publishRoute(self.data.identity, entry.id) orelse return error.RouteTooLong; │ │536 + try addToolButton(allocator, row, "publish", try std.fmt.allocPrint(pa, "a:{s}", .{try route.toUrl(self.session.page_arena)})); │ │537 if (self.session.data.user_id != null) { │ │538 const edit_route = ui.RoutablePage.repoThreadEditRoute(kind, self.data.identity, entry.id) orelse return error.RouteTooLong; │ │539 try addToolButton(allocator, row, "edit", try std.fmt.allocPrint(pa, "a:{s}", .{try edit_route.toUrl(self.session.page_arena)}));│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │812 } │ │813 │ │814 fn primaryAction(self: *This, allocator: std.mem.Allocator) !void { │ │814 - const entry = self.entry orelse return; │ │815 - if (supports_drafts and entryDraft(entry)) │ │816 - try self.publishDraft(allocator) │ │817 - else │ │818 - try self.toggleStatus(allocator); │ │819 - } │ │820 - │ │821 - fn publishDraft(self: *This, allocator: std.mem.Allocator) !void { │ │822 - if (!supports_drafts or comptime wasm) return; │ │823 - const entry = self.entry orelse return; │ │824 - if (!entryDraft(entry) or !entry.revision_ready) return; │ │825 - try self.data.publishDraft(self.session, allocator, entry.id); │ │826 - const route = listRoute(self.data.identity, @enumFromInt(0), "", entry.id) orelse return;│ │827 - try self.session.navigate(route); │ │815 + try self.toggleStatus(allocator); │ │816 } │ │817 │ │818 fn descriptionInput(self: *This, key: Key, root_focus: *Focus) void { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1240 pub fn viewIndex(view: ViewKind) usize { │ │1241 const name = @tagName(view); │ │1242 if (std.mem.eql(u8, name, "tags")) return tags_view_index; │ │1255 - if (std.mem.eql(u8, name, "new") or std.mem.eql(u8, name, "edit") or std.mem.eql(u8, name, "new_comment") or std.mem.eql(u8, name, "edit_comment") or std.mem.eql(u8, name, "remove") or std.mem.eql(u8, name, "resolve")) return form_view_index; │ │1243 + if (std.mem.eql(u8, name, "new") or std.mem.eql(u8, name, "edit") or std.mem.eql(u8, name, "publish") or std.mem.eql(u8, name, "new_comment") or std.mem.eql(u8, name, "edit_comment") or std.mem.eql(u8, name, "remove") or std.mem.eql(u8, name, "resolve")) return form_view_index;│ │1244 if (std.mem.eql(u8, name, "conflicts")) return conflict_view_index; │ │1245 if (std.mem.eql(u8, name, "drafts")) return drafts_view_index; │ │1246 if (std.mem.eql(u8, name, "description")) unreachable; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1250 unreachable; │ │1251 } │ │1252 │ │1253 + const Confirmation = enum { remove, publish }; │ │1254 + │ │1255 + fn confirmation(view: ViewKind) ?Confirmation { │ │1256 + if (view == .remove) return .remove; │ │1257 + if (supports_drafts and std.mem.eql(u8, @tagName(view), "publish")) return .publish;│ │1258 + return null; │ │1259 + } │ │1260 + │ │1261 // the status a status split lists; the conflicts split has none (its │ │1262 // threads carry their own). │ │1263 fn splitStatus(index: usize) Status { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │1282 │ │1283 fn draftsRoute(identity: []const u8) ?ui.RoutablePage { │ │1284 return if (supports_drafts) Data.draftsRoute(identity) else null; │ │1285 + } │ │1286 + │ │1287 + fn publishRoute(identity: []const u8, selected: []const u8) ?ui.RoutablePage { │ │1288 + return if (supports_drafts) Data.publishRoute(identity, selected) else null;│ │1289 } │ │1290 │ │1291 fn conflictsRoute(identity: []const u8, selected: []const u8) ?ui.RoutablePage {│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1378 // logged-out session can't create events, so the unauthorized view │ │1379 // stands in. │ │1380 if (session.data.is_local or session.data.user_id != null) { │ │1381 - if (data.view == .remove) { │ │1381 + if (confirmation(data.view)) |confirmation_kind| { │ │1382 const aa = session.page_arena.allocator(); │ │1383 - const route = ui.RoutablePage.repoThreadRemoveRoute(kind, data.identity, data.selected_id, data.comment_id) orelse return error.RouteTooLong;│ │1383 + const route = switch (confirmation_kind) { │ │1384 + .remove => ui.RoutablePage.repoThreadRemoveRoute(kind, data.identity, data.selected_id, data.comment_id), │ │1385 + .publish => publishRoute(data.identity, data.selected_id), │ │1386 + } orelse return error.RouteTooLong; │ │1387 const action = try std.fmt.allocPrint(aa, "form:{s}", .{try route.toUrl(session.page_arena)}); │ │1388 const event_name = if (data.comment_id.len == 0) thread_name else "comment"; │ │1389 var label_buf: ["remove ".len + @max(thread_name.len, "comment".len)]u8 = undefined; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1387 - const label = try std.fmt.bufPrint(&label_buf, "remove {s}", .{event_name}); │ │1388 - var center = try initRemoveForm(allocator, action, label); │ │1390 + const label = switch (confirmation_kind) { │ │1391 + .remove => try std.fmt.bufPrint(&label_buf, "remove {s}", .{event_name}), │ │1392 + .publish => "publish patch", │ │1393 + }; │ │1394 + var center = try initConfirmationForm(allocator, action, label); │ │1395 errdefer center.deinit(allocator); │ │1396 try stack.children.put(allocator, center.getFocus().id, .{ .center = center });│ │1397 } else if (data.view == .new_comment or data.view == .edit_comment) { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1622 return box; │ │1623 } │ │1624 │ │1619 - fn initRemoveForm(allocator: std.mem.Allocator, action: []const u8, label: []const u8) !Center { │ │1625 + fn initConfirmationForm(allocator: std.mem.Allocator, action: []const u8, label: []const u8) !Center { │ │1626 var box = try wgt.Box(Widget).init(allocator, .{ .border_style = null, .rounded_corners = true, .direction = .vert });│ │1627 errdefer box.deinit(allocator); │ │1628 box.getFocus().kind = .{ .custom = action }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │1885 }; │ │1886 } │ │1887 │ │1882 - fn removeForm(self: *This) ?*wgt.Box(Widget) { │ │1888 + fn confirmationForm(self: *This) ?*wgt.Box(Widget) { │ │1889 return switch (self.viewStack().children.values()[form_view_index]) {│ │1890 .center => |*center| switch (center.child.*) { │ │1891 .box => |*box| box, │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯