Show approval controls for blocked file edits
This commit is contained in:
@@ -395,6 +395,20 @@ impl CodeDiffState {
|
|||||||
fn is_waiting_for_user(&self) -> bool {
|
fn is_waiting_for_user(&self) -> bool {
|
||||||
matches!(self, CodeDiffState::WaitingForUser)
|
matches!(self, CodeDiffState::WaitingForUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sync_with_action_status(&mut self, status: Option<&AIActionStatus>) {
|
||||||
|
match status {
|
||||||
|
Some(AIActionStatus::Blocked) => *self = CodeDiffState::WaitingForUser,
|
||||||
|
Some(status) if status.is_cancelled() => *self = CodeDiffState::Rejected,
|
||||||
|
Some(
|
||||||
|
AIActionStatus::Preprocessing
|
||||||
|
| AIActionStatus::Queued
|
||||||
|
| AIActionStatus::RunningAsync
|
||||||
|
| AIActionStatus::Finished(_),
|
||||||
|
)
|
||||||
|
| None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@@ -676,13 +690,21 @@ impl CodeDiffView {
|
|||||||
ctx: &mut ViewContext<Self>,
|
ctx: &mut ViewContext<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let is_passive = model.request_type(ctx).is_passive_code_diff();
|
let is_passive = model.request_type(ctx).is_passive_code_diff();
|
||||||
let initial_state = if action_model.as_ref(ctx).is_view_only() {
|
let mut initial_state = if action_model.as_ref(ctx).is_view_only() {
|
||||||
CodeDiffState::ViewOnly { is_complete: false }
|
CodeDiffState::ViewOnly { is_complete: false }
|
||||||
} else if model.is_first_action_in_output(action_id, ctx) {
|
} else if model.is_first_action_in_output(action_id, ctx) {
|
||||||
CodeDiffState::WaitingForUser
|
CodeDiffState::WaitingForUser
|
||||||
} else {
|
} else {
|
||||||
CodeDiffState::Queued
|
CodeDiffState::Queued
|
||||||
};
|
};
|
||||||
|
if !action_model.as_ref(ctx).is_view_only() {
|
||||||
|
if let Some(conversation_id) = identifiers.client_conversation_id {
|
||||||
|
let status = action_model
|
||||||
|
.as_ref(ctx)
|
||||||
|
.get_action_status(conversation_id, action_id);
|
||||||
|
initial_state.sync_with_action_status(status.as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let view = Self::build(
|
let view = Self::build(
|
||||||
action_id,
|
action_id,
|
||||||
@@ -700,6 +722,18 @@ impl CodeDiffView {
|
|||||||
ctx.subscribe_to_model(
|
ctx.subscribe_to_model(
|
||||||
&action_model,
|
&action_model,
|
||||||
move |me, action_model, event, ctx| match event {
|
move |me, action_model, event, ctx| match event {
|
||||||
|
BlocklistAIActionEvent::ActionBlockedOnUserConfirmation {
|
||||||
|
action_id: event_action_id,
|
||||||
|
conversation_id: event_conversation_id,
|
||||||
|
..
|
||||||
|
} if !me.is_complete()
|
||||||
|
&& !matches!(me.state, CodeDiffState::ViewOnly { .. })
|
||||||
|
&& *event_action_id == me.action_id
|
||||||
|
&& me.identifiers.client_conversation_id == Some(*event_conversation_id) =>
|
||||||
|
{
|
||||||
|
me.state = CodeDiffState::WaitingForUser;
|
||||||
|
ctx.notify();
|
||||||
|
}
|
||||||
BlocklistAIActionEvent::FinishedAction {
|
BlocklistAIActionEvent::FinishedAction {
|
||||||
action_id: event_action_id,
|
action_id: event_action_id,
|
||||||
conversation_id: event_conversation_id,
|
conversation_id: event_conversation_id,
|
||||||
@@ -715,18 +749,16 @@ impl CodeDiffView {
|
|||||||
.as_ref(ctx)
|
.as_ref(ctx)
|
||||||
.get_action_status(conversation_id, &me.action_id)
|
.get_action_status(conversation_id, &me.action_id)
|
||||||
{
|
{
|
||||||
Some(AIActionStatus::Blocked) => {
|
|
||||||
me.state = CodeDiffState::WaitingForUser;
|
|
||||||
ctx.notify();
|
|
||||||
}
|
|
||||||
Some(status) => {
|
Some(status) => {
|
||||||
if matches!(me.state, CodeDiffState::ViewOnly { .. })
|
if matches!(me.state, CodeDiffState::ViewOnly { .. })
|
||||||
&& status.is_success()
|
&& status.is_success()
|
||||||
{
|
{
|
||||||
me.state = CodeDiffState::ViewOnly { is_complete: true };
|
me.state = CodeDiffState::ViewOnly { is_complete: true };
|
||||||
me.should_expand_when_complete = false;
|
me.should_expand_when_complete = false;
|
||||||
} else if status.is_cancelled() {
|
} else {
|
||||||
me.state = CodeDiffState::Rejected;
|
me.state.sync_with_action_status(Some(&status));
|
||||||
|
}
|
||||||
|
if status.is_cancelled() {
|
||||||
me.should_expand_when_complete = false;
|
me.should_expand_when_complete = false;
|
||||||
}
|
}
|
||||||
ctx.notify();
|
ctx.notify();
|
||||||
@@ -3268,3 +3300,7 @@ fn editor_range_to_file_context_range(range: Range<usize>) -> Range<usize> {
|
|||||||
fn file_context_range_to_editor_range(range: Range<usize>) -> Range<usize> {
|
fn file_context_range_to_editor_range(range: Range<usize>) -> Range<usize> {
|
||||||
range.start.saturating_sub(1)..range.end.saturating_sub(1)
|
range.start.saturating_sub(1)..range.end.saturating_sub(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "code_diff_view_tests.rs"]
|
||||||
|
mod tests;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blocked_action_status_makes_queued_diff_actionable() {
|
||||||
|
let mut state = CodeDiffState::Queued;
|
||||||
|
|
||||||
|
state.sync_with_action_status(Some(&AIActionStatus::Blocked));
|
||||||
|
|
||||||
|
assert!(state.is_waiting_for_user());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preprocessing_action_status_keeps_diff_queued() {
|
||||||
|
let mut state = CodeDiffState::Queued;
|
||||||
|
|
||||||
|
state.sync_with_action_status(Some(&AIActionStatus::Preprocessing));
|
||||||
|
|
||||||
|
assert!(matches!(state, CodeDiffState::Queued));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user