╭ changed ──────────────╮ │src/ui/Repo/Threads.zig│ ╰───────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────╮ │← previous│ ╰──────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1164 // new-thread form shows). │ │1165 fn selectedSplitIndex(self: *This) ?usize { │ │1166 const idx = self.stackSelectedIndex() orelse return null; │ │1202 - return if (idx < status_count or (has_drafts and idx == drafts_view_index) or idx == conflict_view_index) idx else null; │ │1167 + return if (idx < status_count or (supports_drafts and idx == drafts_view_index) or idx == conflict_view_index) idx else null;│ │1168 } │ │1169 │ │1170 fn detailActive(self: *This, index: usize) bool { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1279 │ │1280 // the resolve form's inputs prefill from the picked side, which │ │1281 // is url state and so page-constant like the edit values above │ │1317 - if (has_conflicts and self.data.view == .resolve) { │ │1282 + if (supports_conflicts and self.data.view == .resolve) { │ │1283 for (form.children.values()) |*child| switch (child.widget) { │ │1284 .text_input => |*ti| if (self.resolvePrefill(ti.options.name)) |value| { │ │1285 try self.session.input_values.put(inputs_arena, ti.getFocus().id, value);│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1324 try row.children.put(allocator, spacer.getFocus().id, .{ .widget = .{ .spacer = spacer }, .rect = null, .min_size = null }); │ │1325 } │ │1326 │ │1362 - if (has_drafts and entryDraft(entry)) { │ │1327 + if (supports_drafts and entryDraft(entry)) { │ │1328 if (entry.revision_ready) { │ │1329 const route = listRoute(self.data.identity, @enumFromInt(0), "", entry.id) orelse return error.RouteTooLong; │ │1330 row.getFocus().kind = .{ .custom = try std.fmt.allocPrint(pa, "form:{s}/post", .{try route.toUrl(self.session.page_arena)}) };│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1348 // a conflicted thread's only action is resolving it. the button │ │1349 // stays visible logged out; the resolve page shows the │ │1350 // unauthorized view then. │ │1386 - if (has_conflicts and entryConflicted(entry)) { │ │1351 + if (supports_conflicts and entryConflicted(entry)) { │ │1352 const label = "resolve conflict"; │ │1353 const route = resolveRoute(self.data.identity, entry.id, "") orelse return error.RouteTooLong; │ │1354 try addToolButton(allocator, row, label, try std.fmt.allocPrint(pa, "a:{s}", .{try route.toUrl(self.session.page_arena)}));│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1381 row.getFocus().child_id = row.children.keys()[first_in_row_index]; │ │1382 } │ │1383 } │ │1419 - │ │1420 - if (has_drafts and entryDraft(entry) and !description_page and comment_page == null) { │ │1421 - const aa = self.session.page_arena.allocator(); │ │1422 - var fields: [2]ui.CopyableText.Choice = undefined; │ │1423 - var field_count: usize = 0; │ │1424 - │ │1425 - if (entry.target_branch.len != 0) if (self.session.data.git_ssh_port) |port| { │ │1426 - const url = try std.fmt.allocPrint(aa, "ssh://localhost:{d}/repo/{s}/patch:{s}/branch:{s}", .{ port, self.data.identity, entry.id, entry.target_branch });│ │1427 - const push_command = try std.fmt.allocPrint(aa, "git push {s} HEAD:patch", .{url}); │ │1428 - const clone_name = try Data.cloneDirectoryName(aa, entry.record.event.title); │ │1429 - const clone_command = if (clone_name.len == 0) │ │1430 - try std.fmt.allocPrint(aa, "git clone {s}", .{url}) │ │1431 - else │ │1432 - try std.fmt.allocPrint(aa, "git clone {s} {s}", .{ url, clone_name }); │ │1433 - const choices: [2]ui.CopyableText.Choice = .{ │ │1434 - .{ │ │1435 - .selector = "push", │ │1436 - .text = push_command, │ │1437 - .copyable_text = try std.fmt.allocPrint(aa, "{s}{s}", .{ self.session.data.git_ssh_prefix, push_command }), │ │1438 - .label = " push to this patch from existing repo ", │ │1439 - }, │ │1440 - .{ │ │1441 - .selector = "clone", │ │1442 - .text = clone_command, │ │1443 - .copyable_text = try std.fmt.allocPrint(aa, "{s}{s}", .{ self.session.data.git_ssh_prefix, clone_command }), │ │1444 - .label = " clone this patch ", │ │1445 - }, │ │1446 - }; │ │1447 - var copyable_text = try ui.CopyableText.View.init(allocator, self.session, &choices); │ │1448 - errdefer copyable_text.deinit(allocator); │ │1449 - try inner.children.put(allocator, copyable_text.getFocus().id, .{ .widget = .{ .copyable_text = copyable_text }, .rect = null, .min_size = null }); │ │1450 - try addDetailGap(allocator, inner); │ │1451 - }; │ │1452 - if (entry.fork_oid.len != 0) { │ │1453 - fields[field_count] = .{ │ │1454 - .text = entry.fork_oid, │ │1455 - .label = if (entry.no_changes) " object id of this patch (no changes) " else " object id of this patch ", │ │1456 - }; │ │1457 - field_count += 1; │ │1458 - } │ │1459 - if (entry.target_branch.len != 0) { │ │1460 - fields[field_count] = .{ │ │1461 - .text = entry.target_branch, │ │1462 - .label = " target branch this patch will go to ", │ │1463 - .bottom_label = " (set by the url you push to above) ", │ │1464 - }; │ │1465 - field_count += 1; │ │1466 - } │ │1384 │ │1468 - for (fields[0..field_count], 0..) |field, i| { │ │1469 - var copyable_text = try ui.CopyableText.View.init(allocator, self.session, &.{field}); │ │1470 - errdefer copyable_text.deinit(allocator); │ │1471 - try inner.children.put(allocator, copyable_text.getFocus().id, .{ .widget = .{ .copyable_text = copyable_text }, .rect = null, .min_size = null }); │ │1472 - if (i + 1 < field_count) try addDetailGap(allocator, inner); │ │1473 - } │ │1474 - if (entry.target_branch.len != 0) try addDetailGap(allocator, inner); │ │1385 + if (supports_drafts and entryDraft(entry) and !description_page and comment_page == null) { │ │1386 + try self.data.appendDraftDetails(allocator, inner, self.session, entry); │ │1387 } │ │1388 │ │1389 if (comment_page) |page| { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────╮ │1486 break :blk tb.getFocus().id; │ │1487 }; │ │1488 │ │1577 - if (has_drafts and entryDraft(entry)) { │ │1489 + if (supports_drafts and entryDraft(entry)) { │ │1490 inner.getFocus().child_id = inner.children.keys()[0];│ │1491 const sc = self.detailScroll(index); │ │1492 sc.x = 0; │ ╰───────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1554 if (self.formViewActive()) { │ │1555 if (self.data.view == .remove) { │ │1556 try self.removeFormInput(allocator, key, root_focus); │ │1645 - } else if (has_conflicts and self.data.view == .resolve) { │ │1557 + } else if (supports_conflicts and self.data.view == .resolve) { │ │1558 try self.resolveInput(allocator, key, root_focus); │ │1559 } else if (self.data.view == .new_comment or self.data.view == .edit_comment) {│ │1560 try self.commentFormInput(allocator, key, root_focus); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────╮ │1726 fn primaryAction(self: *This, allocator: std.mem.Allocator, index: usize) !void {│ │1727 const selected = self.detailed_index[index] orelse return; │ │1728 const entry = self.window(index).items[selected]; │ │1817 - if (has_drafts and entryDraft(entry)) │ │1729 + if (supports_drafts and entryDraft(entry)) │ │1730 try self.postDraft(allocator, index) │ │1731 else │ │1732 try self.toggleStatus(allocator, index); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────╮ │1733 } │ │1734 │ │1735 fn postDraft(self: *This, allocator: std.mem.Allocator, index: usize) !void {│ │1824 - if (!has_drafts or comptime wasm) return; │ │1736 + if (!supports_drafts or comptime wasm) return; │ │1737 const selected = self.detailed_index[index] orelse return; │ │1738 const entry = self.window(index).items[selected]; │ │1739 if (!entryDraft(entry) or !entry.revision_ready) return; │ ╰───────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2186 defer any_repo.deinit(io, allocator); │ │2187 switch (any_repo) { │ │2188 inline else => |*repo| { │ │2277 - const change: Event.Update = if (comptime kind == .patch) │ │2278 - .{ .resolve = .{ │ │2279 - .title = title, │ │2280 - .tags = tags, │ │2281 - .hunks = hunks.items, │ │2282 - .theirs = self.data.theirs_picks, │ │2283 - } } │ │2284 - else │ │2285 - .{ .resolve = .{ │ │2286 - .title = title, │ │2287 - .tags = tags, │ │2288 - .hunks = hunks.items, │ │2289 - } }; │ │2189 + var resolution: Event.Resolve = .{ │ │2190 + .title = title, │ │2191 + .tags = tags, │ │2192 + .hunks = hunks.items, │ │2193 + }; │ │2194 + if (comptime @hasField(Event.Resolve, "theirs")) resolution.theirs = self.data.theirs_picks; │ │2195 + const change = Event.Update{ .resolve = resolution }; │ │2196 Event.update(repo_kind, repo.self_repo_opts, io, allocator, repo, &id_bytes, change, author) catch |err| switch (err) {│ │2197 // leave the form up for correction │ │2198 error.InvalidFields => return, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯