first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -1,22 +1,13 @@
|
||||
#![allow(dead_code, unused_imports, unused_variables)]
|
||||
use galaxyui::{
|
||||
elements::{CornerRadius, Dismiss, MouseStateHandle, Radius},
|
||||
fonts::Weight,
|
||||
platform::Cursor,
|
||||
ui_components::{
|
||||
button::ButtonVariant,
|
||||
components::{Coords, UiComponent, UiComponentStyles},
|
||||
},
|
||||
AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
};
|
||||
use galaxyui::elements::{Container, CornerRadius, Dismiss, MouseStateHandle, Radius};
|
||||
use galaxyui::fonts::Weight;
|
||||
use galaxyui::platform::Cursor;
|
||||
use galaxyui::ui_components::button::ButtonVariant;
|
||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
ui_components::{
|
||||
blended_colors,
|
||||
dialog::{dialog_styles, Dialog},
|
||||
},
|
||||
};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::ui_components::blended_colors;
|
||||
use crate::ui_components::dialog::{dialog_styles, Dialog};
|
||||
|
||||
const BUTTON_PADDING: f32 = 12.;
|
||||
const BUTTON_FONT_SIZE: f32 = 14.;
|
||||
@@ -28,12 +19,17 @@ const CANCEL_TEXT: &str = "Cancel";
|
||||
|
||||
const DELETE_TEAM_TITLE_TEXT: &str = "Are you sure you want to delete this team?";
|
||||
const LEAVE_TEAM_TITLE_TEXT: &str = "Are you sure you want to leave this team?";
|
||||
const REMOVE_TEAM_MEMBER_TITLE_TEXT: &str = "Are you sure you want to remove this member?";
|
||||
|
||||
const DELETE_TEAM_BODY_TEXT: &str = "Deleting this team will permanently delete it and all of its related content, including billing information or credits. You will not be able to restore them.";
|
||||
const LEAVE_TEAM_BODY_TEXT: &str = "You will need to be reinvited in order to rejoin.";
|
||||
const LEAVE_TEAM_RELOAD_CREDITS_BODY_TEXT: &str = "If you leave this team, you’ll lose access to any remaining reload credits tied to it. You’ll regain access to any unused, non-expired credits if you rejoin the same team later.";
|
||||
const REMOVE_TEAM_MEMBER_RELOAD_CREDITS_BODY_TEXT: &str = "This member will lose access to any remaining reload credits tied to this team. If they rejoin later, they’ll regain access to any unused, non-expired credits.";
|
||||
|
||||
const DELETE_TEAM_CONFIRM_TEXT: &str = "Yes, delete";
|
||||
const LEAVE_TEAM_CONFIRM_TEXT: &str = "Yes, leave";
|
||||
const LEAVE_TEAM_RELOAD_CREDITS_CONFIRM_TEXT: &str = "Leave Team";
|
||||
const REMOVE_TEAM_MEMBER_RELOAD_CREDITS_CONFIRM_TEXT: &str = "Remove Member";
|
||||
|
||||
pub enum CloudActionConfirmationDialogEvent {
|
||||
Cancel,
|
||||
@@ -50,6 +46,8 @@ pub enum CloudActionConfirmationDialogAction {
|
||||
pub enum CloudActionConfirmationDialogVariant {
|
||||
LeaveTeam,
|
||||
DeleteTeam,
|
||||
LeaveTeamReloadCredits,
|
||||
RemoveTeamMemberReloadCredits,
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
@@ -81,9 +79,15 @@ impl CloudActionConfirmationDialog {
|
||||
|
||||
fn title_text(&self) -> String {
|
||||
match self.variant {
|
||||
CloudActionConfirmationDialogVariant::LeaveTeam => LEAVE_TEAM_TITLE_TEXT.to_string(),
|
||||
CloudActionConfirmationDialogVariant::LeaveTeam
|
||||
| CloudActionConfirmationDialogVariant::LeaveTeamReloadCredits => {
|
||||
LEAVE_TEAM_TITLE_TEXT.to_string()
|
||||
}
|
||||
CloudActionConfirmationDialogVariant::DeleteTeam => DELETE_TEAM_TITLE_TEXT.to_string(),
|
||||
CloudActionConfirmationDialogVariant::None => "".to_string(),
|
||||
CloudActionConfirmationDialogVariant::RemoveTeamMemberReloadCredits => {
|
||||
REMOVE_TEAM_MEMBER_TITLE_TEXT.to_string()
|
||||
}
|
||||
CloudActionConfirmationDialogVariant::None => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +95,13 @@ impl CloudActionConfirmationDialog {
|
||||
match self.variant {
|
||||
CloudActionConfirmationDialogVariant::LeaveTeam => LEAVE_TEAM_BODY_TEXT.to_string(),
|
||||
CloudActionConfirmationDialogVariant::DeleteTeam => DELETE_TEAM_BODY_TEXT.to_string(),
|
||||
CloudActionConfirmationDialogVariant::None => "".to_string(),
|
||||
CloudActionConfirmationDialogVariant::LeaveTeamReloadCredits => {
|
||||
LEAVE_TEAM_RELOAD_CREDITS_BODY_TEXT.to_string()
|
||||
}
|
||||
CloudActionConfirmationDialogVariant::RemoveTeamMemberReloadCredits => {
|
||||
REMOVE_TEAM_MEMBER_RELOAD_CREDITS_BODY_TEXT.to_string()
|
||||
}
|
||||
CloudActionConfirmationDialogVariant::None => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +111,13 @@ impl CloudActionConfirmationDialog {
|
||||
CloudActionConfirmationDialogVariant::DeleteTeam => {
|
||||
DELETE_TEAM_CONFIRM_TEXT.to_string()
|
||||
}
|
||||
CloudActionConfirmationDialogVariant::None => "".to_string(),
|
||||
CloudActionConfirmationDialogVariant::LeaveTeamReloadCredits => {
|
||||
LEAVE_TEAM_RELOAD_CREDITS_CONFIRM_TEXT.to_string()
|
||||
}
|
||||
CloudActionConfirmationDialogVariant::RemoveTeamMemberReloadCredits => {
|
||||
REMOVE_TEAM_MEMBER_RELOAD_CREDITS_CONFIRM_TEXT.to_string()
|
||||
}
|
||||
CloudActionConfirmationDialogVariant::None => String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,7 +210,11 @@ impl View for CloudActionConfirmationDialog {
|
||||
dialog_styles(appearance),
|
||||
)
|
||||
.with_bottom_row_child(cancel_button)
|
||||
.with_bottom_row_child(confirm_button)
|
||||
.with_bottom_row_child(
|
||||
Container::new(confirm_button)
|
||||
.with_margin_left(12.)
|
||||
.finish(),
|
||||
)
|
||||
.with_width(DIALOG_WIDTH)
|
||||
.build()
|
||||
.finish();
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
use galaxyui::{
|
||||
elements::{
|
||||
Border, Clipped, Container, CornerRadius, Dismiss, Empty, Flex, MainAxisSize,
|
||||
MouseStateHandle, ParentElement, Radius, Shrinkable, Text,
|
||||
},
|
||||
fonts::Weight,
|
||||
platform::Cursor,
|
||||
presenter::ChildView,
|
||||
ui_components::{
|
||||
button::ButtonVariant,
|
||||
components::{Coords, UiComponent, UiComponentStyles},
|
||||
},
|
||||
AppContext, Element, ViewHandle,
|
||||
use galaxyui::elements::{
|
||||
Border, Clipped, Container, CornerRadius, Dismiss, Empty, Flex, MainAxisSize, MouseStateHandle,
|
||||
ParentElement, Radius, Shrinkable, Text,
|
||||
};
|
||||
use warpui::fonts::Weight;
|
||||
use warpui::platform::Cursor;
|
||||
use warpui::presenter::ChildView;
|
||||
use warpui::ui_components::button::ButtonVariant;
|
||||
use warpui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
use warpui::{AppContext, Element, ViewHandle};
|
||||
|
||||
use super::index::DriveIndexAction;
|
||||
use super::DriveObjectType;
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::Space;
|
||||
use crate::{
|
||||
appearance::Appearance, editor::EditorView, server::ids::SyncId, ui_components::blended_colors,
|
||||
};
|
||||
|
||||
use super::{index::DriveIndexAction, DriveObjectType};
|
||||
use crate::editor::EditorView;
|
||||
use crate::server::ids::SyncId;
|
||||
use crate::ui_components::blended_colors;
|
||||
|
||||
const DIALOG_PADDING: f32 = 24.;
|
||||
const INPUT_MARGIN_TOP: f32 = 16.;
|
||||
@@ -39,7 +36,7 @@ const CREATE_BUTTON_TEXT: &str = "Create";
|
||||
const CANCEL_BUTTON_TEXT: &str = "Cancel";
|
||||
const RENAME_BUTTON_TEXT: &str = "Rename";
|
||||
|
||||
/// Struct holding necessary infromation and states for the dialog
|
||||
/// Struct holding necessary information and states for the dialog
|
||||
/// that opens when creating or updating a folder or notebook.
|
||||
///
|
||||
/// This dialog can be opened for a folder or a space. If open_for_folder_id = None, it's a space.
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use galaxy_core::ui::{
|
||||
appearance::Appearance,
|
||||
color::{contrast::MinimumAllowedContrast, ContrastingColor},
|
||||
theme::Fill,
|
||||
};
|
||||
use pathfinder_color::ColorU;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_core::ui::color::contrast::MinimumAllowedContrast;
|
||||
use galaxy_core::ui::color::ContrastingColor;
|
||||
use galaxy_core::ui::theme::Fill;
|
||||
|
||||
use super::DriveObjectType;
|
||||
use crate::ui_components::blended_colors;
|
||||
|
||||
+108
-60
@@ -1,83 +1,131 @@
|
||||
use galaxyui::{SingletonEntity, ViewContext};
|
||||
use warp_server_auth::auth_state::AuthState;
|
||||
use warp_server_auth::user::PersonalObjectLimits;
|
||||
use warp_server_auth::AuthStateProvider;
|
||||
use galaxyui::{AppContext, SingletonEntity};
|
||||
|
||||
use crate::{
|
||||
auth::{auth_manager::AuthManager, AuthStateProvider},
|
||||
cloud_object::{
|
||||
model::persistence::CloudModel, GenericStringObjectFormat, JsonObjectType, ObjectType,
|
||||
Space,
|
||||
},
|
||||
};
|
||||
use crate::auth::auth_manager::AuthManager;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::Space;
|
||||
|
||||
pub fn has_feature_gated_anonymous_user_reached_notebook_limit<V: galaxyui::View>(
|
||||
ctx: &mut ViewContext<V>,
|
||||
#[derive(Clone, Copy)]
|
||||
enum AnonymousUserObjectLimit {
|
||||
Notebook,
|
||||
Workflow,
|
||||
EnvVarCollection,
|
||||
}
|
||||
|
||||
impl AnonymousUserObjectLimit {
|
||||
fn is_exceeded(self, limits: PersonalObjectLimits, num_objects: usize) -> bool {
|
||||
match self {
|
||||
Self::Notebook => num_objects > limits.notebook_limit,
|
||||
Self::Workflow => num_objects > limits.workflow_limit,
|
||||
Self::EnvVarCollection => num_objects > limits.env_var_limit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_feature_gated_anonymous_user_past_limit(
|
||||
auth_state: &AuthState,
|
||||
num_objects: usize,
|
||||
object_limit: AnonymousUserObjectLimit,
|
||||
) -> bool {
|
||||
auth_state
|
||||
.is_anonymous_user_feature_gated()
|
||||
.unwrap_or_default()
|
||||
&& auth_state
|
||||
.personal_object_limits()
|
||||
.is_some_and(|limits| object_limit.is_exceeded(limits, num_objects))
|
||||
}
|
||||
|
||||
pub(crate) fn is_feature_gated_anonymous_user_past_notebook_limit(
|
||||
auth_state: &AuthState,
|
||||
num_objects: usize,
|
||||
) -> bool {
|
||||
is_feature_gated_anonymous_user_past_limit(
|
||||
auth_state,
|
||||
num_objects,
|
||||
AnonymousUserObjectLimit::Notebook,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn is_feature_gated_anonymous_user_past_workflow_limit(
|
||||
auth_state: &AuthState,
|
||||
num_objects: usize,
|
||||
) -> bool {
|
||||
is_feature_gated_anonymous_user_past_limit(
|
||||
auth_state,
|
||||
num_objects,
|
||||
AnonymousUserObjectLimit::Workflow,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn is_feature_gated_anonymous_user_past_env_var_limit(
|
||||
auth_state: &AuthState,
|
||||
num_objects: usize,
|
||||
) -> bool {
|
||||
is_feature_gated_anonymous_user_past_limit(
|
||||
auth_state,
|
||||
num_objects,
|
||||
AnonymousUserObjectLimit::EnvVarCollection,
|
||||
)
|
||||
}
|
||||
|
||||
fn has_feature_gated_anonymous_user_reached_limit(
|
||||
ctx: &mut AppContext,
|
||||
num_objects: usize,
|
||||
object_limit: AnonymousUserObjectLimit,
|
||||
) -> bool {
|
||||
if AuthStateProvider::handle(ctx).read(ctx, |auth_state_provider, _ctx| {
|
||||
is_feature_gated_anonymous_user_past_limit(
|
||||
auth_state_provider.get(),
|
||||
num_objects,
|
||||
object_limit,
|
||||
)
|
||||
}) {
|
||||
AuthManager::handle(ctx).update(ctx, |auth_manager: &mut AuthManager, ctx| {
|
||||
auth_manager.anonymous_user_hit_drive_object_limit(ctx);
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn has_feature_gated_anonymous_user_reached_notebook_limit(ctx: &mut AppContext) -> bool {
|
||||
let count = CloudModel::handle(ctx).read(ctx, |model, ctx| {
|
||||
model
|
||||
.active_non_welcome_notebooks_in_space(Space::Personal, ctx)
|
||||
.count()
|
||||
});
|
||||
if AuthStateProvider::handle(ctx).read(ctx, |auth_state_provider, _ctx| {
|
||||
auth_state_provider
|
||||
.get()
|
||||
.is_anonymous_user_past_object_limit(ObjectType::Notebook, count + 1)
|
||||
.unwrap_or_default()
|
||||
}) {
|
||||
AuthManager::handle(ctx).update(ctx, |auth_manager: &mut AuthManager, ctx| {
|
||||
auth_manager.anonymous_user_hit_drive_object_limit(ctx);
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
false
|
||||
has_feature_gated_anonymous_user_reached_limit(
|
||||
ctx,
|
||||
count + 1,
|
||||
AnonymousUserObjectLimit::Notebook,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn has_feature_gated_anonymous_user_reached_workflow_limit<V: galaxyui::View>(
|
||||
ctx: &mut ViewContext<V>,
|
||||
) -> bool {
|
||||
pub fn has_feature_gated_anonymous_user_reached_workflow_limit(ctx: &mut AppContext) -> bool {
|
||||
let count = CloudModel::handle(ctx).read(ctx, |model, ctx| {
|
||||
model
|
||||
.active_non_welcome_workflows_in_space(Space::Personal, ctx)
|
||||
.count()
|
||||
});
|
||||
if AuthStateProvider::handle(ctx).read(ctx, |auth_state_provider, _ctx| {
|
||||
auth_state_provider
|
||||
.get()
|
||||
.is_anonymous_user_past_object_limit(ObjectType::Workflow, count + 1)
|
||||
.unwrap_or_default()
|
||||
}) {
|
||||
AuthManager::handle(ctx).update(ctx, |auth_manager: &mut AuthManager, ctx| {
|
||||
auth_manager.anonymous_user_hit_drive_object_limit(ctx);
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
false
|
||||
has_feature_gated_anonymous_user_reached_limit(
|
||||
ctx,
|
||||
count + 1,
|
||||
AnonymousUserObjectLimit::Workflow,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn has_feature_gated_anonymous_user_reached_env_var_limit<V: galaxyui::View>(
|
||||
ctx: &mut ViewContext<V>,
|
||||
) -> bool {
|
||||
pub fn has_feature_gated_anonymous_user_reached_env_var_limit(ctx: &mut AppContext) -> bool {
|
||||
let count = CloudModel::handle(ctx).read(ctx, |model, ctx| {
|
||||
model
|
||||
.active_non_welcome_env_var_collections_in_space(Space::Personal, ctx)
|
||||
.count()
|
||||
});
|
||||
if AuthStateProvider::handle(ctx).read(ctx, |auth_state_provider, _ctx| {
|
||||
auth_state_provider
|
||||
.get()
|
||||
.is_anonymous_user_past_object_limit(
|
||||
ObjectType::GenericStringObject(GenericStringObjectFormat::Json(
|
||||
JsonObjectType::EnvVarCollection,
|
||||
)),
|
||||
count + 1,
|
||||
)
|
||||
.unwrap_or_default()
|
||||
}) {
|
||||
AuthManager::handle(ctx).update(ctx, |auth_manager: &mut AuthManager, ctx| {
|
||||
auth_manager.anonymous_user_hit_drive_object_limit(ctx);
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
false
|
||||
has_feature_gated_anonymous_user_reached_limit(
|
||||
ctx,
|
||||
count + 1,
|
||||
AnonymousUserObjectLimit::EnvVarCollection,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
use galaxyui::{
|
||||
elements::MouseStateHandle,
|
||||
fonts::Weight,
|
||||
platform::Cursor,
|
||||
ui_components::{
|
||||
button::ButtonVariant,
|
||||
components::{Coords, UiComponent, UiComponentStyles},
|
||||
},
|
||||
AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
};
|
||||
use galaxyui::elements::MouseStateHandle;
|
||||
use galaxyui::fonts::Weight;
|
||||
use galaxyui::platform::Cursor;
|
||||
use galaxyui::ui_components::button::ButtonVariant;
|
||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
use galaxyui::{AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
ui_components::dialog::{dialog_styles, Dialog},
|
||||
};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::ui_components::dialog::{dialog_styles, Dialog};
|
||||
|
||||
const CANCEL_TEXT: &str = "Cancel";
|
||||
|
||||
|
||||
+13
-20
@@ -1,12 +1,8 @@
|
||||
use std::collections::hash_map::{Entry, OccupiedEntry};
|
||||
use std::collections::HashMap;
|
||||
#[cfg(feature = "local_fs")]
|
||||
use std::io::ErrorKind;
|
||||
use std::{
|
||||
collections::{
|
||||
hash_map::{Entry, OccupiedEntry},
|
||||
HashMap,
|
||||
},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[cfg(feature = "local_fs")]
|
||||
use aho_corasick::{AhoCorasick, MatchKind};
|
||||
@@ -15,18 +11,17 @@ use anyhow::{anyhow, Context};
|
||||
#[cfg(feature = "local_fs")]
|
||||
use futures::AsyncWriteExt;
|
||||
use galaxy_util::path::ShellFamily;
|
||||
use galaxyui::{
|
||||
platform::{file_picker::FilePickerError, FilePickerConfiguration, OperatingSystem},
|
||||
r#async::SpawnedFutureHandle,
|
||||
AppContext, Entity, ModelContext, SingletonEntity, WindowId,
|
||||
};
|
||||
use galaxyui::platform::file_picker::FilePickerError;
|
||||
use galaxyui::platform::{FilePickerConfiguration, OperatingSystem};
|
||||
use galaxyui::r#async::SpawnedFutureHandle;
|
||||
use galaxyui::{AppContext, Entity, ModelContext, SingletonEntity, WindowId};
|
||||
|
||||
use crate::{
|
||||
cloud_object::{model::persistence::CloudModel, Space},
|
||||
safe_warn,
|
||||
view_components::DismissibleToast,
|
||||
workspace::{active_terminal_in_window, ToastStack},
|
||||
};
|
||||
use super::CloudObjectTypeAndId;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::Space;
|
||||
use crate::safe_warn;
|
||||
use crate::view_components::DismissibleToast;
|
||||
use crate::workspace::{active_terminal_in_window, ToastStack};
|
||||
#[cfg(feature = "local_fs")]
|
||||
use crate::{
|
||||
notebooks::export_notebook, server::cloud_objects::update_manager::get_duplicate_object_name,
|
||||
@@ -34,8 +29,6 @@ use crate::{
|
||||
workspace::WorkspaceAction,
|
||||
};
|
||||
|
||||
use super::CloudObjectTypeAndId;
|
||||
|
||||
/// Singleton model for exporting from Warp Drive.
|
||||
pub struct ExportManager {
|
||||
exports: HashMap<ExportId, Export>,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::channel::oneshot;
|
||||
use galaxy_util::path::ShellFamily;
|
||||
@@ -11,20 +9,18 @@ use galaxyui::{AddSingletonModel, App, SingletonEntity, WindowId};
|
||||
use parking_lot::Mutex;
|
||||
use tempfile::TempDir;
|
||||
|
||||
use crate::{
|
||||
cloud_object::{
|
||||
model::persistence::CloudModel, CloudObjectMetadata, CloudObjectPermissions, ObjectIdType,
|
||||
ObjectType, Space,
|
||||
},
|
||||
drive::CloudObjectTypeAndId,
|
||||
notebooks::{CloudNotebook, CloudNotebookModel, NotebookId},
|
||||
server::ids::SyncId,
|
||||
workflows::{workflow::Workflow, CloudWorkflow, CloudWorkflowModel, WorkflowId},
|
||||
workspace::ToastStack,
|
||||
workspaces::user_workspaces::UserWorkspaces,
|
||||
};
|
||||
|
||||
use super::{safe_filename, ExportEvent, ExportId, ExportManager};
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::{
|
||||
CloudObjectMetadata, CloudObjectPermissions, ObjectIdType, ObjectType, Space,
|
||||
};
|
||||
use crate::drive::CloudObjectTypeAndId;
|
||||
use crate::notebooks::{CloudNotebook, CloudNotebookModel, NotebookId};
|
||||
use crate::server::ids::SyncId;
|
||||
use crate::workflows::workflow::Workflow;
|
||||
use crate::workflows::{CloudWorkflow, CloudWorkflowModel, WorkflowId};
|
||||
use crate::workspace::ToastStack;
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
|
||||
struct ExportTest {
|
||||
target_dir: TempDir,
|
||||
|
||||
@@ -1,52 +1,25 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::items::folder::WarpDriveFolder;
|
||||
use super::items::WarpDriveItem;
|
||||
use super::CloudObjectTypeAndId;
|
||||
use crate::server::cloud_objects::update_manager::InitiatedBy;
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::{
|
||||
CloudModelType, CloudObjectEventEntrypoint, CreateCloudObjectResult, CreateObjectRequest,
|
||||
GenericCloudObject, GenericServerObject, ObjectType, Revision, ServerCloudObject, Space,
|
||||
UpdateCloudObjectResult,
|
||||
},
|
||||
persistence::ModelEvent,
|
||||
server::{
|
||||
ids::{ServerId, SyncId},
|
||||
server_api::object::ObjectClient,
|
||||
sync_queue::{QueueItem, SerializedModel},
|
||||
},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
|
||||
pub use cloud_object_models::{CloudFolder, CloudFolderModel};
|
||||
// Re-exported from galaxy_server_client.
|
||||
pub use galaxy_server_client::ids::FolderId;
|
||||
|
||||
/// The model for a `CloudFolder`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CloudFolderModel {
|
||||
pub name: String,
|
||||
// TODO: since this is local only state, we should consider only surfacing it as part of the
|
||||
// CloudViewModel. Right now, every server folder uses CloudFolderModel, which means it
|
||||
// hardcodes a value of `false` for this property since it can't know what the local state is.
|
||||
pub is_open: bool,
|
||||
pub is_warp_pack: bool,
|
||||
}
|
||||
|
||||
impl CloudFolderModel {
|
||||
pub fn new(name: &str, is_warp_pack: bool) -> Self {
|
||||
Self {
|
||||
name: name.to_owned(),
|
||||
is_open: false,
|
||||
is_warp_pack,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `CloudFolder` is a folder retrieved from the server.
|
||||
pub type CloudFolder = GenericCloudObject<FolderId, CloudFolderModel>;
|
||||
// Re-exported from warp_server_client.
|
||||
use super::items::folder::WarpDriveFolder;
|
||||
use super::items::WarpDriveItem;
|
||||
use super::CloudObjectTypeAndId;
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::{
|
||||
CloudModelType, CloudObjectEventEntrypoint, CloudObjectUpsertParams, CreateCloudObjectResult,
|
||||
CreateObjectRequest, GenericServerObject, ObjectType, Revision, Space, UpdateCloudObjectResult,
|
||||
};
|
||||
use crate::persistence::ModelEvent;
|
||||
use crate::server::cloud_objects::update_manager::InitiatedBy;
|
||||
use crate::server::ids::{ServerId, SyncId};
|
||||
use crate::server::server_api::object::ObjectClient;
|
||||
use crate::server::sync_queue::{QueueItem, SerializedModel};
|
||||
|
||||
#[cfg_attr(not(target_family = "wasm"), async_trait)]
|
||||
#[cfg_attr(target_family = "wasm", async_trait(?Send))]
|
||||
@@ -70,14 +43,14 @@ impl CloudModelType for CloudFolderModel {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
fn upsert_event(&self, folder: &CloudFolder) -> ModelEvent {
|
||||
fn upsert_event(params: CloudObjectUpsertParams<Self>) -> ModelEvent {
|
||||
ModelEvent::UpsertFolder {
|
||||
folder: folder.clone(),
|
||||
folder: CloudFolder::from(params),
|
||||
}
|
||||
}
|
||||
|
||||
fn bulk_upsert_event(objects: &[CloudFolder]) -> ModelEvent {
|
||||
ModelEvent::UpsertFolders(objects.to_vec())
|
||||
fn bulk_upsert_event(objects: Vec<CloudObjectUpsertParams<Self>>) -> ModelEvent {
|
||||
ModelEvent::UpsertFolders(objects.into_iter().map(CloudFolder::from).collect())
|
||||
}
|
||||
|
||||
fn create_object_queue_item(
|
||||
@@ -120,17 +93,6 @@ impl CloudModelType for CloudFolderModel {
|
||||
SerializedModel::new(self.name.to_owned())
|
||||
}
|
||||
|
||||
fn new_from_server_update(&self, server_cloud_object: &ServerCloudObject) -> Option<Self> {
|
||||
if let ServerCloudObject::Folder(server_folder) = server_cloud_object {
|
||||
return Some(CloudFolderModel {
|
||||
name: server_folder.model.name.clone(),
|
||||
is_open: self.is_open,
|
||||
is_warp_pack: server_folder.model.is_warp_pack,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn can_move_to_space(&self, current_space: Space, new_space: Space) -> bool {
|
||||
// We don't currently support moving folders across spaces.
|
||||
current_space == new_space
|
||||
|
||||
@@ -3,15 +3,14 @@ use std::env::current_dir;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxyui::App;
|
||||
|
||||
use crate::{
|
||||
cloud_object::model::persistence::CloudModel,
|
||||
network::NetworkStatus,
|
||||
server::{cloud_objects::update_manager::UpdateManager, sync_queue::SyncQueue},
|
||||
workspaces::{team_tester::TeamTesterStatus, user_workspaces::UserWorkspaces},
|
||||
GlobalResourceHandles, GlobalResourceHandlesProvider,
|
||||
};
|
||||
|
||||
use super::expand_dirs;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::network::NetworkStatus;
|
||||
use crate::server::cloud_objects::update_manager::UpdateManager;
|
||||
use crate::server::sync_queue::SyncQueue;
|
||||
use crate::workspaces::team_tester::TeamTesterStatus;
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
use crate::{GlobalResourceHandles, GlobalResourceHandlesProvider};
|
||||
|
||||
#[test]
|
||||
fn test_expand_directories() {
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::{model::persistence::CloudModel, CloudObject, Owner},
|
||||
server::{ids::SyncId, sync_queue::SyncQueue},
|
||||
themes::theme::GalaxyTheme,
|
||||
workspaces::user_workspaces::UserWorkspaces,
|
||||
};
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use galaxy_core::ui::theme::Fill;
|
||||
use galaxyui::elements::{
|
||||
Align, Border, ChildAnchor, ClippedScrollStateHandle, ClippedScrollable, ConstrainedBox,
|
||||
Container, CornerRadius, CrossAxisAlignment, Flex, Highlight, MouseStateHandle,
|
||||
OffsetPositioning, ParentAnchor, ParentElement, ParentOffsetBounds, Radius, ScrollbarWidth,
|
||||
Shrinkable, Stack, Text,
|
||||
};
|
||||
use galaxyui::platform::{FilePickerConfiguration, FileType};
|
||||
use galaxyui::presenter::ChildView;
|
||||
use galaxyui::ui_components::button::ButtonVariant;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::{
|
||||
elements::{
|
||||
Align, Border, ChildAnchor, ClippedScrollStateHandle, ClippedScrollable, ConstrainedBox,
|
||||
Container, CornerRadius, CrossAxisAlignment, Flex, Highlight, MouseStateHandle,
|
||||
OffsetPositioning, ParentAnchor, ParentElement, ParentOffsetBounds, Radius, ScrollbarWidth,
|
||||
Shrinkable, Stack, Text,
|
||||
},
|
||||
platform::{FilePickerConfiguration, FileType},
|
||||
presenter::ChildView,
|
||||
ui_components::{
|
||||
button::ButtonVariant,
|
||||
components::{UiComponent, UiComponentStyles},
|
||||
},
|
||||
AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext, ViewHandle,
|
||||
};
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
|
||||
use super::modal_body::{ImportModalBody, ImportModalBodyAction, ImportModalBodyEvent};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::{CloudObject, Owner};
|
||||
use crate::server::ids::SyncId;
|
||||
use crate::server::sync_queue::SyncQueue;
|
||||
use crate::themes::theme::WarpTheme;
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
|
||||
const CLOSE_BUTTON_SIZE: f32 = 24.;
|
||||
const HEADER_FONT_SIZE: f32 = 16.;
|
||||
|
||||
@@ -1,38 +1,31 @@
|
||||
use futures_util::stream::AbortHandle;
|
||||
use galaxyui::{
|
||||
elements::{
|
||||
Align, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Flex,
|
||||
MainAxisAlignment, MainAxisSize, MouseStateHandle, ParentElement, Radius,
|
||||
},
|
||||
platform::{file_picker::FilePickerError, Cursor},
|
||||
ui_components::{
|
||||
button::{ButtonVariant, TextAndIcon, TextAndIconAlignment},
|
||||
components::{Coords, UiComponent, UiComponentStyles},
|
||||
},
|
||||
AppContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
};
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::Owner,
|
||||
server::{
|
||||
ids::{ClientId, SyncId},
|
||||
sync_queue::SyncQueue,
|
||||
},
|
||||
ui_components::icons::Icon,
|
||||
view_components::DismissibleToast,
|
||||
workspace::ToastStack,
|
||||
use futures_util::stream::AbortHandle;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use galaxyui::elements::{
|
||||
Align, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Flex, MainAxisAlignment,
|
||||
MainAxisSize, MouseStateHandle, ParentElement, Radius,
|
||||
};
|
||||
use galaxyui::platform::file_picker::FilePickerError;
|
||||
use galaxyui::platform::Cursor;
|
||||
use galaxyui::ui_components::button::{ButtonVariant, TextAndIcon, TextAndIconAlignment};
|
||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
use galaxyui::{
|
||||
AppContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
};
|
||||
|
||||
use super::{
|
||||
modal::BODY_HEIGHT,
|
||||
nodes::{
|
||||
expand_dirs, parse_file, FileContent, FileId, FileUploadState, FolderId, UploadResult,
|
||||
},
|
||||
queue::{ImportQueue, ImportQueueArgs, ImportQueueEvent, ParentId, RequestContent},
|
||||
use super::modal::BODY_HEIGHT;
|
||||
use super::nodes::{
|
||||
expand_dirs, parse_file, FileContent, FileId, FileUploadState, FolderId, UploadResult,
|
||||
};
|
||||
use super::queue::{ImportQueue, ImportQueueArgs, ImportQueueEvent, ParentId, RequestContent};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::Owner;
|
||||
use crate::server::ids::{ClientId, SyncId};
|
||||
use crate::server::sync_queue::SyncQueue;
|
||||
use crate::ui_components::icons::Icon;
|
||||
use crate::view_components::DismissibleToast;
|
||||
use crate::workspace::ToastStack;
|
||||
|
||||
const FILE_PICKER_BUTTON_WIDTH: f32 = 250.;
|
||||
const BUTTON_FONT_SIZE: f32 = 14.;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use crate::drive::import::nodes::{UploadResult, UploadStatus};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::{FileId, FileNode, FileType, FileUploadState, FolderId, FolderNode, ImportedNode};
|
||||
use crate::drive::import::nodes::{UploadResult, UploadStatus};
|
||||
|
||||
fn mock_tree() -> FileUploadState {
|
||||
let mut folder_id_to_node = HashMap::new();
|
||||
|
||||
@@ -1,36 +1,31 @@
|
||||
use crate::{
|
||||
drive::{cloud_object_styling::warp_drive_icon_color, DriveObjectType},
|
||||
notebooks::post_process_notebook,
|
||||
workflows::{
|
||||
export_workflow::export_deserialize, workflow::Workflow, workflow_enum::WorkflowEnum,
|
||||
},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::ops::{Add, AddAssign, SubAssign};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use async_recursion::async_recursion;
|
||||
use futures_lite::StreamExt;
|
||||
use galaxyui::{
|
||||
elements::{
|
||||
Align, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Flex, Hoverable,
|
||||
MouseStateHandle, ParentElement, Radius, Shrinkable,
|
||||
},
|
||||
platform::Cursor,
|
||||
ui_components::components::{UiComponent, UiComponentStyles},
|
||||
Element,
|
||||
};
|
||||
use pathfinder_color::ColorU;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::OsStr,
|
||||
ops::{Add, AddAssign, SubAssign},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance, notebooks::file::is_markdown_file, server::ids::ClientId,
|
||||
themes::theme::Fill, ui_components::icons::Icon,
|
||||
use galaxyui::elements::{
|
||||
Align, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Flex, Hoverable,
|
||||
MouseStateHandle, ParentElement, Radius, Shrinkable,
|
||||
};
|
||||
use warpui::platform::Cursor;
|
||||
use warpui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use warpui::Element;
|
||||
|
||||
use super::modal_body::{ImportModalBodyAction, BASE_INDENT, IMPORT_FONT_SIZE, INDENT_MARGIN};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::drive::cloud_object_styling::warp_drive_icon_color;
|
||||
use crate::drive::DriveObjectType;
|
||||
use crate::notebooks::file::is_markdown_file;
|
||||
use crate::server::ids::ClientId;
|
||||
use crate::themes::theme::Fill;
|
||||
use crate::ui_components::icons::Icon;
|
||||
use crate::workflows::export_workflow::export_deserialize;
|
||||
use crate::workflows::workflow::Workflow;
|
||||
use crate::workflows::workflow_enum::WorkflowEnum;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "node_tests.rs"]
|
||||
@@ -756,7 +751,7 @@ impl FileUploadState {
|
||||
folder.server_id = Some(server_id.clone());
|
||||
|
||||
// If a folder has no children or all of its children complete syncing,
|
||||
// we need to bubble the state up in the folder hierachy tree.
|
||||
// we need to bubble the state up in the folder hierarchy tree.
|
||||
if folder.children().is_empty() || folder.all_children_synced {
|
||||
folder.status = UploadStatus::Loaded(server_id);
|
||||
true
|
||||
@@ -898,9 +893,7 @@ impl FileUploadState {
|
||||
|
||||
pub(super) async fn parse_file(path: PathBuf, file_type: FileType) -> Result<FileContent> {
|
||||
match file_type {
|
||||
FileType::Notebook => Ok(FileContent::Notebook(post_process_notebook(
|
||||
&async_fs::read_to_string(path).await?,
|
||||
))),
|
||||
FileType::Notebook => Ok(FileContent::Notebook(async_fs::read_to_string(path).await?)),
|
||||
FileType::Workflow => {
|
||||
let file = async_fs::read(path).await?;
|
||||
let mut workflow_enums: HashMap<ClientId, WorkflowEnum> = HashMap::new();
|
||||
|
||||
@@ -2,20 +2,17 @@ use std::collections::HashMap;
|
||||
|
||||
use galaxyui::{Entity, ModelContext, SingletonEntity};
|
||||
|
||||
use crate::{
|
||||
cloud_object::{model::persistence::CloudModel, CloudObjectEventEntrypoint, Owner},
|
||||
drive::folders::FolderId,
|
||||
notebooks::CloudNotebookModel,
|
||||
server::{
|
||||
cloud_objects::update_manager::{
|
||||
InitiatedBy, ObjectOperation, OperationSuccessType, UpdateManager, UpdateManagerEvent,
|
||||
},
|
||||
ids::{ClientId, SyncId},
|
||||
},
|
||||
workflows::{workflow::Workflow, workflow_enum::WorkflowEnum},
|
||||
};
|
||||
|
||||
use super::nodes::{self, FileId};
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::{CloudObjectEventEntrypoint, Owner};
|
||||
use crate::drive::folders::FolderId;
|
||||
use crate::notebooks::CloudNotebookModel;
|
||||
use crate::server::cloud_objects::update_manager::{
|
||||
InitiatedBy, ObjectOperation, OperationSuccessType, UpdateManager, UpdateManagerEvent,
|
||||
};
|
||||
use crate::server::ids::{ClientId, SyncId};
|
||||
use crate::workflows::workflow::Workflow;
|
||||
use crate::workflows::workflow_enum::WorkflowEnum;
|
||||
|
||||
pub(super) enum ImportQueueEvent {
|
||||
FileCompleted {
|
||||
@@ -105,7 +102,7 @@ pub(super) struct ImportQueue {
|
||||
impl ImportQueue {
|
||||
pub fn new(ctx: &mut ModelContext<Self>) -> Self {
|
||||
let update_manager = UpdateManager::handle(ctx);
|
||||
ctx.subscribe_to_model(&update_manager, |me, event, ctx| {
|
||||
ctx.subscribe_to_model(&update_manager, |me, _, event, ctx| {
|
||||
me.handle_update_manager_event(event, ctx);
|
||||
});
|
||||
|
||||
@@ -117,7 +114,7 @@ impl ImportQueue {
|
||||
}
|
||||
}
|
||||
|
||||
// Whether all dependcies of an item has been sync-ed.
|
||||
// Whether all dependencies of an item has been sync-ed.
|
||||
fn dependency_synced(&self, item: &ImportQueueArgs) -> bool {
|
||||
match &item.parent_id {
|
||||
ParentId::FolderToUpload(id) => self
|
||||
|
||||
+95
-105
@@ -1,111 +1,102 @@
|
||||
#[cfg(target_family = "wasm")]
|
||||
use crate::uri::web_intent_parser::open_url_on_desktop;
|
||||
use crate::{
|
||||
ai::{
|
||||
document::ai_document_model::AIDocumentId,
|
||||
facts::{AIFact, AIMemory},
|
||||
},
|
||||
appearance::Appearance,
|
||||
auth::{
|
||||
auth_manager::{AuthManager, LoginGatedFeature},
|
||||
auth_state::AuthState,
|
||||
auth_view_modal::AuthViewVariant,
|
||||
AuthStateProvider,
|
||||
},
|
||||
cloud_object::{
|
||||
model::{
|
||||
persistence::{CloudModel, CloudModelEvent},
|
||||
view::{CloudViewModel, CloudViewModelEvent, UpdateTimestamp},
|
||||
},
|
||||
CloudObject, CloudObjectEventEntrypoint, CloudObjectLocation, CloudObjectSyncStatus,
|
||||
GenericCloudObject, GenericStringObjectFormat, JsonObjectType, NumInFlightRequests,
|
||||
ObjectType, Space,
|
||||
},
|
||||
editor::{EditorView, Event as EditorEvent, SingleLineEditorOptions},
|
||||
env_vars::CloudEnvVarCollection,
|
||||
features::FeatureFlag,
|
||||
menu::{Event, Menu, MenuItem, MenuItemFields},
|
||||
network::NetworkStatus,
|
||||
notebooks::CloudNotebookModel,
|
||||
report_if_error, send_telemetry_from_ctx,
|
||||
server::{
|
||||
cloud_objects::update_manager::{FetchSingleObjectOption, UpdateManager},
|
||||
ids::{ClientId, ObjectUid, ServerId, SyncId},
|
||||
sync_queue::SyncQueue,
|
||||
telemetry::{AnonymousUserSignupEntrypoint, SharingDialogSource, TelemetryEvent},
|
||||
},
|
||||
settings::app_installation_detection::{UserAppInstallDetectionSettings, UserAppInstallStatus},
|
||||
ui_components::{
|
||||
blended_colors,
|
||||
buttons::{highlight, icon_button},
|
||||
icons::{Icon, ICON_DIMENSIONS},
|
||||
menu_button::{icon_button_with_context_menu, MenuDirection},
|
||||
},
|
||||
util::{color::coloru_with_opacity, sync::Condition},
|
||||
view_components::{Dropdown, DropdownItem},
|
||||
workflows::{CloudWorkflow, WorkflowViewMode},
|
||||
workspace::active_terminal_in_window,
|
||||
workspaces::{
|
||||
update_manager::TeamUpdateManager, user_workspaces::UserWorkspaces, workspace::WorkspaceUid,
|
||||
},
|
||||
ObjectActions,
|
||||
};
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{
|
||||
cloud_object_naming_dialog::CloudObjectNamingDialog,
|
||||
drive_helpers::{
|
||||
has_feature_gated_anonymous_user_reached_env_var_limit,
|
||||
has_feature_gated_anonymous_user_reached_notebook_limit,
|
||||
has_feature_gated_anonymous_user_reached_workflow_limit,
|
||||
},
|
||||
empty_trash_confirmation_dialog::{EmptyTrashConfirmationDialog, EmptyTrashConfirmationEvent},
|
||||
folders::CloudFolder,
|
||||
items::{
|
||||
ai_fact_collection::WarpDriveAIFactCollection,
|
||||
item::{tools_panel_menu_direction, ItemStates, WarpDriveRow},
|
||||
mcp_server_collection::WarpDriveMCPServerCollection,
|
||||
WarpDriveItemId,
|
||||
},
|
||||
settings::WarpDriveSettings,
|
||||
sharing::{
|
||||
dialog::{SharingDialog, SharingDialogEvent},
|
||||
ContentEditability, ShareableObject,
|
||||
},
|
||||
CloudObjectTypeAndId, DriveObjectType, DriveSortOrder,
|
||||
};
|
||||
use crate::drive::panel::DrivePanelAction;
|
||||
use crate::server::cloud_objects::update_manager::InitiatedBy;
|
||||
use futures::Future;
|
||||
use galaxy_core::{
|
||||
context_flag::ContextFlag, settings::Setting, ui::theme::color::internal_colors,
|
||||
};
|
||||
use galaxyui::{
|
||||
clipboard::ClipboardContent,
|
||||
elements::{
|
||||
Align, AnchorPair, Border, ChildAnchor, ChildView, ClippedScrollStateHandle,
|
||||
ClippedScrollable, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Dash,
|
||||
DropTarget, DropTargetData, Empty, Flex, Highlight, Hoverable, MainAxisAlignment,
|
||||
MainAxisSize, MouseStateHandle, OffsetPositioning, OffsetType, ParentAnchor, ParentElement,
|
||||
ParentOffsetBounds, PositionedElementAnchor, PositionedElementOffsetBounds,
|
||||
PositioningAxis, Radius, SavePosition, ScrollTarget, ScrollToPositionMode, ScrollbarWidth,
|
||||
Shrinkable, Stack, Text, XAxisAnchor, YAxisAnchor,
|
||||
},
|
||||
fonts::{Properties, Weight},
|
||||
keymap::FixedBinding,
|
||||
platform::{Cursor, OperatingSystem},
|
||||
ui_components::{
|
||||
button::ButtonVariant,
|
||||
components::{Coords, UiComponent, UiComponentStyles},
|
||||
},
|
||||
units::IntoPixels,
|
||||
AppContext, BlurContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView,
|
||||
UpdateView, View, ViewContext, ViewHandle, WindowId,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||
use std::{any::Any, collections::HashMap, sync::Arc};
|
||||
use url::Url;
|
||||
use galaxy_core::context_flag::ContextFlag;
|
||||
use galaxy_core::settings::Setting;
|
||||
use galaxy_core::ui::theme::color::internal_colors;
|
||||
use galaxy_util::sync::Condition;
|
||||
use galaxyui::clipboard::ClipboardContent;
|
||||
use galaxyui::elements::{
|
||||
Align, AnchorPair, Border, ChildAnchor, ChildView, ClippedScrollStateHandle, ClippedScrollable,
|
||||
ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Dash, DropTarget, DropTargetData,
|
||||
Empty, Flex, Highlight, Hoverable, MainAxisAlignment, MainAxisSize, MouseStateHandle,
|
||||
OffsetPositioning, OffsetType, ParentAnchor, ParentElement, ParentOffsetBounds,
|
||||
PositionedElementAnchor, PositionedElementOffsetBounds, PositioningAxis, Radius, SavePosition,
|
||||
ScrollTarget, ScrollToPositionMode, ScrollbarWidth, Shrinkable, Stack, Text, XAxisAnchor,
|
||||
YAxisAnchor,
|
||||
};
|
||||
use galaxyui::fonts::{Properties, Weight};
|
||||
use galaxyui::keymap::FixedBinding;
|
||||
use galaxyui::platform::{Cursor, OperatingSystem};
|
||||
use galaxyui::ui_components::button::ButtonVariant;
|
||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
use galaxyui::units::IntoPixels;
|
||||
use galaxyui::{
|
||||
AppContext, BlurContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView,
|
||||
UpdateView, View, ViewContext, ViewHandle, WindowId,
|
||||
};
|
||||
use std::{any::Any, collections::HashMap, sync::Arc};
|
||||
|
||||
use super::cloud_object_naming_dialog::CloudObjectNamingDialog;
|
||||
use super::drive_helpers::{
|
||||
has_feature_gated_anonymous_user_reached_env_var_limit,
|
||||
has_feature_gated_anonymous_user_reached_notebook_limit,
|
||||
has_feature_gated_anonymous_user_reached_workflow_limit,
|
||||
};
|
||||
use super::empty_trash_confirmation_dialog::{
|
||||
EmptyTrashConfirmationDialog, EmptyTrashConfirmationEvent,
|
||||
};
|
||||
use super::folders::CloudFolder;
|
||||
use super::items::ai_fact_collection::WarpDriveAIFactCollection;
|
||||
use super::items::item::{tools_panel_menu_direction, ItemStates, WarpDriveRow};
|
||||
use super::items::mcp_server_collection::WarpDriveMCPServerCollection;
|
||||
use super::items::WarpDriveItemId;
|
||||
use super::settings::WarpDriveSettings;
|
||||
use super::sharing::dialog::{SharingDialog, SharingDialogEvent};
|
||||
use super::sharing::{ContentEditability, ShareableObject};
|
||||
use super::{CloudObjectTypeAndId, DriveObjectType, DriveSortOrder};
|
||||
use crate::ai::document::ai_document_model::AIDocumentId;
|
||||
use crate::ai::facts::{AIFact, AIMemory};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::auth::auth_manager::{AuthManager, LoginGatedFeature};
|
||||
use crate::auth::auth_state::AuthState;
|
||||
use crate::auth::auth_view_modal::AuthViewVariant;
|
||||
use crate::auth::AuthStateProvider;
|
||||
use crate::cloud_object::model::persistence::{CloudModel, CloudModelEvent};
|
||||
use crate::cloud_object::model::view::{CloudViewModel, CloudViewModelEvent, UpdateTimestamp};
|
||||
use crate::cloud_object::{
|
||||
CloudObject, CloudObjectEventEntrypoint, CloudObjectLocation, CloudObjectSyncStatus,
|
||||
GenericCloudObject, GenericStringObjectFormat, JsonObjectType, NumInFlightRequests, ObjectType,
|
||||
Space,
|
||||
};
|
||||
use crate::drive::panel::DrivePanelAction;
|
||||
use crate::editor::{EditorView, Event as EditorEvent, SingleLineEditorOptions};
|
||||
use crate::env_vars::CloudEnvVarCollection;
|
||||
use crate::features::FeatureFlag;
|
||||
use crate::menu::{Event, Menu, MenuItem, MenuItemFields};
|
||||
use crate::network::NetworkStatus;
|
||||
use crate::notebooks::CloudNotebookModel;
|
||||
use crate::server::cloud_objects::update_manager::{
|
||||
FetchSingleObjectOption, InitiatedBy, UpdateManager,
|
||||
};
|
||||
use crate::server::ids::{ClientId, ObjectUid, ServerId, SyncId};
|
||||
use crate::server::sync_queue::SyncQueue;
|
||||
use crate::server::telemetry::{
|
||||
AnonymousUserSignupEntrypoint, SharingDialogSource, TelemetryEvent,
|
||||
};
|
||||
use crate::settings::app_installation_detection::{
|
||||
UserAppInstallDetectionSettings, UserAppInstallStatus,
|
||||
};
|
||||
use crate::ui_components::blended_colors;
|
||||
use crate::ui_components::buttons::{highlight, icon_button};
|
||||
use crate::ui_components::icons::{Icon, ICON_DIMENSIONS};
|
||||
use crate::ui_components::menu_button::{icon_button_with_context_menu, MenuDirection};
|
||||
#[cfg(target_family = "wasm")]
|
||||
use crate::uri::web_intent_parser::open_url_on_desktop;
|
||||
use crate::util::color::coloru_with_opacity;
|
||||
use crate::view_components::{Dropdown, DropdownItem};
|
||||
use crate::workflows::{CloudWorkflow, WorkflowViewMode};
|
||||
use crate::workspace::active_terminal_in_window;
|
||||
use crate::workspaces::update_manager::TeamUpdateManager;
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
use crate::workspaces::workspace::WorkspaceUid;
|
||||
use crate::{report_if_error, send_telemetry_from_ctx, ObjectActions};
|
||||
|
||||
const WARP_DRIVE_TITLE: &str = "Galaxy Drive";
|
||||
|
||||
@@ -242,7 +233,7 @@ pub enum DriveIndexSection {
|
||||
JoinTeam,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum DriveIndexAction {
|
||||
OpenObject(CloudObjectTypeAndId),
|
||||
OpenWorkflowInPane {
|
||||
@@ -415,7 +406,6 @@ impl DriveIndexAction {
|
||||
|
||||
impl From<&DriveIndexAction> for LoginGatedFeature {
|
||||
fn from(val: &DriveIndexAction) -> LoginGatedFeature {
|
||||
use DriveIndexAction::*;
|
||||
match val {
|
||||
OpenTeamSettingsPage => "Open Team Settings",
|
||||
ViewPlans { .. } => "View Plans",
|
||||
@@ -5659,5 +5649,5 @@ impl TypedActionView for DriveIndex {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "index_test.rs"]
|
||||
#[path = "index_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,38 +1,37 @@
|
||||
use cloud_objects::cloud_object::ServerPermissions;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_server_client::cloud_object::ServerPermissions;
|
||||
use galaxyui::{
|
||||
platform::WindowStyle, AddSingletonModel, App, SingletonEntity, TypedActionView, ViewHandle,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ai::blocklist::BlocklistAIHistoryModel,
|
||||
auth::{auth_manager::AuthManager, AuthStateProvider},
|
||||
cloud_object::{
|
||||
model::{actions::ObjectActions, persistence::CloudModel, view::CloudViewModel},
|
||||
CloudObjectSyncStatus, ObjectIdType, ObjectType, Owner, ServerCreationInfo, Space,
|
||||
},
|
||||
drive::{items::WarpDriveItemId, CloudObjectTypeAndId},
|
||||
menu::MenuItem,
|
||||
network::NetworkStatus,
|
||||
notebooks::{CloudNotebook, CloudNotebookModel},
|
||||
server::{
|
||||
cloud_objects::update_manager::UpdateManager,
|
||||
ids::{ClientId, ServerIdAndType, SyncId},
|
||||
server_api::ServerApiProvider,
|
||||
sync_queue::{QueueItem, SyncQueue},
|
||||
telemetry::context_provider::AppTelemetryContextProvider,
|
||||
},
|
||||
settings_view::keybindings::KeybindingChangedNotifier,
|
||||
terminal::shared_session::permissions_manager::SessionPermissionsManager,
|
||||
test_util::settings::initialize_settings_for_tests,
|
||||
workflows::{workflow::Workflow, CloudWorkflow, CloudWorkflowModel},
|
||||
workspaces::{
|
||||
team_tester::TeamTesterStatus, user_profiles::UserProfiles, user_workspaces::UserWorkspaces,
|
||||
},
|
||||
Assets,
|
||||
};
|
||||
use galaxyui::platform::WindowStyle;
|
||||
use galaxyui::{AddSingletonModel, App, SingletonEntity, TypedActionView, ViewHandle};
|
||||
|
||||
use super::{DriveIndex, DriveIndexAction};
|
||||
use crate::ai::blocklist::BlocklistAIHistoryModel;
|
||||
use crate::auth::auth_manager::AuthManager;
|
||||
use crate::auth::AuthStateProvider;
|
||||
use crate::cloud_object::model::actions::ObjectActions;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::model::view::CloudViewModel;
|
||||
use crate::cloud_object::{
|
||||
CloudObjectSyncStatus, ObjectIdType, ObjectType, Owner, ServerCreationInfo, Space,
|
||||
};
|
||||
use crate::drive::items::WarpDriveItemId;
|
||||
use crate::drive::CloudObjectTypeAndId;
|
||||
use crate::menu::MenuItem;
|
||||
use crate::network::NetworkStatus;
|
||||
use crate::notebooks::{CloudNotebook, CloudNotebookModel};
|
||||
use crate::server::cloud_objects::update_manager::UpdateManager;
|
||||
use crate::server::ids::{ClientId, ServerIdAndType, SyncId};
|
||||
use crate::server::server_api::ServerApiProvider;
|
||||
use crate::server::sync_queue::{QueueItem, SyncQueue};
|
||||
use crate::server::telemetry::context_provider::AppTelemetryContextProvider;
|
||||
use crate::settings_view::keybindings::KeybindingChangedNotifier;
|
||||
use crate::terminal::shared_session::permissions_manager::SessionPermissionsManager;
|
||||
use crate::test_util::settings::initialize_settings_for_tests;
|
||||
use crate::workflows::workflow::Workflow;
|
||||
use crate::workflows::{CloudWorkflow, CloudWorkflowModel};
|
||||
use crate::workspaces::team_tester::TeamTesterStatus;
|
||||
use crate::workspaces::user_profiles::UserProfiles;
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
use crate::ASSETS;
|
||||
|
||||
fn initialize_app(app: &mut App) {
|
||||
initialize_settings_for_tests(app);
|
||||
@@ -121,7 +120,7 @@ fn label_for_menu_item(item: &MenuItem<DriveIndexAction>) -> &str {
|
||||
|
||||
#[test]
|
||||
fn test_retry_menu_item_visibility() {
|
||||
App::test(Assets, |mut app| async move {
|
||||
App::test(ASSETS, |mut app| async move {
|
||||
initialize_app(&mut app);
|
||||
let index = create_index(&mut app);
|
||||
let sync_id = create_workflow(&mut app);
|
||||
@@ -171,7 +170,7 @@ fn test_retry_menu_item_visibility() {
|
||||
|
||||
#[test]
|
||||
fn test_retry_menu_item_logic() {
|
||||
App::test(Assets, |mut app| async move {
|
||||
App::test(ASSETS, |mut app| async move {
|
||||
initialize_app(&mut app);
|
||||
let index = create_index(&mut app);
|
||||
let sync_id = create_workflow(&mut app);
|
||||
@@ -1,19 +1,15 @@
|
||||
use galaxyui::{
|
||||
elements::{Container, Flex, MouseStateHandle, ParentElement},
|
||||
fonts::Weight,
|
||||
ui_components::components::{UiComponent, UiComponentStyles},
|
||||
AppContext, Element,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ai::facts::{AIFact, AIMemory, CloudAIFact},
|
||||
appearance::Appearance,
|
||||
cloud_object::CloudObjectMetadata,
|
||||
drive::{index::DriveIndexAction, CloudObjectTypeAndId, DriveObjectType},
|
||||
themes::theme::Fill,
|
||||
};
|
||||
use galaxyui::elements::{Container, Flex, MouseStateHandle, ParentElement};
|
||||
use galaxyui::fonts::Weight;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::{AppContext, Element};
|
||||
|
||||
use super::{WarpDriveItem, WarpDriveItemId};
|
||||
use crate::ai::facts::{AIFact, AIMemory, CloudAIFact};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::CloudObjectMetadata;
|
||||
use crate::drive::index::DriveIndexAction;
|
||||
use crate::drive::{CloudObjectTypeAndId, DriveObjectType};
|
||||
use crate::themes::theme::Fill;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WarpDriveAIFact {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use galaxyui::{elements::MouseStateHandle, AppContext, Element};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::CloudObjectMetadata,
|
||||
drive::{index::DriveIndexAction, DriveObjectType},
|
||||
server::ids::ClientId,
|
||||
themes::theme::Fill,
|
||||
};
|
||||
use galaxyui::elements::MouseStateHandle;
|
||||
use galaxyui::{AppContext, Element};
|
||||
|
||||
use super::{WarpDriveItem, WarpDriveItemId};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::CloudObjectMetadata;
|
||||
use crate::drive::index::DriveIndexAction;
|
||||
use crate::drive::DriveObjectType;
|
||||
use crate::server::ids::ClientId;
|
||||
use crate::themes::theme::Fill;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WarpDriveAIFactCollection {
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
use galaxy_core::context_flag::ContextFlag;
|
||||
use galaxyui::{
|
||||
elements::{Clipped, Container, Flex, MouseStateHandle, ParentElement},
|
||||
fonts::Weight,
|
||||
ui_components::components::{UiComponent, UiComponentStyles},
|
||||
AppContext, Element, SingletonEntity,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::{
|
||||
model::actions::{ObjectActionType, ObjectActions},
|
||||
CloudObjectMetadata,
|
||||
},
|
||||
drive::{index::DriveIndexAction, CloudObjectTypeAndId, DriveObjectType},
|
||||
env_vars::{CloudEnvVarCollection, EnvVarValue},
|
||||
themes::theme::Fill,
|
||||
};
|
||||
use galaxy_core::context_flag::ContextFlag;
|
||||
use galaxyui::elements::{Clipped, Container, Flex, MouseStateHandle, ParentElement};
|
||||
use galaxyui::fonts::Weight;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::{AppContext, Element, SingletonEntity};
|
||||
|
||||
use super::{WarpDriveItem, WarpDriveItemId};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::model::actions::{ObjectActionType, ObjectActions};
|
||||
use crate::cloud_object::CloudObjectMetadata;
|
||||
use crate::drive::index::DriveIndexAction;
|
||||
use crate::drive::{CloudObjectTypeAndId, DriveObjectType};
|
||||
use crate::env_vars::{CloudEnvVarCollection, EnvVarValue};
|
||||
use crate::themes::theme::Fill;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WarpDriveEnvVarCollection {
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxyui::{elements::MouseStateHandle, AppContext, Element};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::CloudObjectMetadata,
|
||||
drive::{
|
||||
cloud_object_styling::warp_drive_icon_color, folders::CloudFolder, index::DriveIndexAction,
|
||||
CloudObjectTypeAndId, DriveObjectType,
|
||||
},
|
||||
themes::theme::Fill,
|
||||
ui_components::icons::Icon,
|
||||
};
|
||||
use galaxyui::elements::MouseStateHandle;
|
||||
use galaxyui::{AppContext, Element};
|
||||
|
||||
use super::{WarpDriveItem, WarpDriveItemId};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::CloudObjectMetadata;
|
||||
use crate::drive::cloud_object_styling::warp_drive_icon_color;
|
||||
use crate::drive::folders::CloudFolder;
|
||||
use crate::drive::index::DriveIndexAction;
|
||||
use crate::drive::{CloudObjectTypeAndId, DriveObjectType};
|
||||
use crate::themes::theme::Fill;
|
||||
use crate::ui_components::icons::Icon;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WarpDriveFolder {
|
||||
|
||||
+39
-53
@@ -1,57 +1,43 @@
|
||||
use galaxyui::{
|
||||
elements::{
|
||||
AcceptedByDropTarget, Border, ChildAnchor, ConstrainedBox, Container, CornerRadius,
|
||||
CrossAxisAlignment, Draggable, DraggableState, DropShadow, Empty, Flex, Hoverable,
|
||||
MainAxisSize, MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement,
|
||||
ParentOffsetBounds, Radius, SavePosition, Shrinkable, SizeConstraintCondition,
|
||||
SizeConstraintSwitch, Stack,
|
||||
},
|
||||
fonts::Weight,
|
||||
platform::Cursor,
|
||||
presenter::PositionCache,
|
||||
ui_components::{
|
||||
components::{UiComponent, UiComponentStyles},
|
||||
text::Span,
|
||||
},
|
||||
AppContext, Element, SingletonEntity, ViewHandle,
|
||||
use pathfinder_geometry::rect::RectF;
|
||||
use pathfinder_geometry::vector::Vector2F;
|
||||
use galaxyui::elements::{
|
||||
AcceptedByDropTarget, Border, ChildAnchor, ConstrainedBox, Container, CornerRadius,
|
||||
CrossAxisAlignment, Draggable, DraggableState, DropShadow, Empty, Flex, Hoverable,
|
||||
MainAxisSize, MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement,
|
||||
ParentOffsetBounds, Radius, SavePosition, Shrinkable, SizeConstraintCondition,
|
||||
SizeConstraintSwitch, Stack,
|
||||
};
|
||||
use pathfinder_geometry::{rect::RectF, vector::Vector2F};
|
||||
|
||||
use crate::{
|
||||
cloud_object::{
|
||||
model::{persistence::CloudModel, view::CloudViewModel},
|
||||
CloudObject, CloudObjectMetadataExt, Owner,
|
||||
},
|
||||
drive::CloudObjectTypeAndId,
|
||||
workspaces::{user_profiles::UserProfiles, user_workspaces::UserWorkspaces},
|
||||
};
|
||||
|
||||
use crate::workspace::header_toolbar_item::HeaderToolbarItemKind;
|
||||
use crate::workspace::tab_settings::TabSettings;
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::Space,
|
||||
drive::{
|
||||
index::{
|
||||
DriveIndexAction, AUTOSCROLL_DETECTION_DISTANCE, AUTOSCROLL_SPEED_MULTIPLIER,
|
||||
DRIVE_INDEX_VIEW_POSITION_ID, FOLDER_DEPTH_INDENT, INDEX_CONTENT_MARGIN_LEFT,
|
||||
ITEM_FONT_SIZE, ITEM_MARGIN_BOTTOM, ITEM_PADDING_HORIZONTAL, ITEM_PADDING_VERTICAL,
|
||||
},
|
||||
panel::WARP_DRIVE_POSITION_ID,
|
||||
},
|
||||
menu::Menu,
|
||||
ui_components::{
|
||||
blended_colors,
|
||||
icons::{Icon, ICON_DIMENSIONS},
|
||||
menu_button::{
|
||||
highlight_icon_button_with_context_menu_drive, icon_button_with_context_menu_drive,
|
||||
MenuDirection,
|
||||
},
|
||||
},
|
||||
};
|
||||
use crate::{cloud_object::CloudObjectLocation, drive::items::WarpDriveItem};
|
||||
use galaxyui::fonts::Weight;
|
||||
use galaxyui::platform::Cursor;
|
||||
use galaxyui::presenter::PositionCache;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::ui_components::text::Span;
|
||||
use galaxyui::{AppContext, Element, SingletonEntity, ViewHandle};
|
||||
|
||||
use super::WarpDriveItemId;
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::model::view::CloudViewModel;
|
||||
use crate::cloud_object::{CloudObject, CloudObjectLocation, CloudObjectMetadataExt, Owner, Space};
|
||||
use crate::drive::index::{
|
||||
DriveIndexAction, AUTOSCROLL_DETECTION_DISTANCE, AUTOSCROLL_SPEED_MULTIPLIER,
|
||||
DRIVE_INDEX_VIEW_POSITION_ID, FOLDER_DEPTH_INDENT, INDEX_CONTENT_MARGIN_LEFT, ITEM_FONT_SIZE,
|
||||
ITEM_MARGIN_BOTTOM, ITEM_PADDING_HORIZONTAL, ITEM_PADDING_VERTICAL,
|
||||
};
|
||||
use crate::drive::items::WarpDriveItem;
|
||||
use crate::drive::panel::WARP_DRIVE_POSITION_ID;
|
||||
use crate::drive::CloudObjectTypeAndId;
|
||||
use crate::menu::Menu;
|
||||
use crate::ui_components::blended_colors;
|
||||
use crate::ui_components::icons::{Icon, ICON_DIMENSIONS};
|
||||
use crate::ui_components::menu_button::{
|
||||
highlight_icon_button_with_context_menu_drive, icon_button_with_context_menu_drive,
|
||||
MenuDirection,
|
||||
};
|
||||
use crate::workspace::header_toolbar_item::HeaderToolbarItemKind;
|
||||
use crate::workspace::tab_settings::TabSettings;
|
||||
use crate::workspaces::user_profiles::UserProfiles;
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
|
||||
pub(crate) fn tools_panel_menu_direction(app: &AppContext) -> MenuDirection {
|
||||
let config = TabSettings::as_ref(app)
|
||||
@@ -134,7 +120,7 @@ pub struct WarpDriveRow<'a> {
|
||||
space: Space,
|
||||
item_states: ItemStates,
|
||||
overflow_button: Box<dyn Element>,
|
||||
/// how many levels into a folder hierachy the row is.
|
||||
/// how many levels into a folder hierarchy the row is.
|
||||
/// 0 means the object is in the root directory.
|
||||
folder_depth: usize,
|
||||
sync_icon: Option<Box<dyn Element>>,
|
||||
@@ -898,7 +884,7 @@ impl UiComponent for WarpDriveRow<'_> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwize, check to see if we should scroll downwards (revealing more content at the
|
||||
// Otherwise, check to see if we should scroll downwards (revealing more content at the
|
||||
// bottom).
|
||||
// This computes the distance between the bottom of the *currently-dragging* item
|
||||
// and the bottom of the drive index view. If distance < 10, emit a scroll event.
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use warpui::elements::MouseStateHandle;
|
||||
use warpui::{AppContext, Element};
|
||||
|
||||
use super::{WarpDriveItem, WarpDriveItemId};
|
||||
use crate::{
|
||||
ai::mcp::CloudMCPServer,
|
||||
appearance::Appearance,
|
||||
cloud_object::CloudObjectMetadata,
|
||||
drive::{index::DriveIndexAction, CloudObjectTypeAndId, DriveObjectType},
|
||||
themes::theme::Fill,
|
||||
};
|
||||
use galaxyui::{elements::MouseStateHandle, AppContext, Element};
|
||||
use crate::ai::mcp::CloudMCPServer;
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::CloudObjectMetadata;
|
||||
use crate::drive::index::DriveIndexAction;
|
||||
use crate::drive::{CloudObjectTypeAndId, DriveObjectType};
|
||||
use crate::themes::theme::Fill;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WarpDriveMCPServer {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use galaxyui::{elements::MouseStateHandle, AppContext, Element};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::CloudObjectMetadata,
|
||||
drive::{index::DriveIndexAction, DriveObjectType},
|
||||
server::ids::ClientId,
|
||||
themes::theme::Fill,
|
||||
};
|
||||
use galaxyui::elements::MouseStateHandle;
|
||||
use galaxyui::{AppContext, Element};
|
||||
|
||||
use super::{WarpDriveItem, WarpDriveItemId};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::CloudObjectMetadata;
|
||||
use crate::drive::index::DriveIndexAction;
|
||||
use crate::drive::DriveObjectType;
|
||||
use crate::server::ids::ClientId;
|
||||
use crate::themes::theme::Fill;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WarpDriveMCPServerCollection {
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
use galaxyui::{elements::MouseStateHandle, AppContext, Element};
|
||||
use galaxyui::elements::MouseStateHandle;
|
||||
use galaxyui::{AppContext, Element};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::{CloudObjectMetadata, Space},
|
||||
themes::theme::Fill,
|
||||
ui_components::icons::Icon,
|
||||
};
|
||||
|
||||
use super::{
|
||||
cloud_object_styling::warp_drive_icon_color,
|
||||
index::{warp_drive_section_header_position_id, DriveIndexAction, DriveIndexSection},
|
||||
CloudObjectTypeAndId, DriveObjectType,
|
||||
};
|
||||
use super::cloud_object_styling::warp_drive_icon_color;
|
||||
use super::index::{warp_drive_section_header_position_id, DriveIndexAction, DriveIndexSection};
|
||||
use super::{CloudObjectTypeAndId, DriveObjectType};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::{CloudObjectMetadata, Space};
|
||||
use crate::themes::theme::Fill;
|
||||
use crate::ui_components::icons::Icon;
|
||||
|
||||
pub mod ai_fact;
|
||||
pub mod ai_fact_collection;
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
use galaxyui::{
|
||||
elements::{Flex, MouseStateHandle, ParentElement},
|
||||
fonts::Weight,
|
||||
ui_components::components::{UiComponent, UiComponentStyles},
|
||||
AppContext, Element,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::CloudObjectMetadata,
|
||||
drive::{index::DriveIndexAction, CloudObjectTypeAndId, DriveObjectType},
|
||||
notebooks::CloudNotebook,
|
||||
themes::theme::Fill,
|
||||
};
|
||||
use galaxyui::elements::{Flex, MouseStateHandle, ParentElement};
|
||||
use galaxyui::fonts::Weight;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::{AppContext, Element};
|
||||
|
||||
use super::{WarpDriveItem, WarpDriveItemId};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::CloudObjectMetadata;
|
||||
use crate::drive::index::DriveIndexAction;
|
||||
use crate::drive::{CloudObjectTypeAndId, DriveObjectType};
|
||||
use crate::notebooks::CloudNotebook;
|
||||
use crate::themes::theme::Fill;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WarpDriveNotebook {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use galaxyui::{elements::MouseStateHandle, Element};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::{CloudObjectMetadata, Space},
|
||||
drive::{index::DriveIndexAction, DriveObjectType},
|
||||
themes::theme::Fill,
|
||||
};
|
||||
use galaxyui::elements::MouseStateHandle;
|
||||
use galaxyui::Element;
|
||||
|
||||
use super::{WarpDriveItem, WarpDriveItemId};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::{CloudObjectMetadata, Space};
|
||||
use crate::drive::index::DriveIndexAction;
|
||||
use crate::drive::DriveObjectType;
|
||||
use crate::themes::theme::Fill;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WarpDriveSpace {
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
use galaxy_core::context_flag::ContextFlag;
|
||||
use galaxyui::{
|
||||
elements::{Container, Flex, MouseStateHandle, ParentElement},
|
||||
fonts::Weight,
|
||||
ui_components::components::{UiComponent, UiComponentStyles},
|
||||
AppContext, Element, SingletonEntity,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::{
|
||||
model::actions::{ObjectActionType, ObjectActions},
|
||||
CloudObjectMetadata,
|
||||
},
|
||||
drive::{index::DriveIndexAction, CloudObjectTypeAndId, DriveObjectType},
|
||||
themes::theme::Fill,
|
||||
workflows::{CloudWorkflow, WorkflowViewMode},
|
||||
};
|
||||
use galaxyui::elements::{Container, Flex, MouseStateHandle, ParentElement};
|
||||
use galaxyui::fonts::Weight;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::{AppContext, Element, SingletonEntity};
|
||||
|
||||
use super::{WarpDriveItem, WarpDriveItemId};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::model::actions::{ObjectActionType, ObjectActions};
|
||||
use crate::cloud_object::CloudObjectMetadata;
|
||||
use crate::drive::index::DriveIndexAction;
|
||||
use crate::drive::{CloudObjectTypeAndId, DriveObjectType};
|
||||
use crate::themes::theme::Fill;
|
||||
use crate::workflows::{CloudWorkflow, WorkflowViewMode};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WarpDriveWorkflow {
|
||||
|
||||
+24
-161
@@ -13,27 +13,38 @@ pub mod settings;
|
||||
pub mod sharing;
|
||||
pub mod workflows;
|
||||
|
||||
use std::{cmp::Ordering, fmt};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
|
||||
use galaxy_core::user_preferences::GetUserPreferences as _;
|
||||
use galaxyui::AppContext;
|
||||
pub use cloud_objects::drive::CloudObjectTypeAndId;
|
||||
pub use index::DriveIndexVariant;
|
||||
pub use panel::{DrivePanel, DrivePanelEvent};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
cloud_object::{
|
||||
model::view::{CloudViewModel, UpdateTimestamp},
|
||||
CloudObject, GenericStringObjectFormat, ObjectIdType, ObjectType,
|
||||
},
|
||||
server::ids::{HashedSqliteId, ObjectUid, ServerId, SyncId},
|
||||
ui_components::icons::Icon,
|
||||
workflows::CloudWorkflow,
|
||||
};
|
||||
use crate::cloud_object::model::view::{CloudViewModel, UpdateTimestamp};
|
||||
use crate::cloud_object::{CloudObject, ObjectType};
|
||||
use crate::server::ids::ServerId;
|
||||
use crate::ui_components::icons::Icon;
|
||||
use crate::workflows::CloudWorkflow;
|
||||
|
||||
type SortByComparator<'a> = dyn FnMut(&&dyn CloudObject, &&dyn CloudObject) -> Ordering + 'a;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct OpenWarpDriveObjectSettings {
|
||||
/// The folder that should be focused in the Warp Drive when the object is opened.
|
||||
pub focused_folder_id: Option<ServerId>,
|
||||
/// The email of the user to invite to the object, if the object is being opened via the request access flow.
|
||||
pub invitee_email: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct OpenWarpDriveObjectArgs {
|
||||
pub object_type: ObjectType,
|
||||
pub server_id: ServerId,
|
||||
pub settings: OpenWarpDriveObjectSettings,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum DriveObjectType {
|
||||
Workflow,
|
||||
AgentModeWorkflow,
|
||||
@@ -87,154 +98,6 @@ impl fmt::Display for DriveObjectType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct OpenGalaxyDriveObjectSettings {
|
||||
/// The folder that should be focused in the Warp Drive when the object is opened.
|
||||
pub focused_folder_id: Option<ServerId>,
|
||||
/// The email of the user to invite to the object, if the object is being opened via the request access flow.
|
||||
pub invitee_email: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct OpenGalaxyDriveObjectArgs {
|
||||
pub object_type: ObjectType,
|
||||
pub server_id: ServerId,
|
||||
pub settings: OpenGalaxyDriveObjectSettings,
|
||||
}
|
||||
|
||||
/// Enum to use to pass down type and id between actions to avoid multiplying actions whenever we
|
||||
/// need to pass the object id etc.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum CloudObjectTypeAndId {
|
||||
Notebook(SyncId),
|
||||
Workflow(SyncId),
|
||||
Folder(SyncId),
|
||||
GenericStringObject {
|
||||
object_type: GenericStringObjectFormat,
|
||||
id: SyncId,
|
||||
},
|
||||
}
|
||||
|
||||
impl CloudObjectTypeAndId {
|
||||
pub fn from_id_and_type(id: SyncId, object_type: ObjectType) -> Self {
|
||||
match object_type {
|
||||
ObjectType::Notebook => Self::Notebook(id),
|
||||
ObjectType::Workflow => Self::Workflow(id),
|
||||
ObjectType::Folder => Self::Folder(id),
|
||||
ObjectType::GenericStringObject(format) => Self::GenericStringObject {
|
||||
object_type: format,
|
||||
id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uid(self) -> ObjectUid {
|
||||
match self {
|
||||
Self::Notebook(id) => id.uid(),
|
||||
Self::Workflow(id) => id.uid(),
|
||||
Self::Folder(id) => id.uid(),
|
||||
Self::GenericStringObject { id, .. } => id.uid(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sync_id(self) -> SyncId {
|
||||
match self {
|
||||
Self::Notebook(id)
|
||||
| Self::Workflow(id)
|
||||
| Self::Folder(id)
|
||||
| Self::GenericStringObject { id, .. } => id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sqlite_uid_hash(self) -> HashedSqliteId {
|
||||
match self {
|
||||
CloudObjectTypeAndId::Notebook(id) => id.sqlite_uid_hash(ObjectIdType::Notebook),
|
||||
CloudObjectTypeAndId::Workflow(id) => id.sqlite_uid_hash(ObjectIdType::Workflow),
|
||||
CloudObjectTypeAndId::Folder(id) => id.sqlite_uid_hash(ObjectIdType::Folder),
|
||||
CloudObjectTypeAndId::GenericStringObject { object_type: _, id } => {
|
||||
id.sqlite_uid_hash(ObjectIdType::GenericStringObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn object_id_type(&self) -> ObjectIdType {
|
||||
match self {
|
||||
CloudObjectTypeAndId::Notebook(_) => ObjectIdType::Notebook,
|
||||
CloudObjectTypeAndId::Workflow(_) => ObjectIdType::Workflow,
|
||||
CloudObjectTypeAndId::GenericStringObject { .. } => ObjectIdType::GenericStringObject,
|
||||
CloudObjectTypeAndId::Folder(_) => ObjectIdType::Folder,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn object_type(&self) -> ObjectType {
|
||||
match self {
|
||||
CloudObjectTypeAndId::Notebook(_) => ObjectType::Notebook,
|
||||
CloudObjectTypeAndId::Workflow(_) => ObjectType::Workflow,
|
||||
CloudObjectTypeAndId::Folder(_) => ObjectType::Folder,
|
||||
CloudObjectTypeAndId::GenericStringObject { object_type, .. } => {
|
||||
ObjectType::GenericStringObject(*object_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_folder_id(self) -> Option<SyncId> {
|
||||
match self {
|
||||
CloudObjectTypeAndId::Notebook(_) => None,
|
||||
CloudObjectTypeAndId::Workflow(_) => None,
|
||||
CloudObjectTypeAndId::GenericStringObject { .. } => None,
|
||||
CloudObjectTypeAndId::Folder(f) => Some(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_notebook_id(self) -> Option<SyncId> {
|
||||
match self {
|
||||
CloudObjectTypeAndId::Notebook(id) => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_generic_string_object_id(self) -> Option<SyncId> {
|
||||
match self {
|
||||
CloudObjectTypeAndId::GenericStringObject { object_type: _, id } => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_server_id(self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
CloudObjectTypeAndId::Notebook(SyncId::ServerId(_))
|
||||
| CloudObjectTypeAndId::Workflow(SyncId::ServerId(_))
|
||||
| CloudObjectTypeAndId::Folder(SyncId::ServerId(_))
|
||||
| CloudObjectTypeAndId::GenericStringObject {
|
||||
id: SyncId::ServerId(_),
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub fn server_id(self) -> Option<ServerId> {
|
||||
match self {
|
||||
CloudObjectTypeAndId::Notebook(SyncId::ServerId(notebook_id)) => Some(notebook_id),
|
||||
CloudObjectTypeAndId::Workflow(SyncId::ServerId(workflow_id)) => Some(workflow_id),
|
||||
CloudObjectTypeAndId::Folder(SyncId::ServerId(folder_id)) => Some(folder_id),
|
||||
CloudObjectTypeAndId::GenericStringObject {
|
||||
id: SyncId::ServerId(json_object_id),
|
||||
..
|
||||
} => Some(json_object_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drive_row_position_id(self) -> String {
|
||||
format!("WarpDriveRow_{}", self.uid())
|
||||
}
|
||||
|
||||
pub fn from_generic_string_object(object_type: GenericStringObjectFormat, id: SyncId) -> Self {
|
||||
Self::GenericStringObject { object_type, id }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn should_auto_open_welcome_folder(app: &mut AppContext) -> bool {
|
||||
app.private_user_preferences()
|
||||
.read_value(settings::HAS_AUTO_OPENED_WELCOME_FOLDER)
|
||||
|
||||
+30
-30
@@ -1,39 +1,39 @@
|
||||
use futures::Future;
|
||||
use galaxyui::elements::{
|
||||
Align, Flex, Hoverable, MouseStateHandle, ParentElement, SavePosition, Shrinkable,
|
||||
};
|
||||
use galaxyui::presenter::ChildView;
|
||||
use galaxyui::windowing::{StateEvent, WindowManager};
|
||||
use galaxyui::{
|
||||
elements::{Align, Flex, Hoverable, MouseStateHandle, ParentElement, SavePosition, Shrinkable},
|
||||
presenter::ChildView,
|
||||
windowing::{StateEvent, WindowManager},
|
||||
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
ViewHandle,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ai::{document::ai_document_model::AIDocumentId, facts::CloudAIFactModel},
|
||||
cloud_object::{
|
||||
model::{persistence::CloudModel, view::CloudViewModel},
|
||||
CloudObjectEventEntrypoint, GenericStringObjectFormat, JsonObjectType, Owner, Space,
|
||||
},
|
||||
env_vars::{manager::EnvVarCollectionSource, CloudEnvVarCollection},
|
||||
notebooks::{manager::NotebookSource, CloudNotebook},
|
||||
server::{
|
||||
cloud_objects::update_manager::{InitiatedBy, UpdateManager},
|
||||
ids::{ClientId, ServerId, SyncId},
|
||||
telemetry::SharingDialogSource,
|
||||
},
|
||||
workflows::{manager::WorkflowOpenSource, CloudWorkflow, WorkflowViewMode},
|
||||
workspaces::user_workspaces::UserWorkspaces,
|
||||
use super::drive_helpers::{
|
||||
has_feature_gated_anonymous_user_reached_env_var_limit,
|
||||
has_feature_gated_anonymous_user_reached_notebook_limit,
|
||||
has_feature_gated_anonymous_user_reached_workflow_limit,
|
||||
};
|
||||
|
||||
use super::{
|
||||
drive_helpers::{
|
||||
has_feature_gated_anonymous_user_reached_env_var_limit,
|
||||
has_feature_gated_anonymous_user_reached_notebook_limit,
|
||||
has_feature_gated_anonymous_user_reached_workflow_limit,
|
||||
},
|
||||
index::{DriveIndex, DriveIndexAction, DriveIndexEvent},
|
||||
items::WarpDriveItemId,
|
||||
CloudObjectTypeAndId, DriveObjectType,
|
||||
use super::index::{DriveIndex, DriveIndexAction, DriveIndexEvent};
|
||||
use super::items::WarpDriveItemId;
|
||||
use super::{CloudObjectTypeAndId, DriveObjectType};
|
||||
use crate::ai::document::ai_document_model::AIDocumentId;
|
||||
use crate::ai::facts::CloudAIFactModel;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::model::view::CloudViewModel;
|
||||
use crate::cloud_object::{
|
||||
CloudObjectEventEntrypoint, GenericStringObjectFormat, JsonObjectType, Owner, Space,
|
||||
};
|
||||
use crate::env_vars::manager::EnvVarCollectionSource;
|
||||
use crate::env_vars::CloudEnvVarCollection;
|
||||
use crate::notebooks::manager::NotebookSource;
|
||||
use crate::notebooks::CloudNotebook;
|
||||
use crate::server::cloud_objects::update_manager::{InitiatedBy, UpdateManager};
|
||||
use crate::server::ids::{ClientId, ServerId, SyncId};
|
||||
use crate::server::telemetry::SharingDialogSource;
|
||||
use crate::workflows::manager::WorkflowOpenSource;
|
||||
use crate::workflows::{CloudWorkflow, WorkflowViewMode};
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
|
||||
pub const MIN_SIDEBAR_WIDTH: f32 = 250.;
|
||||
pub const MAX_SIDEBAR_WIDTH_RATIO: f32 = 0.75;
|
||||
@@ -583,7 +583,7 @@ impl DrivePanel {
|
||||
ctx.emit(DrivePanelEvent::OpenMCPServerCollection);
|
||||
}
|
||||
|
||||
/// Recomputes and intializes the section states for the WD Index. This is needed after
|
||||
/// Recomputes and initializes the section states for the WD Index. This is needed after
|
||||
/// we directly change anything about the state of the index (such as folders being open/closed).
|
||||
///
|
||||
/// This should only be called if we immeidiately need to update and rely on the updated state.
|
||||
@@ -735,5 +735,5 @@ pub(crate) mod styles {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "panel_test.rs"]
|
||||
#[path = "panel_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxyui::{platform::WindowStyle, App};
|
||||
|
||||
use crate::{
|
||||
ai::blocklist::BlocklistAIHistoryModel,
|
||||
auth::{auth_manager::AuthManager, AuthStateProvider},
|
||||
cloud_object::{
|
||||
model::{persistence::CloudModel, view::CloudViewModel},
|
||||
Space,
|
||||
},
|
||||
drive::index::DriveIndexSection,
|
||||
network::NetworkStatus,
|
||||
server::{
|
||||
cloud_objects::update_manager::UpdateManager, server_api::ServerApiProvider,
|
||||
sync_queue::SyncQueue, telemetry::context_provider::AppTelemetryContextProvider,
|
||||
},
|
||||
settings_view::keybindings::KeybindingChangedNotifier,
|
||||
terminal::{
|
||||
resizable_data::ResizableData,
|
||||
shared_session::permissions_manager::SessionPermissionsManager,
|
||||
},
|
||||
test_util::settings::initialize_settings_for_tests,
|
||||
workspaces::{team_tester::TeamTesterStatus, user_workspaces::UserWorkspaces},
|
||||
Assets, ObjectActions,
|
||||
};
|
||||
use galaxyui::platform::WindowStyle;
|
||||
use galaxyui::App;
|
||||
|
||||
use super::DrivePanel;
|
||||
use crate::ai::blocklist::BlocklistAIHistoryModel;
|
||||
use crate::auth::auth_manager::AuthManager;
|
||||
use crate::auth::AuthStateProvider;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::model::view::CloudViewModel;
|
||||
use crate::cloud_object::Space;
|
||||
use crate::drive::index::DriveIndexSection;
|
||||
use crate::network::NetworkStatus;
|
||||
use crate::server::cloud_objects::update_manager::UpdateManager;
|
||||
use crate::server::server_api::ServerApiProvider;
|
||||
use crate::server::sync_queue::SyncQueue;
|
||||
use crate::server::telemetry::context_provider::AppTelemetryContextProvider;
|
||||
use crate::settings_view::keybindings::KeybindingChangedNotifier;
|
||||
use crate::terminal::resizable_data::ResizableData;
|
||||
use crate::terminal::shared_session::permissions_manager::SessionPermissionsManager;
|
||||
use crate::test_util::settings::initialize_settings_for_tests;
|
||||
use crate::workspaces::team_tester::TeamTesterStatus;
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
use crate::{ObjectActions, ASSETS};
|
||||
|
||||
fn initialize_app(app: &mut App) {
|
||||
initialize_settings_for_tests(app);
|
||||
@@ -52,7 +49,7 @@ fn initialize_app(app: &mut App) {
|
||||
|
||||
#[test]
|
||||
fn test_warp_drive_sections_with_no_team() {
|
||||
App::test(Assets, |mut app| async move {
|
||||
App::test(ASSETS, |mut app| async move {
|
||||
initialize_app(&mut app);
|
||||
|
||||
// Instead of being in the panel module and depending on DrivePanel, this test should be in the index module.
|
||||
@@ -1,5 +1,6 @@
|
||||
use settings::macros::define_settings_group;
|
||||
use settings::{RespectUserSyncSetting, SupportedPlatforms, SyncToCloud};
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use settings::{macros::define_settings_group, SupportedPlatforms, SyncToCloud};
|
||||
|
||||
use super::DriveSortOrder;
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
//! Support for displaying inherited ACLs.
|
||||
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxyui::{
|
||||
elements::{CrossAxisAlignment, Flex, MouseStateHandle, ParentElement as _},
|
||||
ui_components::components::UiComponent as _,
|
||||
AppContext, Element, SingletonEntity as _,
|
||||
};
|
||||
use galaxyui::elements::{CrossAxisAlignment, Flex, MouseStateHandle, ParentElement as _};
|
||||
use galaxyui::ui_components::components::UiComponent as _;
|
||||
use galaxyui::{AppContext, Element, SingletonEntity as _};
|
||||
|
||||
use super::style;
|
||||
use crate::{
|
||||
cloud_object::{model::persistence::CloudModel, ServerObjectContainer},
|
||||
drive::CloudObjectTypeAndId,
|
||||
server::{ids::SyncId, telemetry::SharingDialogSource},
|
||||
workspace::WorkspaceAction,
|
||||
};
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::ServerObjectContainer;
|
||||
use crate::drive::CloudObjectTypeAndId;
|
||||
use crate::server::ids::SyncId;
|
||||
use crate::server::telemetry::SharingDialogSource;
|
||||
use crate::workspace::WorkspaceAction;
|
||||
|
||||
/// UI state for inherited permissions.
|
||||
pub struct InheritanceState {
|
||||
|
||||
@@ -1,70 +1,66 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use email_address::EmailAddress;
|
||||
use inheritance::{InheritanceDetails, InheritanceState};
|
||||
use itertools::Itertools;
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use session_sharing_protocol::common::{Guest, PendingGuest, SessionId, TeamAclData};
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_core::ui::theme::Fill as ThemeFill;
|
||||
use warp_editor::editor::NavigationKey;
|
||||
use warpui::clipboard::ClipboardContent;
|
||||
use warpui::elements::{
|
||||
Align, Border, ChildAnchor, ChildView, ConstrainedBox, Container, CornerRadius,
|
||||
CrossAxisAlignment, Dismiss, Empty, Fill, Flex, Highlight, MainAxisAlignment, MainAxisSize,
|
||||
MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement, PositionedElementAnchor,
|
||||
PositionedElementOffsetBounds, Radius, SavePosition, ScrollStateHandle, Scrollable,
|
||||
ScrollableElement, ScrollbarWidth, Shrinkable, Stack, UniformList, UniformListState,
|
||||
};
|
||||
use warpui::fonts::{Properties, Weight};
|
||||
use warpui::keymap::FixedBinding;
|
||||
use warpui::platform::{Cursor, SaveFilePickerConfiguration};
|
||||
use warpui::ui_components::button::{ButtonVariant, TextAndIcon, TextAndIconAlignment};
|
||||
use warpui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
use warpui::{
|
||||
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
ViewHandle, WeakViewHandle,
|
||||
};
|
||||
|
||||
use super::qr_code::{qr_matrix_for_url, qr_png_for_url, QrMatrix, QUIET_ZONE_MODULES};
|
||||
use super::{
|
||||
style, ContentEditability, LinkSharingSubjectType, ShareableObject, SharingAccessLevel,
|
||||
Subject, SubjectExt, TeamKind, UserKind,
|
||||
};
|
||||
use crate::ai::blocklist::{BlocklistAIHistoryEvent, BlocklistAIHistoryModel};
|
||||
use crate::auth::AuthStateProvider;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::model::persistence::CloudModelEvent;
|
||||
use crate::cloud_object::model::persistence::{CloudModel, CloudModelEvent};
|
||||
use crate::cloud_object::model::view::CloudViewModel;
|
||||
use crate::cloud_object::Owner;
|
||||
use crate::cloud_object::{CloudObject, ServerGuestSubject};
|
||||
use crate::cloud_object::{CloudObject, Owner, ServerGuestSubject};
|
||||
use crate::editor::PropagateAndNoOpNavigationKeys;
|
||||
use crate::menu::{self, Menu, MenuItem, MenuItemFields};
|
||||
use crate::send_telemetry_from_ctx;
|
||||
use crate::server::cloud_objects::update_manager::{
|
||||
ObjectOperation, UpdateManager, UpdateManagerEvent,
|
||||
};
|
||||
use crate::server::ids::ServerId;
|
||||
use crate::server::telemetry::CloudObjectTelemetryMetadata;
|
||||
use crate::server::telemetry::OpenedSharingDialogEvent;
|
||||
use crate::server::telemetry::SharingDialogSource;
|
||||
use crate::server::telemetry::{
|
||||
CloudObjectTelemetryMetadata, OpenedSharingDialogEvent, SharingDialogSource,
|
||||
};
|
||||
use crate::terminal::shared_session::permissions_manager::{
|
||||
SessionPermissionsEvent, SessionPermissionsManager,
|
||||
};
|
||||
use crate::terminal::shared_session::SharedSessionActionSource;
|
||||
use crate::terminal::TerminalView;
|
||||
use crate::ui_components::buttons::icon_button_with_color;
|
||||
use crate::ui_components::icons::Icon;
|
||||
use crate::view_components::DismissibleToast;
|
||||
use crate::word_block_editor::{
|
||||
WordBlockEditorStyles, WordBlockEditorView, WordBlockEditorViewEvent, WordBlockLayout,
|
||||
WordBlockStyles,
|
||||
};
|
||||
use crate::workspace::ToastStack;
|
||||
use crate::workspace::{ToastStack, WorkspaceAction};
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
use crate::TelemetryEvent;
|
||||
use email_address::EmailAddress;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_editor::editor::NavigationKey;
|
||||
use galaxyui::elements::{
|
||||
Align, ChildAnchor, ChildView, Fill, Highlight, MainAxisSize, MouseStateHandle,
|
||||
OffsetPositioning, ParentAnchor, PositionedElementAnchor, PositionedElementOffsetBounds,
|
||||
SavePosition, ScrollStateHandle, Scrollable, ScrollableElement, ScrollbarWidth, Shrinkable,
|
||||
Stack, UniformList, UniformListState,
|
||||
};
|
||||
use galaxyui::fonts::{Properties, Weight};
|
||||
use galaxyui::platform::Cursor;
|
||||
use galaxyui::ui_components::button::{ButtonVariant, TextAndIcon, TextAndIconAlignment};
|
||||
use galaxyui::ui_components::components::Coords;
|
||||
use galaxyui::FocusContext;
|
||||
use galaxyui::WeakViewHandle;
|
||||
use galaxyui::{
|
||||
clipboard::ClipboardContent,
|
||||
elements::{
|
||||
Border, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Dismiss, Empty, Flex,
|
||||
MainAxisAlignment, ParentElement, Radius,
|
||||
},
|
||||
keymap::FixedBinding,
|
||||
ui_components::components::{UiComponent, UiComponentStyles},
|
||||
AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext, ViewHandle,
|
||||
};
|
||||
use inheritance::{InheritanceDetails, InheritanceState};
|
||||
use itertools::Itertools;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use session_sharing_protocol::common::{Guest, PendingGuest, SessionId, TeamAclData};
|
||||
|
||||
use super::{
|
||||
style, ContentEditability, LinkSharingSubjectType, ShareableObject, SharingAccessLevel,
|
||||
Subject, SubjectExt, TeamKind, UserKind,
|
||||
};
|
||||
use crate::{send_telemetry_from_ctx, TelemetryEvent};
|
||||
|
||||
mod inheritance;
|
||||
|
||||
@@ -76,6 +72,11 @@ const EMAIL_CHIP_WIDTH: f32 = 100.;
|
||||
const EMAIL_EDITOR_WIDTH: f32 = 100.;
|
||||
|
||||
const SHARING_DIALOG_WIDTH: f32 = 425.;
|
||||
const QR_DIALOG_WIDTH: f32 = 400.;
|
||||
const QR_CARD_SIZE: f32 = 192.;
|
||||
const QR_VISUAL_SIZE: f32 = 160.;
|
||||
const QR_ICON_BUTTON_SIZE: f32 = 32.;
|
||||
const QR_EXPORT_SIZE: u32 = 1024;
|
||||
|
||||
const NO_ACCESS_LABEL: &str = "No access";
|
||||
|
||||
@@ -87,10 +88,22 @@ struct UiStateHandles {
|
||||
link_sharing_menu_button: MouseStateHandle,
|
||||
team_sharing_menu_button: MouseStateHandle,
|
||||
copy_link_button: MouseStateHandle,
|
||||
qr_code_button: MouseStateHandle,
|
||||
qr_back_button: MouseStateHandle,
|
||||
qr_copy_button: MouseStateHandle,
|
||||
qr_download_button: MouseStateHandle,
|
||||
qr_close_button: MouseStateHandle,
|
||||
guest_list_state: UniformListState,
|
||||
guest_scroll_state: ScrollStateHandle,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||
enum SharingDialogMode {
|
||||
#[default]
|
||||
Access,
|
||||
QrCode,
|
||||
}
|
||||
|
||||
/// State for which menu is currently open.
|
||||
///
|
||||
/// This helps with two things:
|
||||
@@ -173,6 +186,7 @@ pub struct SharingDialog {
|
||||
|
||||
ui_state_handles: UiStateHandles,
|
||||
open_menu_state: OpenMenuState,
|
||||
mode: SharingDialogMode,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -184,6 +198,9 @@ pub enum SharingDialogEvent {
|
||||
pub enum SharingDialogAction {
|
||||
Close,
|
||||
CopyLink,
|
||||
ShowQrCode,
|
||||
BackToAccessDialog,
|
||||
DownloadQrCode,
|
||||
#[allow(dead_code)]
|
||||
SetLinkPermissions(Option<SharingAccessLevel>),
|
||||
ToggleLinkSharingMenu,
|
||||
@@ -280,6 +297,7 @@ impl SharingDialog {
|
||||
team_sharing_menu,
|
||||
ui_state_handles: Default::default(),
|
||||
open_menu_state: Default::default(),
|
||||
mode: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,6 +385,7 @@ impl SharingDialog {
|
||||
/// Sets the target object whose ACLs are shown.
|
||||
pub fn set_target(&mut self, target: Option<ShareableObject>, ctx: &mut ViewContext<Self>) {
|
||||
self.target = target;
|
||||
self.mode = SharingDialogMode::Access;
|
||||
self.reset_invite_form(ctx);
|
||||
self.refresh_object_permission_states(ctx);
|
||||
ctx.notify();
|
||||
@@ -382,6 +401,15 @@ impl SharingDialog {
|
||||
.is_some_and(|target| matches!(target, ShareableObject::Session { .. }))
|
||||
}
|
||||
|
||||
pub fn show_qr_code(&mut self, ctx: &mut ViewContext<Self>) {
|
||||
if matches!(self.target, Some(ShareableObject::Session { .. })) {
|
||||
self.set_open_menu(OpenMenuState::None, ctx);
|
||||
self.mode = SharingDialogMode::QrCode;
|
||||
ctx.focus_self();
|
||||
ctx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the target is an AI conversation that cannot be shared.
|
||||
/// This happens when the conversation hasn't been synced to the cloud.
|
||||
pub fn is_unsharable_conversation(&self, app: &AppContext) -> bool {
|
||||
@@ -615,6 +643,7 @@ impl SharingDialog {
|
||||
}
|
||||
|
||||
fn reset_editable_state(&mut self, ctx: &mut ViewContext<Self>) {
|
||||
self.mode = SharingDialogMode::Access;
|
||||
self.reset_invite_form(ctx);
|
||||
ctx.notify();
|
||||
}
|
||||
@@ -675,7 +704,7 @@ impl SharingDialog {
|
||||
guests: &[Guest],
|
||||
pending_guests: &[PendingGuest],
|
||||
) {
|
||||
// We should only update the guests if the dialog is targetting the
|
||||
// We should only update the guests if the dialog is targeting the
|
||||
// correct session.
|
||||
match self.target.as_ref() {
|
||||
Some(ShareableObject::Session {
|
||||
@@ -723,7 +752,7 @@ impl SharingDialog {
|
||||
access_level: Option<SharingAccessLevel>,
|
||||
ctx: &mut ViewContext<Self>,
|
||||
) {
|
||||
// Ensure we're targetting the correct session.
|
||||
// Ensure we're targeting the correct session.
|
||||
let Some(ShareableObject::Session {
|
||||
session_id: target_session_id,
|
||||
..
|
||||
@@ -2386,9 +2415,317 @@ impl SharingDialog {
|
||||
.finish()
|
||||
}
|
||||
|
||||
fn target_link(&self, app: &AppContext) -> Option<String> {
|
||||
self.target.as_ref().and_then(|target| target.link(app))
|
||||
}
|
||||
|
||||
fn target_session_id(&self) -> Option<SessionId> {
|
||||
match self.target {
|
||||
Some(ShareableObject::Session { session_id, .. }) => Some(session_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn qr_filename(&self) -> String {
|
||||
match self.target_session_id() {
|
||||
Some(session_id) => format!("warp-session-qr-code-{session_id}.png"),
|
||||
None => "warp-session-qr-code.png".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn show_ephemeral_toast(
|
||||
&self,
|
||||
toast: DismissibleToast<WorkspaceAction>,
|
||||
ctx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let window_id = ctx.window_id();
|
||||
ToastStack::handle(ctx).update(ctx, |toast_stack, ctx| {
|
||||
toast_stack.add_ephemeral_toast(toast, window_id, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
fn download_qr_code(&self, ctx: &mut ViewContext<Self>) {
|
||||
let Some(url) = self.target_link(ctx) else {
|
||||
self.show_ephemeral_toast(
|
||||
DismissibleToast::error("Unable to download QR code.".to_string()),
|
||||
ctx,
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
let png = match qr_png_for_url(&url, QR_EXPORT_SIZE) {
|
||||
Ok(png) => png,
|
||||
Err(_) => {
|
||||
self.show_ephemeral_toast(
|
||||
DismissibleToast::error("Unable to download QR code.".to_string()),
|
||||
ctx,
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
ctx.open_save_file_picker(
|
||||
move |path, me, ctx| {
|
||||
let Some(path) = path else {
|
||||
return;
|
||||
};
|
||||
me.write_qr_png(path, png, ctx);
|
||||
},
|
||||
SaveFilePickerConfiguration::new().with_default_filename(self.qr_filename()),
|
||||
);
|
||||
}
|
||||
|
||||
fn write_qr_png(&self, path: String, png: Vec<u8>, ctx: &mut ViewContext<Self>) {
|
||||
ctx.spawn(
|
||||
async move { async_fs::write(path, png).await },
|
||||
|me, result, ctx| me.handle_qr_write_result(result, ctx),
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_qr_write_result(&self, result: std::io::Result<()>, ctx: &mut ViewContext<Self>) {
|
||||
match result {
|
||||
Ok(()) => self.show_ephemeral_toast(
|
||||
DismissibleToast::success("QR code downloaded.".to_string()),
|
||||
ctx,
|
||||
),
|
||||
Err(_) => self.show_ephemeral_toast(
|
||||
DismissibleToast::error("Unable to download QR code.".to_string()),
|
||||
ctx,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_footer_icon_button(
|
||||
&self,
|
||||
icon: Icon,
|
||||
action: SharingDialogAction,
|
||||
tooltip: &'static str,
|
||||
mouse_state: MouseStateHandle,
|
||||
appearance: &Appearance,
|
||||
) -> Box<dyn Element> {
|
||||
let button_background = appearance.theme().surface_2();
|
||||
let button_foreground = appearance.theme().main_text_color(button_background);
|
||||
let ui_builder = appearance.ui_builder().clone();
|
||||
icon_button_with_color(
|
||||
appearance,
|
||||
icon,
|
||||
false,
|
||||
mouse_state,
|
||||
ThemeFill::Solid(button_foreground.into()),
|
||||
)
|
||||
.with_tooltip(move || ui_builder.tool_tip(tooltip.to_string()).build().finish())
|
||||
.with_style(UiComponentStyles {
|
||||
width: Some(style::ACL_ITEM_HEIGHT),
|
||||
height: Some(style::ACL_ITEM_HEIGHT),
|
||||
padding: Some(Coords::uniform(4.)),
|
||||
font_color: Some(button_foreground.into()),
|
||||
background: Some(button_background.into()),
|
||||
border_color: Some(style::form_border_color(appearance).into()),
|
||||
border_radius: Some(CornerRadius::with_all(Radius::Pixels(4.))),
|
||||
..Default::default()
|
||||
})
|
||||
.with_clicked_styles(UiComponentStyles {
|
||||
background: Some(appearance.theme().surface_2().into()),
|
||||
..Default::default()
|
||||
})
|
||||
.with_hovered_styles(UiComponentStyles {
|
||||
background: Some(appearance.theme().surface_3().into()),
|
||||
..Default::default()
|
||||
})
|
||||
.build()
|
||||
.on_click(move |ctx, _, _| ctx.dispatch_typed_action(action.clone()))
|
||||
.finish()
|
||||
}
|
||||
|
||||
fn render_qr_matrix(&self, matrix: &QrMatrix) -> Box<dyn Element> {
|
||||
let modules_with_quiet_zone = matrix.width().saturating_add(QUIET_ZONE_MODULES * 2);
|
||||
let module_size = QR_VISUAL_SIZE / modules_with_quiet_zone as f32;
|
||||
let mut column = Flex::column().with_main_axis_size(MainAxisSize::Max);
|
||||
|
||||
for y in 0..modules_with_quiet_zone {
|
||||
let mut row = Flex::row().with_main_axis_size(MainAxisSize::Max);
|
||||
for x in 0..modules_with_quiet_zone {
|
||||
let matrix_x = x.saturating_sub(QUIET_ZONE_MODULES);
|
||||
let matrix_y = y.saturating_sub(QUIET_ZONE_MODULES);
|
||||
let is_dark = x >= QUIET_ZONE_MODULES
|
||||
&& y >= QUIET_ZONE_MODULES
|
||||
&& matrix_x < matrix.width()
|
||||
&& matrix_y < matrix.width()
|
||||
&& matrix.is_dark(matrix_x, matrix_y);
|
||||
let color = if is_dark {
|
||||
ColorU::black()
|
||||
} else {
|
||||
ColorU::white()
|
||||
};
|
||||
row.add_child(
|
||||
ConstrainedBox::new(
|
||||
Container::new(Empty::new().finish())
|
||||
.with_background(color)
|
||||
.finish(),
|
||||
)
|
||||
.with_width(module_size)
|
||||
.with_height(module_size)
|
||||
.finish(),
|
||||
);
|
||||
}
|
||||
column.add_child(row.finish());
|
||||
}
|
||||
|
||||
ConstrainedBox::new(column.finish())
|
||||
.with_width(QR_VISUAL_SIZE)
|
||||
.with_height(QR_VISUAL_SIZE)
|
||||
.finish()
|
||||
}
|
||||
|
||||
fn render_qr_header(&self, appearance: &Appearance) -> Box<dyn Element> {
|
||||
let foreground = style::acl_primary_text_color(appearance);
|
||||
let icon_button_styles = UiComponentStyles {
|
||||
width: Some(QR_ICON_BUTTON_SIZE),
|
||||
height: Some(QR_ICON_BUTTON_SIZE),
|
||||
font_color: Some(foreground),
|
||||
border_radius: Some(CornerRadius::with_all(Radius::Pixels(4.))),
|
||||
..Default::default()
|
||||
};
|
||||
let icon_hover_styles = UiComponentStyles {
|
||||
background: Some(appearance.theme().surface_2().into()),
|
||||
..Default::default()
|
||||
};
|
||||
let back_button = icon_button_with_color(
|
||||
appearance,
|
||||
Icon::ArrowLeft,
|
||||
false,
|
||||
self.ui_state_handles.qr_back_button.clone(),
|
||||
ThemeFill::Solid(foreground),
|
||||
)
|
||||
.with_style(icon_button_styles)
|
||||
.with_hovered_styles(icon_hover_styles)
|
||||
.build()
|
||||
.on_click(|ctx, _, _| ctx.dispatch_typed_action(SharingDialogAction::BackToAccessDialog))
|
||||
.finish();
|
||||
let title = appearance
|
||||
.ui_builder()
|
||||
.span("Share session QR code")
|
||||
.with_style(UiComponentStyles {
|
||||
font_color: Some(foreground),
|
||||
font_size: Some(style::HEADER_TEXT_SIZE),
|
||||
..Default::default()
|
||||
})
|
||||
.build()
|
||||
.finish();
|
||||
let esc_hint = appearance
|
||||
.ui_builder()
|
||||
.span("ESC")
|
||||
.with_style(UiComponentStyles {
|
||||
font_color: Some(style::acl_secondary_text_color(appearance)),
|
||||
font_size: Some(12.),
|
||||
background: Some(appearance.theme().surface_2().into()),
|
||||
border_radius: Some(CornerRadius::with_all(Radius::Pixels(4.))),
|
||||
padding: Some(Coords::default().left(6.).right(6.).top(2.).bottom(2.)),
|
||||
..Default::default()
|
||||
})
|
||||
.build()
|
||||
.finish();
|
||||
let close_button = icon_button_with_color(
|
||||
appearance,
|
||||
Icon::X,
|
||||
false,
|
||||
self.ui_state_handles.qr_close_button.clone(),
|
||||
ThemeFill::Solid(foreground),
|
||||
)
|
||||
.with_style(icon_button_styles)
|
||||
.with_hovered_styles(icon_hover_styles)
|
||||
.build()
|
||||
.on_click(|ctx, _, _| ctx.dispatch_typed_action(SharingDialogAction::Close))
|
||||
.finish();
|
||||
|
||||
Container::new(
|
||||
Flex::row()
|
||||
.with_main_axis_size(MainAxisSize::Max)
|
||||
.with_main_axis_alignment(MainAxisAlignment::SpaceBetween)
|
||||
.with_cross_axis_alignment(CrossAxisAlignment::Center)
|
||||
.with_children([
|
||||
back_button,
|
||||
Shrinkable::new(1., title).finish(),
|
||||
esc_hint,
|
||||
close_button,
|
||||
])
|
||||
.finish(),
|
||||
)
|
||||
.with_horizontal_padding(style::ACL_ITEM_PADDING)
|
||||
.with_padding_top(8.)
|
||||
.with_padding_bottom(8.)
|
||||
.finish()
|
||||
}
|
||||
|
||||
fn render_qr_dialog(&self, appearance: &Appearance, app: &AppContext) -> Box<dyn Element> {
|
||||
let qr_contents = self
|
||||
.target_link(app)
|
||||
.and_then(|url| qr_matrix_for_url(&url).ok())
|
||||
.map(|matrix| {
|
||||
let card = Container::new(Align::new(self.render_qr_matrix(&matrix)).finish())
|
||||
.with_background(ColorU::white())
|
||||
.with_corner_radius(CornerRadius::with_all(Radius::Pixels(8.)))
|
||||
.finish();
|
||||
let action_row = Flex::row()
|
||||
.with_main_axis_alignment(MainAxisAlignment::Center)
|
||||
.with_cross_axis_alignment(CrossAxisAlignment::Center)
|
||||
.with_children([
|
||||
self.render_footer_icon_button(
|
||||
Icon::Copy,
|
||||
SharingDialogAction::CopyLink,
|
||||
"Copy link",
|
||||
self.ui_state_handles.qr_copy_button.clone(),
|
||||
appearance,
|
||||
),
|
||||
Container::new(self.render_footer_icon_button(
|
||||
Icon::Download,
|
||||
SharingDialogAction::DownloadQrCode,
|
||||
"Download QR code",
|
||||
self.ui_state_handles.qr_download_button.clone(),
|
||||
appearance,
|
||||
))
|
||||
.with_margin_left(8.)
|
||||
.finish(),
|
||||
])
|
||||
.finish();
|
||||
Flex::column()
|
||||
.with_main_axis_alignment(MainAxisAlignment::Center)
|
||||
.with_cross_axis_alignment(CrossAxisAlignment::Center)
|
||||
.with_children([
|
||||
ConstrainedBox::new(card)
|
||||
.with_width(QR_CARD_SIZE)
|
||||
.with_height(QR_CARD_SIZE)
|
||||
.finish(),
|
||||
Container::new(action_row).with_margin_top(12.).finish(),
|
||||
])
|
||||
.finish()
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
appearance
|
||||
.ui_builder()
|
||||
.paragraph("Unable to create QR code for this session link.")
|
||||
.with_style(UiComponentStyles {
|
||||
font_color: Some(style::acl_secondary_text_color(appearance)),
|
||||
..Default::default()
|
||||
})
|
||||
.build()
|
||||
.finish()
|
||||
});
|
||||
|
||||
Flex::column()
|
||||
.with_main_axis_size(MainAxisSize::Min)
|
||||
.with_children([
|
||||
self.render_qr_header(appearance),
|
||||
Container::new(Align::new(qr_contents).finish())
|
||||
.with_vertical_padding(32.)
|
||||
.finish(),
|
||||
])
|
||||
.finish()
|
||||
}
|
||||
|
||||
/// Renders a link to the shared object, with a CTA to copy the URL.
|
||||
fn render_object_link(&self, appearance: &Appearance, app: &AppContext) -> Box<dyn Element> {
|
||||
let url = match self.target.as_ref().and_then(|target| target.link(app)) {
|
||||
let url = match self.target_link(app) {
|
||||
Some(url) => url,
|
||||
None => return Empty::new().finish(),
|
||||
};
|
||||
@@ -2404,12 +2741,8 @@ impl SharingDialog {
|
||||
.finish();
|
||||
|
||||
let link = Container::new(Align::new(link_text).left().finish())
|
||||
.with_border(
|
||||
Border::new(1.)
|
||||
.with_sides(true, true, true, false)
|
||||
.with_border_color(style::form_border_color(appearance)),
|
||||
)
|
||||
.with_corner_radius(CornerRadius::with_left(Radius::Pixels(4.)))
|
||||
.with_border(Border::all(1.).with_border_color(style::form_border_color(appearance)))
|
||||
.with_corner_radius(CornerRadius::with_all(Radius::Pixels(4.)))
|
||||
.with_uniform_padding(8.)
|
||||
.finish();
|
||||
|
||||
@@ -2436,7 +2769,7 @@ impl SharingDialog {
|
||||
font_color: Some(copy_button_foreground.into()),
|
||||
background: Some(copy_button_background.into()),
|
||||
border_color: Some(style::form_border_color(appearance).into()),
|
||||
border_radius: Some(CornerRadius::with_right(Radius::Pixels(4.))),
|
||||
border_radius: Some(CornerRadius::with_all(Radius::Pixels(4.))),
|
||||
..Default::default()
|
||||
})
|
||||
.with_clicked_styles(UiComponentStyles {
|
||||
@@ -2451,16 +2784,29 @@ impl SharingDialog {
|
||||
.on_click(|ctx, _, _| ctx.dispatch_typed_action(SharingDialogAction::CopyLink))
|
||||
.finish();
|
||||
|
||||
let link_form = ConstrainedBox::new(
|
||||
Flex::row()
|
||||
.with_children([Shrinkable::new(1., link).finish(), copy_button])
|
||||
.with_main_axis_size(MainAxisSize::Max)
|
||||
.with_main_axis_alignment(MainAxisAlignment::SpaceBetween)
|
||||
.with_cross_axis_alignment(CrossAxisAlignment::Center)
|
||||
.finish(),
|
||||
)
|
||||
.with_min_height(style::ACL_ITEM_HEIGHT)
|
||||
.finish();
|
||||
let qr_button = matches!(self.target, Some(ShareableObject::Session { .. })).then(|| {
|
||||
self.render_footer_icon_button(
|
||||
Icon::QrCode,
|
||||
SharingDialogAction::ShowQrCode,
|
||||
"Show QR code",
|
||||
self.ui_state_handles.qr_code_button.clone(),
|
||||
appearance,
|
||||
)
|
||||
});
|
||||
|
||||
let mut link_row = Flex::row()
|
||||
.with_main_axis_size(MainAxisSize::Max)
|
||||
.with_main_axis_alignment(MainAxisAlignment::SpaceBetween)
|
||||
.with_cross_axis_alignment(CrossAxisAlignment::Center)
|
||||
.with_child(Shrinkable::new(1., link).finish());
|
||||
if let Some(qr_button) = qr_button {
|
||||
link_row.add_child(Container::new(qr_button).with_margin_left(8.).finish());
|
||||
}
|
||||
link_row.add_child(Container::new(copy_button).with_margin_left(8.).finish());
|
||||
|
||||
let link_form = ConstrainedBox::new(link_row.finish())
|
||||
.with_min_height(style::ACL_ITEM_HEIGHT)
|
||||
.finish();
|
||||
|
||||
Container::new(link_form)
|
||||
.with_horizontal_padding(style::ACL_ITEM_PADDING)
|
||||
@@ -2500,41 +2846,51 @@ impl View for SharingDialog {
|
||||
let appearance = Appearance::as_ref(app);
|
||||
let theme = appearance.theme();
|
||||
|
||||
let mut contents = Flex::column();
|
||||
let (contents, width) = if self.mode == SharingDialogMode::QrCode
|
||||
&& matches!(self.target, Some(ShareableObject::Session { .. }))
|
||||
{
|
||||
(self.render_qr_dialog(appearance, app), QR_DIALOG_WIDTH)
|
||||
} else {
|
||||
let mut contents = Flex::column();
|
||||
|
||||
contents.extend(self.render_session_header(appearance, app));
|
||||
contents.extend(self.render_session_header(appearance, app));
|
||||
|
||||
if self.can_edit_access(app) && self.can_direct_link_share(app) {
|
||||
contents.add_child(self.render_invite_form(appearance, app));
|
||||
}
|
||||
contents.add_child(self.render_access_header(appearance));
|
||||
contents.extend(self.render_restricted_access_label(appearance, app));
|
||||
if self.can_edit_access(app) && self.can_direct_link_share(app) {
|
||||
contents.add_child(self.render_invite_form(appearance, app));
|
||||
}
|
||||
contents.add_child(self.render_access_header(appearance));
|
||||
contents.extend(self.render_restricted_access_label(appearance, app));
|
||||
|
||||
if self.can_anyone_with_link_share(app) {
|
||||
contents.extend(self.render_link_sharing_subject(appearance, app));
|
||||
}
|
||||
contents.extend(self.render_team_sharing_subject(appearance, app));
|
||||
contents.extend(self.render_owner(appearance, app));
|
||||
if self.can_anyone_with_link_share(app) {
|
||||
contents.extend(self.render_link_sharing_subject(appearance, app));
|
||||
}
|
||||
contents.extend(self.render_team_sharing_subject(appearance, app));
|
||||
contents.extend(self.render_owner(appearance, app));
|
||||
|
||||
if let Some(guest_list) = self.render_guests(appearance) {
|
||||
contents.add_child(guest_list);
|
||||
}
|
||||
if let Some(guest_list) = self.render_guests(appearance) {
|
||||
contents.add_child(guest_list);
|
||||
}
|
||||
|
||||
contents.add_child(self.render_object_link(appearance, app));
|
||||
contents.add_child(self.render_object_link(appearance, app));
|
||||
|
||||
let mut stack = Stack::new();
|
||||
stack.add_child(contents.finish());
|
||||
self.render_menu(&mut stack, app);
|
||||
let mut stack = Stack::new();
|
||||
stack.add_child(contents.finish());
|
||||
self.render_menu(&mut stack, app);
|
||||
|
||||
let dialog = Container::new(stack.finish())
|
||||
let contents = Container::new(stack.finish())
|
||||
.with_vertical_padding(style::ACL_ITEM_PADDING)
|
||||
.finish();
|
||||
(contents, SHARING_DIALOG_WIDTH)
|
||||
};
|
||||
|
||||
let dialog = Container::new(contents)
|
||||
.with_corner_radius(CornerRadius::with_all(Radius::Pixels(8.)))
|
||||
.with_border(Border::all(1.).with_border_color(theme.surface_3().into()))
|
||||
.with_vertical_padding(style::ACL_ITEM_PADDING)
|
||||
.with_background(style::dialog_background(appearance));
|
||||
|
||||
Dismiss::new(
|
||||
ConstrainedBox::new(dialog.finish())
|
||||
.with_width(SHARING_DIALOG_WIDTH)
|
||||
.with_width(width)
|
||||
.finish(),
|
||||
)
|
||||
.on_dismiss(|ctx, _app| ctx.dispatch_typed_action(SharingDialogAction::Close))
|
||||
@@ -2543,7 +2899,7 @@ impl View for SharingDialog {
|
||||
}
|
||||
|
||||
fn on_focus(&mut self, focus_ctx: &FocusContext, ctx: &mut ViewContext<Self>) {
|
||||
if focus_ctx.is_self_focused() {
|
||||
if focus_ctx.is_self_focused() && self.mode == SharingDialogMode::Access {
|
||||
ctx.focus(&self.invite_form.email_editor);
|
||||
}
|
||||
}
|
||||
@@ -2615,6 +2971,12 @@ impl TypedActionView for SharingDialog {
|
||||
ctx.notify();
|
||||
}
|
||||
SharingDialogAction::CopyLink => self.copy_link(ctx),
|
||||
SharingDialogAction::ShowQrCode => self.show_qr_code(ctx),
|
||||
SharingDialogAction::BackToAccessDialog => {
|
||||
self.mode = SharingDialogMode::Access;
|
||||
ctx.notify();
|
||||
}
|
||||
SharingDialogAction::DownloadQrCode => self.download_qr_code(ctx),
|
||||
SharingDialogAction::ToggleLinkSharingMenu => {
|
||||
self.toggle_menu(OpenMenuState::LinkSharing, ctx);
|
||||
}
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use chrono::{DateTime, Local};
|
||||
use galaxy_core::{channel::ChannelState, ui::appearance::Appearance};
|
||||
use galaxyui::{
|
||||
color::ColorU,
|
||||
ui_components::components::{UiComponent, UiComponentStyles},
|
||||
AppContext, SingletonEntity, WeakViewHandle,
|
||||
};
|
||||
use session_sharing_protocol::common::SessionId;
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxyui::color::ColorU;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::{AppContext, SingletonEntity, WeakViewHandle};
|
||||
|
||||
use crate::{
|
||||
ai::{agent::conversation::AIConversationId, blocklist::BlocklistAIHistoryModel},
|
||||
cloud_object::model::persistence::CloudModel,
|
||||
server::{ids::ServerId, server_api::object::GuestIdentifier},
|
||||
terminal::{shared_session::join_link, TerminalView},
|
||||
ui_components::{
|
||||
avatar::{Avatar, AvatarContent},
|
||||
icons::Icon,
|
||||
},
|
||||
workspaces::{user_profiles::UserProfiles, user_workspaces::UserWorkspaces},
|
||||
};
|
||||
use crate::ai::agent::conversation::AIConversationId;
|
||||
use crate::ai::blocklist::BlocklistAIHistoryModel;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::server::ids::ServerId;
|
||||
use crate::server::server_api::object::GuestIdentifier;
|
||||
use crate::terminal::shared_session::join_link;
|
||||
use crate::terminal::TerminalView;
|
||||
use crate::ui_components::avatar::{Avatar, AvatarContent};
|
||||
use crate::ui_components::icons::Icon;
|
||||
use crate::workspaces::user_profiles::UserProfiles;
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
|
||||
pub mod dialog;
|
||||
mod qr_code;
|
||||
mod style;
|
||||
|
||||
// Re-export types from galaxy_server_client.
|
||||
pub use galaxy_server_client::drive::sharing::{
|
||||
// Re-export types from cloud_objects.
|
||||
pub use cloud_objects::drive::sharing::{
|
||||
LinkSharingSubjectType, SharingAccessLevel, Subject, TeamKind, UserKind,
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
use std::io::Cursor;
|
||||
|
||||
use image::{ImageBuffer, ImageFormat, Luma};
|
||||
use qrcode::{Color, QrCode};
|
||||
|
||||
pub const QUIET_ZONE_MODULES: usize = 4;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct QrMatrix {
|
||||
width: usize,
|
||||
modules: Vec<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum QrCodeError {
|
||||
#[error("Unable to encode QR code")]
|
||||
Encode,
|
||||
#[error("Unable to encode QR code image")]
|
||||
Image(#[from] image::ImageError),
|
||||
}
|
||||
|
||||
impl QrMatrix {
|
||||
pub fn width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn is_dark(&self, x: usize, y: usize) -> bool {
|
||||
self.modules
|
||||
.get(y.saturating_mul(self.width).saturating_add(x))
|
||||
.copied()
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn qr_matrix_for_url(url: &str) -> Result<QrMatrix, QrCodeError> {
|
||||
let code = QrCode::new(url.as_bytes()).map_err(|_| QrCodeError::Encode)?;
|
||||
let width = code.width();
|
||||
let modules = code
|
||||
.to_colors()
|
||||
.into_iter()
|
||||
.map(|color| matches!(color, Color::Dark))
|
||||
.collect();
|
||||
Ok(QrMatrix { width, modules })
|
||||
}
|
||||
|
||||
pub fn qr_png_for_url(url: &str, pixel_size: u32) -> Result<Vec<u8>, QrCodeError> {
|
||||
let matrix = qr_matrix_for_url(url)?;
|
||||
let modules_with_quiet_zone = matrix.width().saturating_add(QUIET_ZONE_MODULES * 2);
|
||||
let module_size = (pixel_size as usize / modules_with_quiet_zone).max(1);
|
||||
let image_size = modules_with_quiet_zone.saturating_mul(module_size) as u32;
|
||||
let mut image = ImageBuffer::from_pixel(image_size, image_size, Luma([255u8]));
|
||||
|
||||
for y in 0..matrix.width() {
|
||||
for x in 0..matrix.width() {
|
||||
if matrix.is_dark(x, y) {
|
||||
let start_x = (x + QUIET_ZONE_MODULES) * module_size;
|
||||
let start_y = (y + QUIET_ZONE_MODULES) * module_size;
|
||||
for pixel_y in start_y..start_y + module_size {
|
||||
for pixel_x in start_x..start_x + module_size {
|
||||
image.put_pixel(pixel_x as u32, pixel_y as u32, Luma([0u8]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut png = Cursor::new(Vec::new());
|
||||
image.write_to(&mut png, ImageFormat::Png)?;
|
||||
Ok(png.into_inner())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "qr_code_tests.rs"]
|
||||
mod tests;
|
||||
@@ -0,0 +1,13 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn qr_matrix_for_url_returns_square_matrix_with_dark_modules() {
|
||||
let matrix = match qr_matrix_for_url("https://app.warp.dev/session/test-session") {
|
||||
Ok(matrix) => matrix,
|
||||
Err(error) => panic!("failed to generate QR matrix: {error}"),
|
||||
};
|
||||
|
||||
assert!(matrix.width() > 0);
|
||||
assert_eq!(matrix.modules.len(), matrix.width() * matrix.width());
|
||||
assert!(matrix.modules.iter().any(|is_dark| *is_dark));
|
||||
}
|
||||
@@ -1,18 +1,13 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use galaxy_core::ui::{
|
||||
appearance::Appearance,
|
||||
theme::{color::internal_colors, Fill},
|
||||
};
|
||||
use galaxyui::{
|
||||
color::ColorU,
|
||||
elements::{CornerRadius, Radius},
|
||||
fonts::Weight,
|
||||
ui_components::{
|
||||
components::{UiComponent as _, UiComponentStyles},
|
||||
text::Span,
|
||||
},
|
||||
};
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_core::ui::theme::color::internal_colors;
|
||||
use galaxy_core::ui::theme::Fill;
|
||||
use galaxyui::color::ColorU;
|
||||
use galaxyui::elements::{CornerRadius, Radius};
|
||||
use galaxyui::fonts::Weight;
|
||||
use galaxyui::ui_components::components::{UiComponent as _, UiComponentStyles};
|
||||
use galaxyui::ui_components::text::Span;
|
||||
|
||||
/// The padding around ACL items in the sharing dialog.
|
||||
pub const ACL_ITEM_PADDING: f32 = 16.;
|
||||
|
||||
@@ -5,19 +5,14 @@ use galaxyui::{SingletonEntity, ViewContext};
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
ai::AIRequestUsageModel,
|
||||
auth::AuthStateProvider,
|
||||
send_telemetry_from_ctx,
|
||||
server::telemetry::TelemetryEvent,
|
||||
workflows::workflow::{Argument, Workflow},
|
||||
workspaces::user_workspaces::UserWorkspaces,
|
||||
};
|
||||
|
||||
use super::{
|
||||
arguments::ArgumentsState,
|
||||
modal::{AiAssistState, WorkflowModal, WorkflowModalEvent},
|
||||
};
|
||||
use super::arguments::ArgumentsState;
|
||||
use super::modal::{AiAssistState, WorkflowModal, WorkflowModalEvent};
|
||||
use crate::ai::AIRequestUsageModel;
|
||||
use crate::auth::AuthStateProvider;
|
||||
use crate::send_telemetry_from_ctx;
|
||||
use crate::server::telemetry::TelemetryEvent;
|
||||
use crate::workflows::workflow::{Argument, Workflow};
|
||||
use crate::workspaces::user_workspaces::UserWorkspaces;
|
||||
|
||||
/// Generated command metadata from server.
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
ops::Range,
|
||||
};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ops::Range;
|
||||
|
||||
use handlebars::parser::{ParsedArgumentResult, ParsedArgumentsIterator};
|
||||
|
||||
use crate::workflows::workflow::Argument;
|
||||
use handlebars::parser::{ParsedArgumentResult, ParsedArgumentsIterator};
|
||||
|
||||
/// Represents arguments for workflow to be viewed and edited in ArgumentsEditorView.
|
||||
///
|
||||
@@ -201,5 +200,5 @@ impl ArgumentsState {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "arguments_test.rs"]
|
||||
#[path = "arguments_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
+3
-2
@@ -1,9 +1,10 @@
|
||||
use std::{fmt::Debug, iter::zip};
|
||||
use std::fmt::Debug;
|
||||
use std::iter::zip;
|
||||
|
||||
use crate::workflows::workflow::Argument;
|
||||
use galaxyui::App;
|
||||
|
||||
use super::ArgumentsState;
|
||||
use crate::workflows::workflow::Argument;
|
||||
|
||||
fn assert_vector_eq<T>(vector: Vec<T>, expected_vector: &Vec<T>)
|
||||
where
|
||||
@@ -1,34 +1,33 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use galaxy_core::{features::FeatureFlag, ui::appearance::Appearance};
|
||||
use strum::IntoEnumIterator;
|
||||
use strum_macros::{EnumIter, IntoStaticStr};
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_editor::editor::NavigationKey;
|
||||
use galaxyui::elements::{
|
||||
Border, ClippedScrollStateHandle, ClippedScrollable, ConstrainedBox, Container, CornerRadius,
|
||||
CrossAxisAlignment, Empty, Fill, Flex, MainAxisAlignment, MainAxisSize, MouseStateHandle,
|
||||
ParentElement, Radius, ScrollbarWidth, Shrinkable,
|
||||
};
|
||||
use galaxyui::ui_components::button::ButtonVariant;
|
||||
use galaxyui::ui_components::components::{UiComponent, UiComponentStyles};
|
||||
use galaxyui::ui_components::toggle_menu::{ToggleMenuItem, ToggleMenuStateHandle};
|
||||
use galaxyui::{
|
||||
elements::{
|
||||
Border, ClippedScrollStateHandle, ClippedScrollable, ConstrainedBox, Container,
|
||||
CornerRadius, CrossAxisAlignment, Empty, Fill, Flex, MainAxisAlignment, MainAxisSize,
|
||||
MouseStateHandle, ParentElement, Radius, ScrollbarWidth, Shrinkable,
|
||||
},
|
||||
ui_components::{
|
||||
button::ButtonVariant,
|
||||
components::{UiComponent, UiComponentStyles},
|
||||
toggle_menu::{ToggleMenuItem, ToggleMenuStateHandle},
|
||||
},
|
||||
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
ViewHandle,
|
||||
};
|
||||
use strum::IntoEnumIterator;
|
||||
use strum_macros::{EnumIter, IntoStaticStr};
|
||||
|
||||
use crate::{
|
||||
cloud_object::{model::persistence::CloudModel, Revision},
|
||||
editor::{
|
||||
EditorOptions, EditorView, Event, PropagateAndNoOpNavigationKeys, SingleLineEditorOptions,
|
||||
TextOptions,
|
||||
},
|
||||
server::ids::{ClientId, SyncId},
|
||||
ui_components::{buttons::icon_button, icons::Icon},
|
||||
workflows::workflow_enum::EnumVariants,
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::Revision;
|
||||
use crate::editor::{
|
||||
EditorOptions, EditorView, Event, PropagateAndNoOpNavigationKeys, SingleLineEditorOptions,
|
||||
TextOptions,
|
||||
};
|
||||
use crate::server::ids::{ClientId, SyncId};
|
||||
use crate::ui_components::buttons::icon_button;
|
||||
use crate::ui_components::icons::Icon;
|
||||
use crate::workflows::workflow_enum::EnumVariants;
|
||||
|
||||
const CONTAINER_PADDING: f32 = 16.;
|
||||
const CORE_WIDTH: f32 = 400.;
|
||||
|
||||
@@ -1,70 +1,27 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::{cmp::Ordering, sync::Arc};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
|
||||
use galaxy_core::ui::theme::Fill;
|
||||
use galaxy_editor::editor::NavigationKey;
|
||||
use galaxyui::elements::Clipped;
|
||||
use galaxyui::FocusContext;
|
||||
use galaxyui::{
|
||||
clipboard::ClipboardContent,
|
||||
elements::{
|
||||
Align, Border, ChildAnchor, ClippedScrollStateHandle, ClippedScrollable, ConstrainedBox,
|
||||
Container, CornerRadius, CrossAxisAlignment, Flex, MainAxisAlignment, MainAxisSize,
|
||||
MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement, ParentOffsetBounds,
|
||||
Radius, ScrollbarWidth, Shrinkable, Stack,
|
||||
},
|
||||
fonts::{FamilyId, Weight},
|
||||
platform::Cursor,
|
||||
presenter::ChildView,
|
||||
ui_components::{
|
||||
button::{ButtonVariant, TextAndIcon, TextAndIconAlignment},
|
||||
components::{Coords, UiComponent, UiComponentStyles},
|
||||
},
|
||||
AppContext, Element, Entity, SingletonEntity, TypedActionView, UpdateView, View, ViewContext,
|
||||
ViewHandle,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use string_offset::CharOffset;
|
||||
|
||||
use crate::auth::UserUid;
|
||||
use crate::{
|
||||
appearance::Appearance,
|
||||
cloud_object::{
|
||||
breadcrumbs::{ContainingObject, ContainingObjectKind},
|
||||
model::persistence::{CloudModel, CloudModelEvent},
|
||||
CloudObject, CloudObjectEventEntrypoint, ObjectType, Owner, Revision,
|
||||
},
|
||||
drive::{
|
||||
cloud_object_styling::warp_drive_icon_color, items::WarpDriveItemId, CloudObjectTypeAndId,
|
||||
DriveObjectType,
|
||||
},
|
||||
editor::{
|
||||
EditorOptions, EditorView, EnterAction, EnterSettings, Event as EditorEvent,
|
||||
InteractionState, PlainTextEditorViewAction as EditorAction,
|
||||
PropagateAndNoOpNavigationKeys, TextOptions, TextStyleOperation,
|
||||
},
|
||||
menu::{Event, Menu, MenuItem, MenuItemFields},
|
||||
network::NetworkStatus,
|
||||
server::{
|
||||
cloud_objects::update_manager::UpdateManager,
|
||||
ids::{ClientId, ServerId, SyncId},
|
||||
server_api::ai::AIClient,
|
||||
},
|
||||
themes::theme::AnsiColorIdentifier,
|
||||
ui_components::{
|
||||
blended_colors,
|
||||
breadcrumb::{self, BreadcrumbState},
|
||||
buttons::icon_button,
|
||||
dialog::{dialog_styles, Dialog},
|
||||
icons::{self, Icon, ICON_DIMENSIONS},
|
||||
menu_button::{icon_button_with_context_menu, MenuDirection},
|
||||
},
|
||||
workflows::{
|
||||
workflow::{Argument, Workflow},
|
||||
CloudWorkflow,
|
||||
},
|
||||
use galaxy_core::ui::theme::Fill;
|
||||
use galaxy_editor::editor::NavigationKey;
|
||||
use galaxyui::clipboard::ClipboardContent;
|
||||
use galaxyui::elements::{
|
||||
Align, Border, ChildAnchor, Clipped, ClippedScrollStateHandle, ClippedScrollable,
|
||||
ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Flex, MainAxisAlignment,
|
||||
MainAxisSize, MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement,
|
||||
ParentOffsetBounds, Radius, ScrollbarWidth, Shrinkable, Stack,
|
||||
};
|
||||
use galaxyui::fonts::{FamilyId, Weight};
|
||||
use galaxyui::platform::Cursor;
|
||||
use galaxyui::presenter::ChildView;
|
||||
use galaxyui::ui_components::button::{ButtonVariant, TextAndIcon, TextAndIconAlignment};
|
||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
use galaxyui::{
|
||||
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, UpdateView, View,
|
||||
ViewContext, ViewHandle,
|
||||
};
|
||||
|
||||
use super::arguments::ArgumentsState;
|
||||
@@ -73,6 +30,33 @@ use super::workflow_arg_selector::{
|
||||
WorkflowArgSelector, WorkflowArgSelectorEvent, WorkflowArgSelectorStyles,
|
||||
};
|
||||
use super::workflow_arg_type_helpers::{self, ArgumentEditorRowIndex};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::auth::UserUid;
|
||||
use crate::cloud_object::breadcrumbs::{ContainingObject, ContainingObjectKind};
|
||||
use crate::cloud_object::model::persistence::{CloudModel, CloudModelEvent};
|
||||
use crate::cloud_object::{CloudObject, CloudObjectEventEntrypoint, ObjectType, Owner, Revision};
|
||||
use crate::drive::cloud_object_styling::warp_drive_icon_color;
|
||||
use crate::drive::items::WarpDriveItemId;
|
||||
use crate::drive::{CloudObjectTypeAndId, DriveObjectType};
|
||||
use crate::editor::{
|
||||
EditorOptions, EditorView, EnterAction, EnterSettings, Event as EditorEvent, InteractionState,
|
||||
PlainTextEditorViewAction as EditorAction, PropagateAndNoOpNavigationKeys, TextOptions,
|
||||
TextStyleOperation,
|
||||
};
|
||||
use crate::menu::{Event, Menu, MenuItem, MenuItemFields};
|
||||
use crate::network::NetworkStatus;
|
||||
use crate::server::cloud_objects::update_manager::UpdateManager;
|
||||
use crate::server::ids::{ClientId, ServerId, SyncId};
|
||||
use crate::server::server_api::ai::AIClient;
|
||||
use crate::themes::theme::AnsiColorIdentifier;
|
||||
use crate::ui_components::blended_colors;
|
||||
use crate::ui_components::breadcrumb::{self, BreadcrumbState};
|
||||
use crate::ui_components::buttons::icon_button;
|
||||
use crate::ui_components::dialog::{dialog_styles, Dialog};
|
||||
use crate::ui_components::icons::{self, Icon, ICON_DIMENSIONS};
|
||||
use crate::ui_components::menu_button::{icon_button_with_context_menu, MenuDirection};
|
||||
use crate::workflows::workflow::{Argument, Workflow};
|
||||
use crate::workflows::CloudWorkflow;
|
||||
|
||||
const BREADCRUMBS_VERTICAL_MARGIN: f32 = 6.;
|
||||
const MODAL_WIDTH: f32 = 900.;
|
||||
@@ -1947,5 +1931,5 @@ impl TypedActionView for WorkflowModal {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "modal_test.rs"]
|
||||
#[path = "modal_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxyui::{platform::WindowStyle, App, SingletonEntity, ViewHandle};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use warpui::platform::WindowStyle;
|
||||
use warpui::{App, SingletonEntity, ViewHandle};
|
||||
|
||||
use super::WorkflowModal;
|
||||
use crate::auth::AuthStateProvider;
|
||||
use crate::{
|
||||
cloud_object::model::persistence::CloudModel,
|
||||
editor::PlainTextEditorViewAction as EditorAction,
|
||||
server::server_api::team::MockTeamClient,
|
||||
server::server_api::workspace::MockWorkspaceClient,
|
||||
server::server_api::ServerApiProvider,
|
||||
settings_view::keybindings::KeybindingChangedNotifier,
|
||||
test_util::settings::initialize_settings_for_tests,
|
||||
workflows::workflow::{Argument, Workflow},
|
||||
UserWorkspaces,
|
||||
};
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::editor::PlainTextEditorViewAction as EditorAction;
|
||||
use crate::server::server_api::team::MockTeamClient;
|
||||
use crate::server::server_api::workspace::MockWorkspaceClient;
|
||||
use crate::server::server_api::ServerApiProvider;
|
||||
use crate::settings_view::keybindings::KeybindingChangedNotifier;
|
||||
use crate::test_util::settings::initialize_settings_for_tests;
|
||||
use crate::workflows::workflow::{Argument, Workflow};
|
||||
use crate::UserWorkspaces;
|
||||
|
||||
fn initialize_app(app: &mut App) {
|
||||
initialize_settings_for_tests(app);
|
||||
@@ -1,49 +1,39 @@
|
||||
use galaxy_core::ui::{appearance::Appearance, theme::Fill};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use itertools::Itertools;
|
||||
use strum::IntoEnumIterator;
|
||||
use strum_macros::{EnumIter, IntoStaticStr};
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_core::ui::theme::Fill;
|
||||
use galaxy_editor::editor::NavigationKey;
|
||||
use galaxyui::elements::{
|
||||
Align, Border, ChildAnchor, ChildView, ClippedScrollStateHandle, ClippedScrollable,
|
||||
ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Dismiss, Empty, EventHandler,
|
||||
Flex, Hoverable, MainAxisSize, MouseStateHandle, OffsetPositioning, ParentAnchor,
|
||||
ParentElement, ParentOffsetBounds, Radius, ScrollbarWidth, Shrinkable, Stack, Text,
|
||||
};
|
||||
use galaxyui::fonts::FamilyId;
|
||||
use galaxyui::geometry::vector::vec2f;
|
||||
use galaxyui::platform::Cursor;
|
||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
use galaxyui::ui_components::text::Span;
|
||||
use galaxyui::ui_components::toggle_menu::{ToggleMenuItem, ToggleMenuStateHandle};
|
||||
use galaxyui::{
|
||||
elements::{
|
||||
Align, Border, ChildAnchor, ChildView, ClippedScrollStateHandle, ClippedScrollable,
|
||||
ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Dismiss, Empty, EventHandler,
|
||||
Flex, Hoverable, MainAxisSize, MouseStateHandle, OffsetPositioning, ParentElement, Radius,
|
||||
ScrollbarWidth, Shrinkable, Stack, Text,
|
||||
},
|
||||
geometry::vector::vec2f,
|
||||
ui_components::{
|
||||
components::{Coords, UiComponent, UiComponentStyles},
|
||||
text::Span,
|
||||
toggle_menu::{ToggleMenuItem, ToggleMenuStateHandle},
|
||||
},
|
||||
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
ViewHandle,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use std::{collections::HashMap, rc::Rc};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::{
|
||||
editor::{
|
||||
EditorOptions, EditorView, EnterSettings, Event as EditorEvent, InteractionState,
|
||||
PropagateAndNoOpNavigationKeys, TextOptions,
|
||||
},
|
||||
server::ids::SyncId,
|
||||
ui_components::{
|
||||
buttons::{highlight, icon_button},
|
||||
icons::{self, Icon},
|
||||
},
|
||||
workflows::workflow::ArgumentType,
|
||||
};
|
||||
|
||||
use galaxyui::platform::Cursor;
|
||||
|
||||
use galaxyui::{
|
||||
elements::{ParentAnchor, ParentOffsetBounds},
|
||||
fonts::FamilyId,
|
||||
};
|
||||
|
||||
use crate::editor::EnterAction;
|
||||
use strum_macros::{EnumIter, IntoStaticStr};
|
||||
|
||||
use super::enum_creation_dialog::WorkflowEnumData;
|
||||
use crate::editor::{
|
||||
EditorOptions, EditorView, EnterAction, EnterSettings, Event as EditorEvent, InteractionState,
|
||||
PropagateAndNoOpNavigationKeys, TextOptions,
|
||||
};
|
||||
use crate::server::ids::SyncId;
|
||||
use crate::ui_components::buttons::{highlight, icon_button};
|
||||
use crate::ui_components::icons::{self, Icon};
|
||||
use crate::workflows::workflow::ArgumentType;
|
||||
|
||||
const ARGUMENT_DEFAULT_VALUE_PLACEHOLDER_TEXT: &str = "Default value (optional)";
|
||||
const ARGUMENT_EDITOR_FONT_SIZE: f32 = 14.;
|
||||
|
||||
@@ -2,20 +2,15 @@ use std::collections::HashMap;
|
||||
|
||||
use galaxyui::{AppContext, SingletonEntity, ViewHandle};
|
||||
|
||||
use crate::{
|
||||
cloud_object::{model::persistence::CloudModel, CloudObjectEventEntrypoint, Owner},
|
||||
editor::EditorView,
|
||||
server::{cloud_objects::update_manager::UpdateManager, ids::SyncId},
|
||||
workflows::{
|
||||
workflow::{Argument, ArgumentType},
|
||||
workflow_enum::WorkflowEnum,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{
|
||||
enum_creation_dialog::{EnumCreationDialog, WorkflowEnumData},
|
||||
workflow_arg_selector::WorkflowArgSelector,
|
||||
};
|
||||
use super::enum_creation_dialog::{EnumCreationDialog, WorkflowEnumData};
|
||||
use super::workflow_arg_selector::WorkflowArgSelector;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::{CloudObjectEventEntrypoint, Owner};
|
||||
use crate::editor::EditorView;
|
||||
use crate::server::cloud_objects::update_manager::UpdateManager;
|
||||
use crate::server::ids::SyncId;
|
||||
use crate::workflows::workflow::{Argument, ArgumentType};
|
||||
use crate::workflows::workflow_enum::WorkflowEnum;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArgumentEditorRowIndex(pub usize);
|
||||
|
||||
Reference in New Issue
Block a user