Merge branch 'master' of gitlab.com:samnasbo/shared/galaxy into experiment/cross-check

# Conflicts:
#	app/src/settings_view/mod.rs
This commit is contained in:
Ryan Ward
2026-07-23 13:17:04 -05:00
61 changed files with 953 additions and 22422 deletions
@@ -13,7 +13,7 @@ use crate::ai::agent::{
DocumentContext, EditDocumentsRequest, EditDocumentsResult, ReadDocumentsRequest,
ReadDocumentsResult,
};
use crate::ai::document::ai_document_model::AIDocumentVersion;
use crate::ai::document::ai_document_model::{AIDocumentId, AIDocumentVersion};
use crate::cloud_object::model::persistence::CloudModel;
use crate::notebooks::CloudNotebookModel;
use crate::server::cloud_objects::update_manager::UpdateManager;
@@ -59,10 +59,11 @@ impl NotebookExecutor {
for document in documents {
let client_id = ClientId::new();
let document_id = AIDocumentId::new();
let model = CloudNotebookModel {
title: document.title.clone(),
data: document.content.clone(),
ai_document_id: None,
ai_document_id: Some(document_id),
conversation_id: None,
};
@@ -79,7 +80,7 @@ impl NotebookExecutor {
});
created.push(DocumentContext {
document_id: crate::ai::document::ai_document_model::AIDocumentId::new(),
document_id,
document_version: AIDocumentVersion::default(),
content: document.content.clone(),
line_ranges: vec![],
@@ -112,10 +113,15 @@ impl NotebookExecutor {
let mut documents = Vec::new();
for id in document_ids {
// Try to find the notebook by treating the ID as a SyncId string
// Look up the notebook by its ai_document_id field, falling back to SyncId matching
let notebook = cloud_model
.get_all_active_notebooks()
.find(|nb| nb.id.uid() == id.to_string());
.find(|nb| nb.model().ai_document_id.as_ref() == Some(id))
.or_else(|| {
cloud_model
.get_all_active_notebooks()
.find(|nb| nb.id.uid() == id.to_string())
});
if let Some(notebook) = notebook {
documents.push(DocumentContext {
@@ -149,9 +155,15 @@ impl NotebookExecutor {
for diff in diffs {
let cloud_model = CloudModel::as_ref(ctx);
// Look up the notebook by its ai_document_id field, falling back to SyncId matching
let notebook_data = cloud_model
.get_all_active_notebooks()
.find(|nb| nb.id.uid() == diff.document_id.to_string())
.find(|nb| nb.model().ai_document_id.as_ref() == Some(&diff.document_id))
.or_else(|| {
cloud_model
.get_all_active_notebooks()
.find(|nb| nb.id.uid() == diff.document_id.to_string())
})
.map(|nb| (nb.id, nb.model().data.clone()));
let Some((notebook_id, current_data)) = notebook_data else {
@@ -1,11 +1,5 @@
use warpui::elements::{ChildView, Element, Empty};
use warpui::{AppContext, Entity, SingletonEntity, TypedActionView, View, ViewContext, ViewHandle};
use crate::settings_view::handoff_environment_creation_modal::{
HandoffEnvironmentCreationModal, HandoffEnvironmentCreationModalEvent,
};
use crate::view_components::DismissibleToast;
use crate::workspace::ToastStack;
use warpui::elements::{Element, Empty};
use warpui::{AppContext, Entity, TypedActionView, View, ViewContext};
#[derive(Debug, Clone)]
pub enum CreateEnvironmentModalEvent {
@@ -15,38 +9,11 @@ pub enum CreateEnvironmentModalEvent {
pub struct CreateEnvironmentModal {
visible: bool,
handoff_modal: ViewHandle<HandoffEnvironmentCreationModal>,
}
impl CreateEnvironmentModal {
pub fn new(ctx: &mut ViewContext<Self>) -> Self {
let handoff_modal =
ctx.add_typed_action_view(HandoffEnvironmentCreationModal::new_for_orchestration);
ctx.subscribe_to_view(&handoff_modal, |me, _, event, ctx| match event {
HandoffEnvironmentCreationModalEvent::Created { env_id } => {
me.visible = false;
ctx.emit(CreateEnvironmentModalEvent::Created {
environment_id: env_id.uid(),
});
ctx.notify();
}
HandoffEnvironmentCreationModalEvent::Cancelled => {
me.cancel(ctx);
}
HandoffEnvironmentCreationModalEvent::CreationFailed { error_message } => {
me.visible = false;
me.show_error_toast(
format!("Failed to create environment: {error_message}"),
ctx,
);
ctx.notify();
}
});
Self {
visible: false,
handoff_modal,
}
pub fn new(_ctx: &mut ViewContext<Self>) -> Self {
Self { visible: false }
}
pub fn is_visible(&self) -> bool {
@@ -55,10 +22,7 @@ impl CreateEnvironmentModal {
pub fn show(&mut self, ctx: &mut ViewContext<Self>) {
self.visible = true;
self.handoff_modal.update(ctx, |modal, ctx| {
modal.show(ctx);
});
ctx.focus(&self.handoff_modal);
ctx.emit(CreateEnvironmentModalEvent::Cancelled);
ctx.notify();
}
@@ -66,18 +30,6 @@ impl CreateEnvironmentModal {
self.visible = false;
ctx.notify();
}
fn cancel(&mut self, ctx: &mut ViewContext<Self>) {
self.hide(ctx);
ctx.emit(CreateEnvironmentModalEvent::Cancelled);
}
fn show_error_toast(&self, message: String, ctx: &mut ViewContext<Self>) {
let window_id = ctx.window_id();
ToastStack::handle(ctx).update(ctx, |toast_stack, ctx| {
toast_stack.add_ephemeral_toast(DismissibleToast::error(message), window_id, ctx);
});
}
}
impl Entity for CreateEnvironmentModal {
@@ -96,11 +48,7 @@ impl View for CreateEnvironmentModal {
}
fn render(&self, _app: &AppContext) -> Box<dyn Element> {
if !self.visible {
return Empty::new().finish();
}
ChildView::new(&self.handoff_modal).finish()
Empty::new().finish()
}
}
@@ -1476,9 +1476,8 @@ impl View for RequestedCommandView {
let is_input_pinned_to_top =
*InputModeSettings::as_ref(app).input_mode.value() == InputMode::PinnedToTop;
// When expanded details are rendered using a regular block, having a non-zero horizontal
// margin while toggled expanded will cause the body to look wider than the header.
// The expanded details should also appear connected to the header, so we remove bottom margin in this case.
// Tracks whether the expanded command has a terminal output block directly below it.
// Used to remove the bottom margin for visual continuity with the terminal block.
let is_rendered_above_expanded_command_block = {
let terminal_model = self.terminal_model.lock();
@@ -1517,7 +1516,6 @@ impl View for RequestedCommandView {
let header_element = self.render_header(
!should_render_editor
&& !should_render_mcp_content
&& !is_rendered_above_expanded_command_block
&& !has_citations_footer,
app,
);
@@ -1613,12 +1611,9 @@ impl View for RequestedCommandView {
theme.surface_2()
};
// If the requested command state is completed and input isn't pinned to the top, we're
// going to have a regular block directly below this one with the output of the executed
// command. Since we can't control the top padding of the AI block that comes _after_ the
// subsequent regular block, we'll simply need to eliminate the bottom margin on this block
// and have the next AI block take care of the vertical spacing. Moreover, having a non-zero
// bottom margin while expanded will cause the body to look disconnected from the header.
// If the requested command is expanded above a terminal block or
// the next exchange flows directly after, remove bottom margin for
// visual continuity.
let should_remove_bottom_margin = is_rendered_above_expanded_command_block
|| ((self.action_type.is_requested_command() || self.action_type.is_mcp_tool())
&& is_last_output_message_in_output
@@ -1645,28 +1640,20 @@ impl View for RequestedCommandView {
&& !is_input_pinned_to_top);
let container = Container::new(content.finish())
.with_margin_left(if is_rendered_above_expanded_command_block {
0.
} else if action_status.is_some_and(|status| status.is_blocked()) {
CONTENT_HORIZONTAL_PADDING
} else {
CONTENT_HORIZONTAL_PADDING + icon_size(app) + 16.
})
.with_margin_right(if is_rendered_above_expanded_command_block {
0.
} else {
CONTENT_HORIZONTAL_PADDING
})
.with_margin_left(
if action_status.is_some_and(|status| status.is_blocked()) {
CONTENT_HORIZONTAL_PADDING
} else {
CONTENT_HORIZONTAL_PADDING + icon_size(app) + 16.
},
)
.with_margin_right(CONTENT_HORIZONTAL_PADDING)
.with_margin_bottom(if should_remove_bottom_margin {
0.
} else {
CONTENT_ITEM_VERTICAL_MARGIN
})
.with_corner_radius(if is_rendered_above_expanded_command_block {
CornerRadius::with_top(Radius::Pixels(8.))
} else {
CornerRadius::with_all(Radius::Pixels(8.))
})
.with_corner_radius(CornerRadius::with_all(Radius::Pixels(8.)))
.with_border(Border::all(1.).with_border_fill(border_color))
.finish();
+1 -1
View File
@@ -392,7 +392,7 @@ impl View for PromptAlertView {
text_fragments.push(FormattedTextFragment::plain_text(" "));
text_fragments.push(FormattedTextFragment::hyperlink_action(
"Add credits",
WorkspaceAction::ShowSettingsPage(SettingsSection::BillingAndUsage),
WorkspaceAction::ShowSettingsPage(SettingsSection::About),
));
} else {
self.action_hyperlink(&state, &mut text_fragments, app);