╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────────────╮ │src/ui/Repo/Threads.zig│ ╰───────────────────────╯ ╭───────────────────────────────────────────────────╮ │ 50 - status_button_id: [view_count]?usize, │ │372 + primary_button_id: [view_count]?usize,│ │373 │ │374 const header_index: usize = 0; │ │375 const stack_index: usize = 1; │ ╰───────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │376 // indices within the stack, 1:1 with the header tabs. │ │377 const status_count = @typeInfo(Status).@"enum".fields.len; │ │378 const tags_view_index: usize = status_count; │ │ 57 - // the new-issue form, or the edit, comment, or resolve form when the page was │ │379 + // the new-thread form, or the edit, comment, or resolve form when the page was│ │380 // loaded at one of their urls. │ │381 const form_view_index: usize = tags_view_index + 1; │ │382 // the conflicts split; the tab and stack child exist only when the repo │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────╮ │ 61 - // has conflicted issues. │ │ 62 - const conflict_view_index: usize = form_view_index + 1; │ │383 + // has conflicted threads. │ │384 + const drafts_view_index: usize = form_view_index + 1; │ │385 + const conflict_view_index: usize = drafts_view_index + @intFromBool(has_drafts);│ │386 const view_count: usize = conflict_view_index + @intFromBool(has_conflicts); │ │387 // indices within a split (the horizontal box inside the stack). │ │388 const list_index: usize = 0; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │403 if (std.mem.eql(u8, name, "tags")) return tags_view_index; │ │404 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;│ │405 if (std.mem.eql(u8, name, "conflicts")) return conflict_view_index; │ │406 + if (std.mem.eql(u8, name, "drafts")) return drafts_view_index; │ │407 if (std.mem.eql(u8, name, "description")) unreachable; │ │408 inline for (@typeInfo(Status).@"enum".fields, 0..) |field, index| { │ │409 if (std.mem.eql(u8, name, field.name)) return index; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │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); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯