╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ───────────────╮ │src/ui/widget/thread.zig│ ╰────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2245 - .arrow_down, .tab => if (cur < submit_field_index) { │ │2246 - root_focus.setFocus(form.children.keys()[cur + 1]); │ │2247 - }, │ │2248 - .enter => if (cur == submit_field_index) try self.submitForm(allocator), │ │2258 + .arrow_down, .tab => return if (cur < submit_field_index) root_focus.setFocus(form.children.keys()[cur + 1]), │ │2259 + .enter => if (cur == submit_field_index) return self.submitForm(allocator), │ │2260 .mouse => |mouse| if (cur == submit_field_index) { │ │2250 - const submit = &form.children.values()[cur].widget.submit_button; │ │2251 - if (inp.leftClickOn(root_focus, submit.buttonId(), mouse)) try self.submitForm(allocator); │ │2261 + if (inp.leftClickOn(root_focus, child.widget.submit_button.buttonId(), mouse)) return self.submitForm(allocator);│ │2262 }, │ │2253 - else => try form.children.values()[cur].widget.input(allocator, key, root_focus), │ │2263 + else => {}, │ │2264 } │ │2265 + try child.widget.input(allocator, key, root_focus); │ │2266 } │ │2267 │ │2268 fn commentFormInput(self: *This, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2524 const author = (try self.session.eventAuthor()) orelse return; │ │2525 │ │2526 const form = self.threadForm() orelse return; │ │2527 + const target_branch_field_index = form.children.count() - 2; │ │2528 const title_input = &form.children.values()[title_field_index].widget.text_input; │ │2529 const tags_input = &form.children.values()[tags_field_index].widget.text_input; │ │2530 const description_input = &form.children.values()[description_field_index].widget.text_input;│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2544 } │ │2545 │ │2546 if (comptime supports_drafts) { │ │2535 - const event_id_hex = Data.createDraft(self.data, self.session, allocator, title, tags, description, target_branch) catch |err| switch (err) {│ │2536 - error.InvalidFields => { │ │2537 - try self.rememberThreadFeedback(.invalid_target_branch, title, tags, description, target_branch); │ │2538 - return; │ │2539 - }, │ │2540 - else => |other| return other, │ │2547 + const source = &form.children.values()[source_field_index].widget.patch_source; │ │2548 + const source_branch = if (source.existing) try source.field().text(allocator) else null; │ │2549 + defer if (source_branch) |branch| allocator.free(branch); │ │2550 + const event_id_hex = Data.create(self.data, self.session, allocator, title, tags, description, target_branch, source_branch) catch |err| { │ │2551 + const failure = FeedbackFailure.fromError(err) orelse return err; │ │2552 + try self.rememberThreadFeedback(failure, title, tags, description, target_branch); │ │2553 + return; │ │2554 }; │ │2555 title_input.clear(allocator); │ │2556 tags_input.clear(allocator); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2604 const entry = self.data.selectedThread() orelse return; │ │2605 │ │2606 const form = self.threadForm() orelse return; │ │2607 + const target_branch_field_index = form.children.count() - 2; │ │2608 const title_input = &form.children.values()[title_field_index].widget.text_input; │ │2609 const tags_input = &form.children.values()[tags_field_index].widget.text_input; │ │2610 const description_input = &form.children.values()[description_field_index].widget.text_input;│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2626 │ │2627 if (comptime supports_drafts) { │ │2628 if (entryDraft(entry.*)) { │ │2615 - self.data.editDraft(self.session, allocator, entry.id, title, tags, description, target_branch) catch |err| switch (err) {│ │2616 - error.InvalidFields => { │ │2617 - try self.rememberThreadFeedback(.invalid_target_branch, title, tags, description, target_branch); │ │2618 - return; │ │2619 - }, │ │2620 - else => |other| return other, │ │2629 + self.data.editDraft(self.session, allocator, entry.id, title, tags, description, target_branch) catch |err| { │ │2630 + const failure = FeedbackFailure.fromError(err) orelse return err; │ │2631 + try self.rememberThreadFeedback(failure, title, tags, description, target_branch); │ │2632 + return; │ │2633 }; │ │2634 const route = listRoute(self.data.identity, entryStatus(entry.*), "", entry.id) orelse return; │ │2635 try self.session.navigate(route); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2651 .tags = tags, │ │2652 .description = description, │ │2653 .target_branch = target_branch, │ │2642 - } }, author) catch |err| switch (err) { │ │2643 - error.InvalidFields => { │ │2644 - try self.rememberThreadFeedback(.invalid_target_branch, title, tags, description, target_branch); │ │2645 - return; │ │2646 - }, │ │2647 - else => |other| return other, │ │2654 + } }, author) catch |err| { │ │2655 + const failure = FeedbackFailure.fromError(err) orelse return err; │ │2656 + try self.rememberThreadFeedback(failure, title, tags, description, target_branch); │ │2657 + return; │ │2658 }; │ │2659 } else if (has_status) │ │2660 try Event.update(self.session.data.host_kind, repo_kind, repo.self_repo_opts, io, allocator, repo, &id_bytes, .{ .fields = .{│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2674 │ │2675 fn rememberThreadFeedback(self: *This, failure: FeedbackFailure, title: []const u8, tags: []const u8, description: []const u8, target_branch: []const u8) !void {│ │2676 const aa = self.session.arena.allocator(); │ │2677 + const source = if (supports_drafts) blk: { │ │2678 + const form = self.threadForm() orelse break :blk null; │ │2679 + break :blk switch (form.children.values()[source_field_index].widget) { │ │2680 + .patch_source => |*value| value, │ │2681 + else => null, │ │2682 + }; │ │2683 + } else null; │ │2684 self.session.data.form_feedback = @unionInit(ui.Session.FormFeedback, @tagName(feedback_tag), .{ │ │2685 .failure = failure, │ │2686 .fields = if (comptime supports_drafts) .{ │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────╮ │2688 .tags = try aa.dupe(u8, tags), │ │2689 .description = try aa.dupe(u8, description), │ │2690 .target_branch = try aa.dupe(u8, target_branch), │ │2691 + .source_branch = if (source) |value| try value.field().text(aa) else "",│ │2692 + .branch_source = if (source) |value| value.existing else false, │ │2693 } else .{ │ │2694 .title = try aa.dupe(u8, title), │ │2695 .tags = try aa.dupe(u8, tags), │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │406 }; │ │407 } │ │408 │ │409 -fn requiredTitleFeedback(kind: evt.EventKind, title: []const u8, tags: []const u8, description: []const u8, target_branch: []const u8) ui.Session.FormFeedback { │ │409 +fn requiredTitleFeedback(kind: evt.EventKind, title: []const u8, tags: []const u8, description: []const u8, target_branch: []const u8, source_branch: ?[]const u8) ui.Session.FormFeedback {│ │410 return switch (kind) { │ │411 .issue => .{ .issue = .{ .failure = .required_title, .fields = .{ │ │412 .title = title, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │413 .tags = tags, │ │414 .description = description, │ │415 } } }, │ │416 - .patch => .{ .patch = .{ .failure = .required_title, .fields = .{ │ │417 - .title = title, │ │418 - .tags = tags, │ │419 - .description = description, │ │420 - .target_branch = target_branch, │ │421 - } } }, │ │416 + .patch => patchFeedback(.required_title, title, tags, description, target_branch, source_branch),│ │417 .discuss => .{ .discussion = .{ .failure = .required_title, .fields = .{ │ │418 .title = title, │ │419 .tags = tags, │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯