╭ changed ──────────────╮ │src/ui/Repo/Threads.zig│ ╰───────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭──────────╮ │← previous│ ╰──────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │423 │ │424 fn entryStatus(entry: Entry) Status { │ │425 return if (has_status) entry.record.event.status else @enumFromInt(0); │ │426 + } │ │427 + │ │428 + fn entryDraft(entry: Entry) bool { │ │429 + return if (has_drafts) entry.draft else false; │ │430 + } │ │431 + │ │432 + fn statusAction(status: Status) ?[]const u8 { │ │433 + const name = @tagName(status); │ │434 + if (std.mem.eql(u8, name, "open")) return "close"; │ │435 + if (std.mem.eql(u8, name, "closed")) return "open"; │ │436 + return null; │ │437 } │ │438 │ │439 + fn toggledStatus(status: Status) ?Status { │ │440 + const name = @tagName(status); │ │441 + if (std.mem.eql(u8, name, "open")) return std.meta.stringToEnum(Status, "closed"); │ │442 + if (std.mem.eql(u8, name, "closed")) return std.meta.stringToEnum(Status, "open"); │ │443 + return null; │ │444 + } │ │445 + │ │446 fn listRoute(identity: []const u8, status: Status, tag: []const u8, selected: []const u8) ?ui.RoutablePage {│ │447 return switch (kind) { │ │448 .issue => ui.RoutablePage.repoIssuesRoute(identity, status, tag, selected), │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────╮ │449 + .patch => ui.RoutablePage.repoPatchesRoute(identity, status, tag, selected),│ │450 .discuss => ui.RoutablePage.repoDiscussionsRoute(identity, tag, selected), │ │451 else => @compileError("unsupported thread event kind"), │ │452 }; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────╮ │478 │ │479 fn newRoute(identity: []const u8) ?ui.RoutablePage { │ │480 return ui.RoutablePage.repoThreadNewRoute(kind, identity); │ │481 + } │ │482 + │ │483 + fn draftsRoute(identity: []const u8) ?ui.RoutablePage { │ │484 + return switch (kind) { │ │485 + .patch => ui.RoutablePage.repoPatchesDraftsRoute(identity), │ │486 + else => null, │ │487 + }; │ │488 } │ │489 │ │490 fn descriptionRoute(identity: []const u8, selected: []const u8) ?ui.RoutablePage {│ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────╮ │498 fn conflictsRoute(identity: []const u8, selected: []const u8) ?ui.RoutablePage {│ │499 return switch (kind) { │ │500 .issue => ui.RoutablePage.repoIssuesConflictsRoute(identity, selected), │ │501 + .patch => ui.RoutablePage.repoPatchesConflictsRoute(identity, selected),│ │502 else => @compileError("thread event kind has no conflict route"), │ │503 }; │ │504 } │ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │506 fn resolveRoute(identity: []const u8, selected: []const u8, picks: []const u8) ?ui.RoutablePage {│ │507 return switch (kind) { │ │508 .issue => ui.RoutablePage.repoIssuesResolveRoute(identity, selected, picks), │ │509 + .patch => ui.RoutablePage.repoPatchesResolveRoute(identity, selected, picks), │ │510 else => @compileError("thread event kind has no resolve route"), │ │511 }; │ │512 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │521 return std.fmt.allocPrint(page_arena.allocator(), "ai:{s}", .{try route.toUrl(page_arena)}); │ │522 } │ │523 │ │172 - fn windowLink(page_arena: *std.heap.ArenaAllocator, data: *const Self, status_maybe: ?Status, id: []const u8) ![]const u8 { │ │173 - if (has_conflicts and status_maybe == null) { │ │524 + fn windowLink(page_arena: *std.heap.ArenaAllocator, data: *const Self, status_maybe: ?Status, drafts: bool, id: []const u8) ![]const u8 {│ │525 + if (has_conflicts and status_maybe == null and !drafts) { │ │526 const route = conflictsRoute(data.identity, id) orelse return error.RouteTooLong; │ │527 + return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{try route.toUrl(page_arena)}); │ │528 + } │ │529 + if (drafts and id.len == 0) { │ │530 + const route = draftsRoute(data.identity) orelse return error.RouteTooLong; │ │531 return std.fmt.allocPrint(page_arena.allocator(), "a:{s}", .{try route.toUrl(page_arena)}); │ │532 } │ │533 return listLink(page_arena, data.identity, status_maybe orelse @enumFromInt(0), data.tag, id); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │549 │ │550 // the tabs at the top. │ │551 { │ │196 - var hdr = try Header.init(allocator, session, data); │ │552 + var hdr = try Data.initHeader(allocator, session, data); │ │553 errdefer hdr.deinit(allocator); │ │554 switch (kind) { │ │555 .issue => try outer.children.put(allocator, hdr.getFocus().id, .{ .widget = .{ .repo_issues_header = hdr }, .rect = null, .min_size = null }),│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │556 + .patch => try outer.children.put(allocator, hdr.getFocus().id, .{ .widget = .{ .repo_patches_header = hdr }, .rect = null, .min_size = null }), │ │557 .discuss => try outer.children.put(allocator, hdr.getFocus().id, .{ .widget = .{ .repo_discussions_header = hdr }, .rect = null, .min_size = null }),│ │558 else => @compileError("unsupported thread event kind"), │ │559 } │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │569 const stack = &outer.children.values()[stack_index].widget.stack; │ │570 │ │571 inline for (@typeInfo(Status).@"enum".fields) |field| { │ │215 - var split = try initSplit(allocator, session, data, @enumFromInt(field.value)); │ │572 + var split = try initSplit(allocator, session, data, @enumFromInt(field.value), false);│ │573 errdefer split.deinit(allocator); │ │574 try stack.children.put(allocator, split.getFocus().id, .{ .box = split }); │ │575 } │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │674 var message = try ui.Unauthorized.View.init(allocator); │ │675 errdefer message.deinit(allocator); │ │676 try stack.children.put(allocator, message.getFocus().id, .{ .unauthorized = message });│ │677 + } │ │678 + │ │679 + if (has_drafts) { │ │680 + var split = try initSplit(allocator, session, data, null, true); │ │681 + errdefer split.deinit(allocator); │ │682 + try stack.children.put(allocator, split.getFocus().id, .{ .box = split }); │ │683 } │ │684 │ │685 // the conflicts split; its tab exists only when the repo has │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯