Add Rig native model providers
This commit is contained in:
@@ -1,32 +1,12 @@
|
||||
use std::env::current_dir;
|
||||
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxyui::App;
|
||||
|
||||
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() {
|
||||
App::test((), |mut app| async move {
|
||||
app.update(crate::settings::init_and_register_user_preferences);
|
||||
|
||||
let global_resource_handles = GlobalResourceHandles::mock(&mut app);
|
||||
app.add_singleton_model(|_| GlobalResourceHandlesProvider::new(global_resource_handles));
|
||||
app.add_singleton_model(CloudModel::mock);
|
||||
app.add_singleton_model(UserWorkspaces::default_mock);
|
||||
app.add_singleton_model(|_| Appearance::mock());
|
||||
app.add_singleton_model(|_| NetworkStatus::new());
|
||||
app.add_singleton_model(SyncQueue::mock);
|
||||
app.add_singleton_model(TeamTesterStatus::mock);
|
||||
app.add_singleton_model(UpdateManager::mock);
|
||||
|
||||
App::test((), |_| async move {
|
||||
let directory = current_dir()
|
||||
.expect("current directory should exist")
|
||||
.parent()
|
||||
|
||||
@@ -18,6 +18,7 @@ use super::modal_body::{ImportModalBody, ImportModalBodyAction, ImportModalBodyE
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::cloud_object::{CloudObject, Owner};
|
||||
use crate::local_object_repository::local_owner;
|
||||
use crate::server::ids::SyncId;
|
||||
use crate::server::sync_queue::SyncQueue;
|
||||
use crate::themes::theme::GalaxyTheme;
|
||||
@@ -88,7 +89,8 @@ impl ImportModal {
|
||||
let window_id = ctx.window_id();
|
||||
let import_body_id = self.import_modal.id();
|
||||
|
||||
let sync_queue_is_dequeueing = SyncQueue::as_ref(ctx).is_dequeueing();
|
||||
let sync_queue_is_dequeueing =
|
||||
self.owner != Some(local_owner()) && SyncQueue::as_ref(ctx).is_dequeueing();
|
||||
|
||||
let allowed_file_types = vec![FileType::Yaml, FileType::Markdown];
|
||||
|
||||
@@ -98,7 +100,7 @@ impl ImportModal {
|
||||
|
||||
// Files under a folder could only be uploaded when the folder is created on the server.
|
||||
// When sync queue is not dequeueing, disable folder upload in the import modal.
|
||||
if sync_queue_is_dequeueing {
|
||||
if sync_queue_is_dequeueing || self.owner == Some(local_owner()) {
|
||||
file_picker_config = file_picker_config.allow_folder();
|
||||
}
|
||||
|
||||
@@ -165,9 +167,13 @@ impl ImportModal {
|
||||
// Convert to a Space for display, in case we're importing into a shared folder.
|
||||
self.owner
|
||||
.map(|owner| {
|
||||
UserWorkspaces::as_ref(app)
|
||||
.owner_to_space(owner, app)
|
||||
.name(app)
|
||||
if owner == local_owner() {
|
||||
"Personal".to_string()
|
||||
} else {
|
||||
UserWorkspaces::as_ref(app)
|
||||
.owner_to_space(owner, app)
|
||||
.name(app)
|
||||
}
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
0,
|
||||
|
||||
@@ -21,6 +21,7 @@ use super::nodes::{
|
||||
use super::queue::{ImportQueue, ImportQueueArgs, ImportQueueEvent, ParentId, RequestContent};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::cloud_object::Owner;
|
||||
use crate::local_object_repository::local_owner;
|
||||
use crate::server::ids::{ClientId, SyncId};
|
||||
use crate::server::sync_queue::SyncQueue;
|
||||
use crate::ui_components::icons::Icon;
|
||||
@@ -96,7 +97,7 @@ pub struct ImportModalBody {
|
||||
|
||||
impl ImportModalBody {
|
||||
pub fn new(ctx: &mut ViewContext<Self>) -> Self {
|
||||
let import_queue = ctx.add_model(ImportQueue::new);
|
||||
let import_queue = ctx.add_model(|_| ImportQueue::new());
|
||||
ctx.subscribe_to_model(&import_queue, |me, _, event, ctx| {
|
||||
me.handle_import_queue_event(event, ctx)
|
||||
});
|
||||
@@ -152,7 +153,8 @@ impl ImportModalBody {
|
||||
}
|
||||
}
|
||||
|
||||
let sync_queue_dequeueing = SyncQueue::as_ref(ctx).is_dequeueing();
|
||||
let sync_queue_dequeueing =
|
||||
self.owner != Some(local_owner()) && SyncQueue::as_ref(ctx).is_dequeueing();
|
||||
|
||||
if !sync_queue_dequeueing && state.all_files_saved_locally() {
|
||||
ctx.emit(ImportModalBodyEvent::AllFileSavedLocally);
|
||||
@@ -177,7 +179,8 @@ impl ImportModalBody {
|
||||
// Whether there is an active upload in progress (If all uploads are completed,
|
||||
// we don't consider the import modal upload to be in progress).
|
||||
pub fn upload_in_progress(&self, app: &AppContext) -> bool {
|
||||
let sync_queue_dequeueing = SyncQueue::as_ref(app).is_dequeueing();
|
||||
let sync_queue_dequeueing =
|
||||
self.owner != Some(local_owner()) && SyncQueue::as_ref(app).is_dequeueing();
|
||||
|
||||
match &self.state {
|
||||
ImportState::Upload => false,
|
||||
@@ -498,7 +501,8 @@ impl View for ImportModalBody {
|
||||
}
|
||||
|
||||
fn render(&self, app: &AppContext) -> Box<dyn Element> {
|
||||
let sync_queue_dequeueing = SyncQueue::as_ref(app).is_dequeueing();
|
||||
let sync_queue_dequeueing =
|
||||
self.owner != Some(local_owner()) && SyncQueue::as_ref(app).is_dequeueing();
|
||||
let appearance = Appearance::as_ref(app);
|
||||
|
||||
match &self.state {
|
||||
|
||||
+165
-77
@@ -5,7 +5,7 @@ use galaxyui::{Entity, ModelContext, SingletonEntity};
|
||||
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::local_object_repository::{local_owner, LocalObjectRepository};
|
||||
use crate::notebooks::CloudNotebookModel;
|
||||
use crate::server::cloud_objects::update_manager::{
|
||||
InitiatedBy, ObjectOperation, OperationSuccessType, UpdateManager, UpdateManagerEvent,
|
||||
@@ -94,31 +94,40 @@ impl FileCompletionCounter {
|
||||
|
||||
pub(super) struct ImportQueue {
|
||||
queue: Vec<ImportQueueArgs>,
|
||||
client_to_server_id: HashMap<ClientId, Option<FolderId>>,
|
||||
client_to_folder_id: HashMap<ClientId, Option<SyncId>>,
|
||||
client_to_node_folder_id: HashMap<ClientId, nodes::FolderId>,
|
||||
file_completion: FileCompletionCounter,
|
||||
remote_subscription_initialized: bool,
|
||||
}
|
||||
|
||||
impl ImportQueue {
|
||||
pub fn new(ctx: &mut ModelContext<Self>) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
queue: Vec::new(),
|
||||
client_to_folder_id: HashMap::default(),
|
||||
file_completion: Default::default(),
|
||||
client_to_node_folder_id: HashMap::default(),
|
||||
remote_subscription_initialized: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_remote_subscription(&mut self, ctx: &mut ModelContext<Self>) {
|
||||
if self.remote_subscription_initialized {
|
||||
return;
|
||||
}
|
||||
|
||||
let update_manager = UpdateManager::handle(ctx);
|
||||
ctx.subscribe_to_model(&update_manager, |me, _, event, ctx| {
|
||||
me.handle_update_manager_event(event, ctx);
|
||||
});
|
||||
|
||||
Self {
|
||||
queue: Vec::new(),
|
||||
client_to_server_id: HashMap::default(),
|
||||
file_completion: Default::default(),
|
||||
client_to_node_folder_id: HashMap::default(),
|
||||
}
|
||||
self.remote_subscription_initialized = true;
|
||||
}
|
||||
|
||||
// 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
|
||||
.client_to_server_id
|
||||
.client_to_folder_id
|
||||
.get(id)
|
||||
.map(|item| item.is_some())
|
||||
.unwrap_or(false),
|
||||
@@ -128,6 +137,11 @@ impl ImportQueue {
|
||||
|
||||
// Enqueue a new request to the import queue.
|
||||
pub fn enqueue(&mut self, arg: ImportQueueArgs, ctx: &mut ModelContext<Self>) {
|
||||
let is_local = arg.owner == local_owner();
|
||||
if !is_local {
|
||||
self.ensure_remote_subscription(ctx);
|
||||
}
|
||||
|
||||
// Update internal tracker of the object.
|
||||
match &arg.content {
|
||||
RequestContent::Folder {
|
||||
@@ -135,17 +149,23 @@ impl ImportQueue {
|
||||
folder_id,
|
||||
..
|
||||
} => {
|
||||
self.client_to_server_id.insert(*client_id, None);
|
||||
self.client_to_folder_id.insert(*client_id, None);
|
||||
self.client_to_node_folder_id.insert(*client_id, *folder_id);
|
||||
}
|
||||
RequestContent::Notebook {
|
||||
client_id, file_id, ..
|
||||
} => self.file_completion.add_entry(*client_id, *file_id),
|
||||
} => {
|
||||
if !is_local {
|
||||
self.file_completion.add_entry(*client_id, *file_id);
|
||||
}
|
||||
}
|
||||
RequestContent::Workflow {
|
||||
workflows, file_id, ..
|
||||
} => {
|
||||
for (_, client_id) in workflows {
|
||||
self.file_completion.add_entry(*client_id, *file_id);
|
||||
if !is_local {
|
||||
for (_, client_id) in workflows {
|
||||
self.file_completion.add_entry(*client_id, *file_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,31 +187,47 @@ impl ImportQueue {
|
||||
{
|
||||
let dequeued_item = self.queue.remove(idx);
|
||||
let parent_id = match dequeued_item.parent_id {
|
||||
ParentId::FolderToUpload(client_id) => Some(SyncId::ServerId(
|
||||
self.client_to_server_id
|
||||
ParentId::FolderToUpload(client_id) => Some(
|
||||
self.client_to_folder_id
|
||||
.get(&client_id)
|
||||
.expect("Client id entry should exist")
|
||||
.expect("Server id entry should exist")
|
||||
.into(),
|
||||
)),
|
||||
.expect("Folder id entry should exist"),
|
||||
),
|
||||
ParentId::InitialFolder(folder_id) => folder_id,
|
||||
};
|
||||
|
||||
let is_local = dequeued_item.owner == local_owner();
|
||||
match dequeued_item.content {
|
||||
RequestContent::Folder {
|
||||
name, client_id, ..
|
||||
} => {
|
||||
UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| {
|
||||
update_manager.create_folder(
|
||||
name,
|
||||
dequeued_item.owner,
|
||||
client_id,
|
||||
parent_id,
|
||||
false,
|
||||
InitiatedBy::User,
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
if is_local {
|
||||
let local_id = SyncId::ClientId(client_id);
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.create_folder_with_id(local_id, name, parent_id, ctx);
|
||||
});
|
||||
self.client_to_folder_id.insert(client_id, Some(local_id));
|
||||
ctx.emit(ImportQueueEvent::FolderCompleted {
|
||||
folder_id: self
|
||||
.client_to_node_folder_id
|
||||
.get(&client_id)
|
||||
.copied()
|
||||
.expect("Folder node id should exist"),
|
||||
server_id: Some(local_id.uid()),
|
||||
});
|
||||
} else {
|
||||
UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| {
|
||||
update_manager.create_folder(
|
||||
name,
|
||||
dequeued_item.owner,
|
||||
client_id,
|
||||
parent_id,
|
||||
false,
|
||||
InitiatedBy::User,
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
RequestContent::Notebook {
|
||||
title,
|
||||
@@ -199,56 +235,104 @@ impl ImportQueue {
|
||||
client_id,
|
||||
file_id,
|
||||
} => {
|
||||
UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| {
|
||||
update_manager.create_notebook(
|
||||
client_id,
|
||||
dequeued_item.owner,
|
||||
parent_id,
|
||||
CloudNotebookModel {
|
||||
title,
|
||||
data,
|
||||
ai_document_id: None,
|
||||
conversation_id: None,
|
||||
},
|
||||
CloudObjectEventEntrypoint::ImportModal,
|
||||
false,
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
ctx.emit(ImportQueueEvent::FileSavedLocally(file_id));
|
||||
if is_local {
|
||||
let local_id = SyncId::ClientId(client_id);
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.create_notebook_with_id(
|
||||
local_id,
|
||||
parent_id,
|
||||
CloudNotebookModel {
|
||||
title,
|
||||
data,
|
||||
ai_document_id: None,
|
||||
conversation_id: None,
|
||||
},
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
ctx.emit(ImportQueueEvent::FileCompleted {
|
||||
file_id,
|
||||
server_id: Some(local_id.uid()),
|
||||
});
|
||||
} else {
|
||||
UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| {
|
||||
update_manager.create_notebook(
|
||||
client_id,
|
||||
dequeued_item.owner,
|
||||
parent_id,
|
||||
CloudNotebookModel {
|
||||
title,
|
||||
data,
|
||||
ai_document_id: None,
|
||||
conversation_id: None,
|
||||
},
|
||||
CloudObjectEventEntrypoint::ImportModal,
|
||||
false,
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
ctx.emit(ImportQueueEvent::FileSavedLocally(file_id));
|
||||
}
|
||||
}
|
||||
RequestContent::Workflow {
|
||||
workflows,
|
||||
workflow_enums,
|
||||
file_id,
|
||||
} => {
|
||||
UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| {
|
||||
// Create any new workflow enums
|
||||
for (client_id, workflow_enum) in workflow_enums {
|
||||
update_manager.create_workflow_enum(
|
||||
workflow_enum,
|
||||
dequeued_item.owner,
|
||||
client_id,
|
||||
CloudObjectEventEntrypoint::ImportModal,
|
||||
false,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
if is_local {
|
||||
let local_object_id = workflows
|
||||
.first()
|
||||
.map(|(_, client_id)| SyncId::ClientId(*client_id).uid());
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
for (client_id, workflow_enum) in workflow_enums {
|
||||
repository.create_workflow_enum_with_id(
|
||||
SyncId::ClientId(client_id),
|
||||
workflow_enum,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
for (workflow, client_id) in workflows {
|
||||
repository.create_workflow_with_id(
|
||||
SyncId::ClientId(client_id),
|
||||
parent_id,
|
||||
workflow,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
});
|
||||
ctx.emit(ImportQueueEvent::FileCompleted {
|
||||
file_id,
|
||||
server_id: local_object_id,
|
||||
});
|
||||
} else {
|
||||
UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| {
|
||||
// Create any new workflow enums
|
||||
for (client_id, workflow_enum) in workflow_enums {
|
||||
update_manager.create_workflow_enum(
|
||||
workflow_enum,
|
||||
dequeued_item.owner,
|
||||
client_id,
|
||||
CloudObjectEventEntrypoint::ImportModal,
|
||||
false,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
|
||||
// Create the workflow
|
||||
for (workflow, client_id) in workflows {
|
||||
update_manager.create_workflow(
|
||||
workflow,
|
||||
dequeued_item.owner,
|
||||
parent_id,
|
||||
client_id,
|
||||
CloudObjectEventEntrypoint::ImportModal,
|
||||
false,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
});
|
||||
ctx.emit(ImportQueueEvent::FileSavedLocally(file_id));
|
||||
// Create the workflow
|
||||
for (workflow, client_id) in workflows {
|
||||
update_manager.create_workflow(
|
||||
workflow,
|
||||
dequeued_item.owner,
|
||||
parent_id,
|
||||
client_id,
|
||||
CloudObjectEventEntrypoint::ImportModal,
|
||||
false,
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
});
|
||||
ctx.emit(ImportQueueEvent::FileSavedLocally(file_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.dequeue(ctx);
|
||||
@@ -294,14 +378,14 @@ impl ImportQueue {
|
||||
|
||||
let Some(folder_id) = cloud_model
|
||||
.get_folder_by_uid(&result.server_id.expect("Expect id").uid())
|
||||
.and_then(|folder| folder.id.into_server())
|
||||
.map(|folder| folder.id)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let replaced = match self.client_to_server_id.get_mut(&client_id) {
|
||||
let replaced = match self.client_to_folder_id.get_mut(&client_id) {
|
||||
Some(value) if value.is_none() => {
|
||||
*value = Some(folder_id.into());
|
||||
*value = Some(folder_id);
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
@@ -323,3 +407,7 @@ impl ImportQueue {
|
||||
impl Entity for ImportQueue {
|
||||
type Event = ImportQueueEvent;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "queue_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use galaxyui::{App, SingletonEntity};
|
||||
|
||||
use super::*;
|
||||
use crate::cloud_object::model::persistence::CloudModel;
|
||||
use crate::local_object_repository::local_owner;
|
||||
use crate::server::ids::ClientId;
|
||||
use crate::workflows::workflow_enum::{EnumVariants, WorkflowEnum};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum EventKind {
|
||||
Folder {
|
||||
folder_id: nodes::FolderId,
|
||||
object_id: Option<String>,
|
||||
},
|
||||
File {
|
||||
file_id: FileId,
|
||||
object_id: Option<String>,
|
||||
},
|
||||
FileSavedLocally(FileId),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_import_queue_persists_nested_content_and_reports_completion() {
|
||||
App::test((), |mut app| async move {
|
||||
app.add_singleton_model(|_| CloudModel::new(None, Vec::new(), None));
|
||||
app.add_singleton_model(|ctx| {
|
||||
crate::local_object_repository::LocalObjectRepository::new(None, None, ctx)
|
||||
});
|
||||
|
||||
let queue = app.add_model(|_| ImportQueue::new());
|
||||
let events = Rc::new(RefCell::new(Vec::new()));
|
||||
let events_for_subscription = events.clone();
|
||||
app.update(|ctx| {
|
||||
ctx.subscribe_to_model(&queue, move |_, event: &ImportQueueEvent, _| {
|
||||
let event = match event {
|
||||
ImportQueueEvent::FolderCompleted {
|
||||
folder_id,
|
||||
server_id,
|
||||
} => EventKind::Folder {
|
||||
folder_id: *folder_id,
|
||||
object_id: server_id.clone(),
|
||||
},
|
||||
ImportQueueEvent::FileCompleted { file_id, server_id } => EventKind::File {
|
||||
file_id: *file_id,
|
||||
object_id: server_id.clone(),
|
||||
},
|
||||
ImportQueueEvent::FileSavedLocally(file_id) => {
|
||||
EventKind::FileSavedLocally(*file_id)
|
||||
}
|
||||
};
|
||||
events_for_subscription.borrow_mut().push(event);
|
||||
});
|
||||
});
|
||||
|
||||
let parent_client_id = ClientId::new();
|
||||
let child_client_id = ClientId::new();
|
||||
let notebook_client_id = ClientId::new();
|
||||
let workflow_client_id = ClientId::new();
|
||||
let workflow_enum_client_id = ClientId::new();
|
||||
|
||||
queue.update(&mut app, |queue, ctx| {
|
||||
queue.enqueue(
|
||||
ImportQueueArgs {
|
||||
owner: local_owner(),
|
||||
parent_id: ParentId::InitialFolder(None),
|
||||
content: RequestContent::Folder {
|
||||
name: "Imported".to_string(),
|
||||
client_id: parent_client_id,
|
||||
folder_id: nodes::FolderId::from(1),
|
||||
},
|
||||
},
|
||||
ctx,
|
||||
);
|
||||
queue.enqueue(
|
||||
ImportQueueArgs {
|
||||
owner: local_owner(),
|
||||
parent_id: ParentId::FolderToUpload(parent_client_id),
|
||||
content: RequestContent::Folder {
|
||||
name: "Nested".to_string(),
|
||||
client_id: child_client_id,
|
||||
folder_id: nodes::FolderId::from(2),
|
||||
},
|
||||
},
|
||||
ctx,
|
||||
);
|
||||
queue.enqueue(
|
||||
ImportQueueArgs {
|
||||
owner: local_owner(),
|
||||
parent_id: ParentId::FolderToUpload(child_client_id),
|
||||
content: RequestContent::Notebook {
|
||||
title: "Imported notes".to_string(),
|
||||
data: "hello".to_string(),
|
||||
client_id: notebook_client_id,
|
||||
file_id: FileId(0),
|
||||
},
|
||||
},
|
||||
ctx,
|
||||
);
|
||||
queue.enqueue(
|
||||
ImportQueueArgs {
|
||||
owner: local_owner(),
|
||||
parent_id: ParentId::FolderToUpload(child_client_id),
|
||||
content: RequestContent::Workflow {
|
||||
workflows: vec![(
|
||||
crate::workflows::workflow::Workflow::new(
|
||||
"Imported workflow",
|
||||
"echo imported",
|
||||
),
|
||||
workflow_client_id,
|
||||
)],
|
||||
workflow_enums: HashMap::from([(
|
||||
workflow_enum_client_id,
|
||||
WorkflowEnum {
|
||||
name: "Environment".to_string(),
|
||||
is_shared: false,
|
||||
variants: EnumVariants::Static(vec!["dev".to_string()]),
|
||||
},
|
||||
)]),
|
||||
file_id: FileId(1),
|
||||
},
|
||||
},
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
|
||||
let parent_id = SyncId::ClientId(parent_client_id);
|
||||
let child_id = SyncId::ClientId(child_client_id);
|
||||
let notebook_id = SyncId::ClientId(notebook_client_id);
|
||||
let workflow_id = SyncId::ClientId(workflow_client_id);
|
||||
let workflow_enum_id = SyncId::ClientId(workflow_enum_client_id);
|
||||
|
||||
app.update(|ctx| {
|
||||
let cloud_model = CloudModel::as_ref(ctx);
|
||||
let parent = cloud_model.get_folder(&parent_id).expect("parent folder");
|
||||
assert_eq!(parent.permissions.owner, local_owner());
|
||||
assert_eq!(
|
||||
cloud_model
|
||||
.get_folder(&child_id)
|
||||
.unwrap()
|
||||
.metadata
|
||||
.folder_id,
|
||||
Some(parent_id)
|
||||
);
|
||||
assert_eq!(
|
||||
cloud_model
|
||||
.get_notebook(¬ebook_id)
|
||||
.unwrap()
|
||||
.metadata
|
||||
.folder_id,
|
||||
Some(child_id)
|
||||
);
|
||||
assert_eq!(
|
||||
cloud_model
|
||||
.get_workflow(&workflow_id)
|
||||
.unwrap()
|
||||
.metadata
|
||||
.folder_id,
|
||||
Some(child_id)
|
||||
);
|
||||
assert_eq!(
|
||||
cloud_model
|
||||
.get_workflow_enum(&workflow_enum_id)
|
||||
.unwrap()
|
||||
.model()
|
||||
.string_model
|
||||
.name,
|
||||
"Environment"
|
||||
);
|
||||
});
|
||||
|
||||
let events = events.borrow();
|
||||
assert!(events.contains(&EventKind::Folder {
|
||||
folder_id: nodes::FolderId::from(1),
|
||||
object_id: Some(parent_id.uid()),
|
||||
}));
|
||||
assert!(events.contains(&EventKind::Folder {
|
||||
folder_id: nodes::FolderId::from(2),
|
||||
object_id: Some(child_id.uid()),
|
||||
}));
|
||||
assert!(events.contains(&EventKind::File {
|
||||
file_id: FileId(0),
|
||||
object_id: Some(notebook_id.uid()),
|
||||
}));
|
||||
assert!(events.contains(&EventKind::File {
|
||||
file_id: FileId(1),
|
||||
object_id: Some(workflow_id.uid()),
|
||||
}));
|
||||
});
|
||||
}
|
||||
+100
-21
@@ -68,7 +68,7 @@ use crate::drive::panel::DrivePanelAction;
|
||||
use crate::editor::{EditorView, Event as EditorEvent, SingleLineEditorOptions};
|
||||
use crate::env_vars::CloudEnvVarCollection;
|
||||
use crate::features::FeatureFlag;
|
||||
use crate::local_object_repository::LocalObjectRepository;
|
||||
use crate::local_object_repository::{local_owner, LocalObjectRepository};
|
||||
use crate::menu::{Event, Menu, MenuItem, MenuItemFields};
|
||||
use crate::network::NetworkStatus;
|
||||
use crate::notebooks::CloudNotebookModel;
|
||||
@@ -1064,6 +1064,12 @@ impl DriveIndex {
|
||||
NetworkStatus::as_ref(app).is_online()
|
||||
}
|
||||
|
||||
fn is_local_folder(folder_id: &SyncId, app: &AppContext) -> bool {
|
||||
CloudModel::as_ref(app)
|
||||
.get_folder(folder_id)
|
||||
.is_some_and(|folder| folder.permissions.owner == local_owner())
|
||||
}
|
||||
|
||||
pub fn scroll_item_into_view(&mut self, item_id: WarpDriveItemId, ctx: &mut ViewContext<Self>) {
|
||||
self.clipped_scroll_state.scroll_to_position(ScrollTarget {
|
||||
position_id: item_id.drive_row_position_id(),
|
||||
@@ -3330,9 +3336,15 @@ impl DriveIndex {
|
||||
match new_location {
|
||||
CloudObjectLocation::Space(space) => self.open_section_of_space(space),
|
||||
CloudObjectLocation::Folder(folder_id) => {
|
||||
cloud_model.update(ctx, |cloud_model, ctx| {
|
||||
cloud_model.open_folder(folder_id, ctx);
|
||||
});
|
||||
if Self::is_local_folder(&folder_id, ctx) {
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.open_folder(folder_id, ctx);
|
||||
});
|
||||
} else {
|
||||
cloud_model.update(ctx, |cloud_model, ctx| {
|
||||
cloud_model.open_folder(folder_id, ctx);
|
||||
});
|
||||
}
|
||||
}
|
||||
// If location is the trash, then the above move_[object]_to_location call already trashed the object
|
||||
CloudObjectLocation::Trash => {}
|
||||
@@ -3508,9 +3520,15 @@ impl DriveIndex {
|
||||
if !new_name.is_empty() {
|
||||
self.reset_menus(ctx);
|
||||
|
||||
UpdateManager::handle(ctx).update(ctx, move |update_manager, ctx| {
|
||||
update_manager.rename_folder(folder_id, new_name, ctx);
|
||||
});
|
||||
if Self::is_local_folder(&folder_id, ctx) {
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.update_folder_name(folder_id, new_name, ctx);
|
||||
});
|
||||
} else {
|
||||
UpdateManager::handle(ctx).update(ctx, move |update_manager, ctx| {
|
||||
update_manager.rename_folder(folder_id, new_name, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
self.cloud_object_naming_dialog.close(ctx);
|
||||
ctx.notify();
|
||||
@@ -3542,6 +3560,11 @@ impl DriveIndex {
|
||||
repository.set_env_var_collection_trashed(id, true, ctx);
|
||||
});
|
||||
}
|
||||
CloudObjectTypeAndId::Folder(id) if Self::is_local_folder(&id, ctx) => {
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.set_folder_trashed(id, true, ctx);
|
||||
});
|
||||
}
|
||||
CloudObjectTypeAndId::Folder(_) | CloudObjectTypeAndId::GenericStringObject { .. } => {
|
||||
UpdateManager::handle(ctx).update(ctx, move |update_manager, ctx| {
|
||||
update_manager.trash_object(cloud_object_type_and_id, ctx);
|
||||
@@ -3585,6 +3608,14 @@ impl DriveIndex {
|
||||
ctx.notify();
|
||||
return;
|
||||
}
|
||||
CloudObjectTypeAndId::Folder(id) if Self::is_local_folder(id, ctx) => {
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.set_folder_trashed(*id, false, ctx);
|
||||
});
|
||||
self.reset_menus(ctx);
|
||||
ctx.notify();
|
||||
return;
|
||||
}
|
||||
CloudObjectTypeAndId::Folder(_) | CloudObjectTypeAndId::GenericStringObject { .. } => {}
|
||||
}
|
||||
|
||||
@@ -3736,6 +3767,11 @@ impl DriveIndex {
|
||||
repository.delete_env_var_collection(*id, ctx);
|
||||
});
|
||||
}
|
||||
CloudObjectTypeAndId::Folder(id) if Self::is_local_folder(id, ctx) => {
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.delete_folder(*id, ctx);
|
||||
});
|
||||
}
|
||||
CloudObjectTypeAndId::Folder(_) | CloudObjectTypeAndId::GenericStringObject { .. } => {
|
||||
UpdateManager::handle(ctx).update(ctx, move |update_manager, ctx| {
|
||||
update_manager.delete_object_by_user(*cloud_object_type_and_id, ctx);
|
||||
@@ -5088,14 +5124,35 @@ impl DriveIndex {
|
||||
}
|
||||
}
|
||||
CloudObjectTypeAndId::Folder(id) => {
|
||||
CloudModel::handle(ctx).update(ctx, |cloud_model, ctx| match key {
|
||||
DriveIndexAction::EnterKey => {
|
||||
cloud_model.toggle_folder_open(*id, ctx);
|
||||
}
|
||||
DriveIndexAction::LeftArrowKey => cloud_model.close_folder(*id, ctx),
|
||||
DriveIndexAction::RightArrowKey => cloud_model.open_folder(*id, ctx),
|
||||
_ => {}
|
||||
});
|
||||
if Self::is_local_folder(id, ctx) {
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
match key {
|
||||
DriveIndexAction::EnterKey => {
|
||||
repository.toggle_folder_open(*id, ctx);
|
||||
}
|
||||
DriveIndexAction::LeftArrowKey => {
|
||||
repository.close_folder(*id, ctx)
|
||||
}
|
||||
DriveIndexAction::RightArrowKey => {
|
||||
repository.open_folder(*id, ctx)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
CloudModel::handle(ctx).update(ctx, |cloud_model, ctx| match key {
|
||||
DriveIndexAction::EnterKey => {
|
||||
cloud_model.toggle_folder_open(*id, ctx);
|
||||
}
|
||||
DriveIndexAction::LeftArrowKey => {
|
||||
cloud_model.close_folder(*id, ctx)
|
||||
}
|
||||
DriveIndexAction::RightArrowKey => {
|
||||
cloud_model.open_folder(*id, ctx)
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
}
|
||||
CloudObjectTypeAndId::GenericStringObject { object_type, id: _ } => {
|
||||
if let GenericStringObjectFormat::Json(JsonObjectType::EnvVarCollection) =
|
||||
@@ -5556,14 +5613,36 @@ impl TypedActionView for DriveIndex {
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
CloudModel::handle(ctx).update(ctx, |cloud_model, ctx| {
|
||||
cloud_model.toggle_folder_open(*id, ctx);
|
||||
});
|
||||
if Self::is_local_folder(id, ctx) {
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.toggle_folder_open(*id, ctx);
|
||||
});
|
||||
} else {
|
||||
CloudModel::handle(ctx).update(ctx, |cloud_model, ctx| {
|
||||
cloud_model.toggle_folder_open(*id, ctx);
|
||||
});
|
||||
}
|
||||
}
|
||||
DriveIndexAction::CollapseAllInLocation(location) => {
|
||||
CloudModel::handle(ctx).update(ctx, |cloud_model, ctx| {
|
||||
cloud_model.collapse_all_in_location(*location, self.index_variant, ctx);
|
||||
});
|
||||
if let CloudObjectLocation::Folder(folder_id) = location {
|
||||
if Self::is_local_folder(folder_id, ctx) {
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.collapse_local_folders_in_location(*location, ctx);
|
||||
});
|
||||
} else {
|
||||
CloudModel::handle(ctx).update(ctx, |cloud_model, ctx| {
|
||||
cloud_model.collapse_all_in_location(
|
||||
*location,
|
||||
self.index_variant,
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
CloudModel::handle(ctx).update(ctx, |cloud_model, ctx| {
|
||||
cloud_model.collapse_all_in_location(*location, self.index_variant, ctx);
|
||||
});
|
||||
}
|
||||
}
|
||||
DriveIndexAction::TrashObject {
|
||||
cloud_object_type_and_id,
|
||||
|
||||
+22
-11
@@ -178,17 +178,28 @@ impl DrivePanel {
|
||||
} => match Self::new_object_owner(*space, initial_folder_id.as_ref(), ctx) {
|
||||
Some(owner) => {
|
||||
let client_id = ClientId::default();
|
||||
UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| {
|
||||
update_manager.create_folder(
|
||||
title.clone(),
|
||||
owner,
|
||||
client_id,
|
||||
*initial_folder_id,
|
||||
true,
|
||||
InitiatedBy::User,
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
if owner == local_owner() {
|
||||
LocalObjectRepository::handle(ctx).update(ctx, |repository, ctx| {
|
||||
repository.create_folder_with_id(
|
||||
SyncId::ClientId(client_id),
|
||||
title.clone(),
|
||||
*initial_folder_id,
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| {
|
||||
update_manager.create_folder(
|
||||
title.clone(),
|
||||
owner,
|
||||
client_id,
|
||||
*initial_folder_id,
|
||||
true,
|
||||
InitiatedBy::User,
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
None => {
|
||||
log::error!("Cannot identify a folder owner from {space:?}");
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use settings::macros::define_settings_group;
|
||||
use settings::{RespectUserSyncSetting, Setting, SupportedPlatforms, SyncToCloud};
|
||||
|
||||
@@ -37,14 +36,8 @@ define_settings_group!(WarpDriveSettings, settings: [
|
||||
|
||||
impl WarpDriveSettings {
|
||||
/// Returns whether Warp Drive should be considered enabled.
|
||||
/// Returns `false` when the user is anonymous or fully logged out,
|
||||
/// regardless of the user setting.
|
||||
pub fn is_warp_drive_enabled(app: &galaxyui::AppContext) -> bool {
|
||||
use galaxyui::SingletonEntity as _;
|
||||
let is_anonymous_or_logged_out = FeatureFlag::SkipFirebaseAnonymousUser.is_enabled()
|
||||
&& crate::auth::AuthStateProvider::as_ref(app)
|
||||
.get()
|
||||
.is_anonymous_or_logged_out();
|
||||
*Self::as_ref(app).enable_warp_drive && !is_anonymous_or_logged_out
|
||||
*Self::as_ref(app).enable_warp_drive
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user