fix: reorder view when sibling view was deleted (#2724)

* fix: reorder view when sibling view was deleted

* ci: fix test

* ci: rust fmt
This commit is contained in:
Nathan.fooo 2023-06-07 00:05:27 +08:00 committed by GitHub
parent e3eee76609
commit 381d2e6c71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 248 additions and 83 deletions

View File

@ -105,6 +105,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
}
Future<void> _createView(CreateView value, Emitter<AppState> emit) async {
// create a child view for the current view
final result = await ViewBackendService.createView(
parentViewId: state.view.id,
name: value.name,

View File

@ -34,12 +34,12 @@ default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]
[patch.crates-io]
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
#collab = { path = "../../AppFlowy-Collab/collab" }
#collab-folder = { path = "../../AppFlowy-Collab/collab-folder" }

View File

@ -85,7 +85,7 @@ checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
[[package]]
name = "appflowy-integrate"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"anyhow",
"collab",
@ -887,7 +887,7 @@ dependencies = [
[[package]]
name = "collab"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"anyhow",
"bytes",
@ -905,7 +905,7 @@ dependencies = [
[[package]]
name = "collab-client-ws"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"bytes",
"collab-sync",
@ -923,7 +923,7 @@ dependencies = [
[[package]]
name = "collab-database"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"anyhow",
"async-trait",
@ -949,7 +949,7 @@ dependencies = [
[[package]]
name = "collab-derive"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"proc-macro2",
"quote",
@ -961,7 +961,7 @@ dependencies = [
[[package]]
name = "collab-document"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"anyhow",
"collab",
@ -978,7 +978,7 @@ dependencies = [
[[package]]
name = "collab-folder"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"anyhow",
"collab",
@ -997,7 +997,7 @@ dependencies = [
[[package]]
name = "collab-persistence"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"bincode",
"chrono",
@ -1017,7 +1017,7 @@ dependencies = [
[[package]]
name = "collab-plugins"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"anyhow",
"async-trait",
@ -1048,7 +1048,7 @@ dependencies = [
[[package]]
name = "collab-sync"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5c519e#5c519e988e93f6fbc7d98ce4373c5ff30a547fb1"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a647d9#a647d922ef432510d6be0abb5f968d9a75dc7011"
dependencies = [
"bytes",
"collab",

View File

@ -33,11 +33,11 @@ opt-level = 3
incremental = false
[patch.crates-io]
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5c519e" }
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a647d9" }
#collab = { path = "../AppFlowy-Collab/collab" }
#collab-folder = { path = "../AppFlowy-Collab/collab-folder" }

View File

@ -25,7 +25,7 @@ impl SnapshotDB for SnapshotDBImpl {
.and_then(|pool| Ok(pool.get()?))
.and_then(|conn| {
CollabSnapshotTableSql::get_all_snapshots(object_id, &conn)
.and_then(|rows| Ok(rows.into_iter().map(|row| row.into()).collect()))
.map(|rows| rows.into_iter().map(|row| row.into()).collect())
})
.unwrap_or_else(|_| vec![])
}
@ -34,6 +34,8 @@ impl SnapshotDB for SnapshotDBImpl {
&self,
uid: i64,
object_id: &str,
title: String,
collab_type: String,
snapshot: Snapshot,
collab: Arc<MutexCollab>,
) -> Result<(), PersistenceError> {
@ -74,7 +76,9 @@ impl SnapshotDB for SnapshotDBImpl {
CollabSnapshotRow {
id: uuid::Uuid::new_v4().to_string(),
object_id: object_id.clone(),
title,
desc,
collab_type,
timestamp: timestamp(),
data: new_snapshot_data,
},
@ -97,7 +101,9 @@ impl SnapshotDB for SnapshotDBImpl {
struct CollabSnapshotRow {
id: String,
object_id: String,
title: String,
desc: String,
collab_type: String,
timestamp: i64,
data: Vec<u8>,
}
@ -118,7 +124,9 @@ impl CollabSnapshotTableSql {
let values = (
dsl::id.eq(row.id),
dsl::object_id.eq(row.object_id),
dsl::title.eq(row.title),
dsl::desc.eq(row.desc),
dsl::collab_type.eq(row.collab_type),
dsl::data.eq(row.data),
dsl::timestamp.eq(row.timestamp),
);

View File

@ -84,7 +84,6 @@ impl DatabaseManager2 {
self.get_database(&database_id).await
}
#[tracing::instrument(level = "debug", skip(self), err)]
pub async fn get_database_id_with_view_id(&self, view_id: &str) -> FlowyResult<String> {
let database_id = self.with_user_database(Err(FlowyError::internal()), |database| {
database

View File

@ -1,12 +1,15 @@
use crate::entities::parser::view::{ViewDesc, ViewIdentify, ViewName, ViewThumbnail};
use crate::view_operation::gen_view_id;
use collab_folder::core::{View, ViewLayout};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode;
use std::collections::HashMap;
use std::convert::TryInto;
use std::ops::{Deref, DerefMut};
use collab_folder::core::{View, ViewLayout};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode;
use crate::entities::parser::view::{ViewDesc, ViewIdentify, ViewName, ViewThumbnail};
use crate::view_operation::gen_view_id;
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct ViewPB {
#[pb(index = 1)]
@ -284,7 +287,7 @@ pub struct MoveViewPayloadPB {
}
pub struct MoveViewParams {
pub item_id: String,
pub view_id: String,
pub from: usize,
pub to: usize,
}
@ -295,7 +298,7 @@ impl TryInto<MoveViewParams> for MoveViewPayloadPB {
fn try_into(self) -> Result<MoveViewParams, Self::Error> {
let view_id = ViewIdentify::parse(self.view_id)?.0;
Ok(MoveViewParams {
item_id: view_id,
view_id,
from: self.from as usize,
to: self.to as usize,
})

View File

@ -72,8 +72,6 @@ pub async fn read_cur_workspace_setting_handler(
folder: AFPluginState<Arc<Folder2Manager>>,
) -> DataResult<WorkspaceSettingPB, FlowyError> {
let workspace = folder.get_current_workspace().await?;
let views = folder.get_workspace_views(&workspace.id).await?;
let workspace: WorkspacePB = (workspace, views).into();
let latest_view: Option<ViewPB> = folder.get_current_view().await;
data_result_ok(WorkspaceSettingPB {
workspace,
@ -149,7 +147,7 @@ pub(crate) async fn move_view_handler(
) -> Result<(), FlowyError> {
let params: MoveViewParams = data.into_inner().try_into()?;
folder
.move_view(&params.item_id, params.from, params.to)
.move_view(&params.view_id, params.from, params.to)
.await?;
Ok(())
}

View File

@ -19,7 +19,7 @@ use lib_infra::util::timestamp;
use crate::deps::{FolderCloudService, FolderUser};
use crate::entities::{
view_pb_with_child_views, CreateViewParams, CreateWorkspaceParams, DeletedViewPB,
RepeatedTrashPB, RepeatedViewPB, RepeatedWorkspacePB, UpdateViewParams, ViewPB,
RepeatedTrashPB, RepeatedViewPB, RepeatedWorkspacePB, UpdateViewParams, ViewPB, WorkspacePB,
};
use crate::notification::{
send_notification, send_workspace_notification, send_workspace_setting_notification,
@ -61,11 +61,17 @@ impl Folder2Manager {
Ok(manager)
}
pub async fn get_current_workspace(&self) -> FlowyResult<Workspace> {
match self.with_folder(None, |folder| folder.get_current_workspace()) {
None => Err(FlowyError::record_not_found().context("Can not find the workspace")),
Some(workspace) => Ok(workspace),
}
pub async fn get_current_workspace(&self) -> FlowyResult<WorkspacePB> {
self.with_folder(Err(FlowyError::internal()), |folder| {
match folder.get_current_workspace() {
None => Err(FlowyError::record_not_found().context("Can not find the workspace")),
Some(workspace) => {
let views = get_workspace_view_pbs(&workspace.id, folder);
let workspace: WorkspacePB = (workspace, views).into();
Ok(workspace)
},
}
})
}
/// Return a list of views of the current workspace.
@ -307,18 +313,48 @@ impl Folder2Manager {
Ok(())
}
/// Move the view from one position to another position.
#[tracing::instrument(level = "debug", skip(self), err)]
/// Move the view with given id from one position to another position.
/// The view will be moved to the new position in the same parent view.
/// The passed in index is the index of the view that displayed in the UI.
/// We need to convert the index to the real index of the view in the parent view.
#[tracing::instrument(level = "trace", skip(self), err)]
pub async fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> {
let view = self.with_folder(None, |folder| {
folder.move_view(view_id, from as u32, to as u32)
});
if let Some((is_workspace, parent_view_id, child_views)) = self.get_view_relation(view_id).await
{
// The display parent view is the view that is displayed in the UI
let display_views = if is_workspace {
self
.get_current_workspace()
.await?
.views
.into_iter()
.map(|view| view.id)
.collect::<Vec<_>>()
} else {
self
.get_view(&parent_view_id)
.await?
.child_views
.into_iter()
.map(|view| view.id)
.collect::<Vec<_>>()
};
match view {
None => tracing::error!("Couldn't find the view. It should not be empty"),
Some(view) => {
notify_parent_view_did_change(self.mutex_folder.clone(), vec![view.parent_view_id]);
},
if display_views.len() > to {
let to_view_id = display_views[to].clone();
// Find the actual index of the view in the parent view
let actual_from_index = child_views.iter().position(|id| id == view_id);
let actual_to_index = child_views.iter().position(|id| id == &to_view_id);
if let (Some(actual_from_index), Some(actual_to_index)) =
(actual_from_index, actual_to_index)
{
self.with_folder((), |folder| {
folder.move_view(view_id, actual_from_index as u32, actual_to_index as u32);
});
notify_parent_view_did_change(self.mutex_folder.clone(), vec![parent_view_id]);
}
}
}
Ok(())
}
@ -516,6 +552,40 @@ impl Folder2Manager {
Some(processor) => Ok(processor.clone()),
}
}
/// Returns the relation of the view. The relation is a tuple of (is_workspace, parent_view_id,
/// child_view_ids). If the view is a workspace, then the parent_view_id is the workspace id.
/// Otherwise, the parent_view_id is the parent view id of the view. The child_view_ids is the
/// child view ids of the view.
async fn get_view_relation(&self, view_id: &str) -> Option<(bool, String, Vec<String>)> {
self.with_folder(None, |folder| {
let view = folder.views.get_view(view_id)?;
match folder.views.get_view(&view.parent_view_id) {
None => folder.get_current_workspace().map(|workspace| {
(
true,
workspace.id,
workspace
.child_views
.items
.into_iter()
.map(|view| view.id)
.collect::<Vec<String>>(),
)
}),
Some(parent_view) => Some((
false,
parent_view.id,
parent_view
.children
.items
.into_iter()
.map(|view| view.id)
.collect::<Vec<String>>(),
)),
}
})
}
}
/// Listen on the [ViewChange] after create/delete/update events happened
@ -594,6 +664,7 @@ fn listen_on_trash_change(mut rx: TrashChangeReceiver, weak_mutex_folder: &Weak<
});
}
/// Return the views that belong to the workspace. The views are filtered by the trash.
fn get_workspace_view_pbs(workspace_id: &str, folder: &Folder) -> Vec<ViewPB> {
let trash_ids = folder
.trash

View File

@ -2,7 +2,9 @@
CREATE TABLE collab_snapshot (
id TEXT NOT NULL PRIMARY KEY DEFAULT '',
object_id TEXT NOT NULL DEFAULT '',
title TEXT NOT NULL DEFAULT '',
desc TEXT NOT NULL DEFAULT '',
collab_type TEXT NOT NULL DEFAULT '',
timestamp BIGINT NOT NULL DEFAULT 0,
data BLOB NOT NULL DEFAULT (x'')
);

View File

@ -4,7 +4,9 @@ diesel::table! {
collab_snapshot (id) {
id -> Text,
object_id -> Text,
title -> Text,
desc -> Text,
collab_type -> Text,
timestamp -> BigInt,
data -> Binary,
}

View File

@ -1,14 +1,18 @@
use nanoid::nanoid;
use parking_lot::RwLock;
use std::env::temp_dir;
use std::sync::Arc;
use crate::event_builder::EventBuilder;
use nanoid::nanoid;
use parking_lot::RwLock;
use flowy_core::{AppFlowyCore, AppFlowyCoreConfig};
use flowy_folder2::entities::{CreateViewPayloadPB, RepeatedViewIdPB, ViewPB, WorkspaceSettingPB};
use flowy_folder2::entities::{
CreateViewPayloadPB, RepeatedViewIdPB, ViewIdPB, ViewPB, WorkspaceSettingPB,
};
use flowy_user::entities::{AuthTypePB, UserProfilePB};
use crate::event_builder::EventBuilder;
use crate::user_event::{async_sign_up, init_user_setting, SignUpContext};
pub mod event_builder;
pub mod folder_event;
pub mod user_event;
@ -68,6 +72,15 @@ impl FlowyCoreTest {
.parse::<flowy_folder2::entities::WorkspaceSettingPB>()
}
pub async fn get_all_workspace_views(&self) -> Vec<ViewPB> {
EventBuilder::new(self.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadWorkspaceViews)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedViewPB>()
.items
}
pub async fn delete_view(&self, view_id: &str) {
let payload = RepeatedViewIdPB {
items: vec![view_id.to_string()],
@ -99,6 +112,17 @@ impl FlowyCoreTest {
.await
.parse::<flowy_folder2::entities::ViewPB>()
}
pub async fn get_view(&self, view_id: &str) -> ViewPB {
EventBuilder::new(self.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadView)
.payload(ViewIdPB {
value: view_id.to_string(),
})
.async_send()
.await
.parse::<flowy_folder2::entities::ViewPB>()
}
}
impl std::ops::Deref for FlowyCoreTest {

View File

@ -240,13 +240,7 @@ async fn multiple_hierarchy_view_test() {
}
}
let mut views = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadWorkspaceViews)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedViewPB>()
.items;
let mut views = test.get_all_workspace_views().await;
// There will be one default view when AppFlowy is initialized. So there will be 4 views in total
assert_eq!(views.len(), 4);
views.remove(0);
@ -294,15 +288,7 @@ async fn multiple_hierarchy_view_test() {
for (k, _child_view) in child_view.child_views.into_iter().enumerate() {
// Get the last level view
let sub_child = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadView)
.payload(ViewIdPB {
value: child.id.clone(),
})
.async_send()
.await
.parse::<flowy_folder2::entities::ViewPB>();
let sub_child = test.get_view(&child.id).await;
assert_eq!(child.name, format!("My {}-{}-{} view", i + 1, j + 1, k + 1));
assert!(sub_child.child_views.is_empty());
}
@ -324,13 +310,7 @@ async fn move_view_event_test() {
.await;
}
}
let views = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadWorkspaceViews)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedViewPB>()
.items;
let views = test.get_all_workspace_views().await;
// There will be one default view when AppFlowy is initialized. So there will be 4 views in total
assert_eq!(views.len(), 4);
assert_eq!(views[1].name, "My 1 view");
@ -348,18 +328,95 @@ async fn move_view_event_test() {
.async_send()
.await;
let views = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::ReadWorkspaceViews)
.async_send()
.await
.parse::<flowy_folder2::entities::RepeatedViewPB>()
.items;
let views = test.get_all_workspace_views().await;
assert_eq!(views[1].name, "My 2 view");
assert_eq!(views[2].name, "My 1 view");
assert_eq!(views[3].name, "My 3 view");
}
#[tokio::test]
async fn move_view_event_after_delete_view_test() {
let test = FlowyCoreTest::new_with_user().await;
let current_workspace = test.get_current_workspace().await.workspace;
for i in 1..6 {
let _ = test
.create_view(&current_workspace.id, format!("My {} view", i))
.await;
}
let views = test.get_all_workspace_views().await;
assert_eq!(views[1].name, "My 1 view");
assert_eq!(views[2].name, "My 2 view");
assert_eq!(views[3].name, "My 3 view");
assert_eq!(views[4].name, "My 4 view");
assert_eq!(views[5].name, "My 5 view");
test.delete_view(&views[3].id).await;
// There will be one default view when AppFlowy is initialized. So there will be 4 views in total
let views = test.get_all_workspace_views().await;
assert_eq!(views[1].name, "My 1 view");
assert_eq!(views[2].name, "My 2 view");
assert_eq!(views[3].name, "My 4 view");
assert_eq!(views[4].name, "My 5 view");
let payload = MoveViewPayloadPB {
view_id: views[1].id.clone(),
from: 1,
to: 3,
};
let _ = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::MoveView)
.payload(payload)
.async_send()
.await;
let views = test.get_all_workspace_views().await;
assert_eq!(views[1].name, "My 2 view");
assert_eq!(views[2].name, "My 4 view");
assert_eq!(views[3].name, "My 1 view");
assert_eq!(views[4].name, "My 5 view");
}
#[tokio::test]
async fn move_view_event_after_delete_view_test2() {
let test = FlowyCoreTest::new_with_user().await;
let current_workspace = test.get_current_workspace().await.workspace;
let parent = test
.create_view(&current_workspace.id, "My view".to_string())
.await;
for j in 1..6 {
let _ = test
.create_view(&parent.id, format!("My 1-{} view", j))
.await;
}
let views = test.get_view(&parent.id).await.child_views;
assert_eq!(views.len(), 5);
assert_eq!(views[0].name, "My 1-1 view");
assert_eq!(views[1].name, "My 1-2 view");
assert_eq!(views[2].name, "My 1-3 view");
assert_eq!(views[3].name, "My 1-4 view");
assert_eq!(views[4].name, "My 1-5 view");
test.delete_view(&views[2].id).await;
let payload = MoveViewPayloadPB {
view_id: views[0].id.clone(),
from: 0,
to: 2,
};
let _ = EventBuilder::new(test.clone())
.event(flowy_folder2::event_map::FolderEvent::MoveView)
.payload(payload)
.async_send()
.await;
let views = test.get_view(&parent.id).await.child_views;
assert_eq!(views[0].name, "My 1-2 view");
assert_eq!(views[1].name, "My 1-4 view");
assert_eq!(views[2].name, "My 1-1 view");
assert_eq!(views[3].name, "My 1-5 view");
}
#[tokio::test]
async fn create_parent_view_with_invalid_name() {
for (name, code) in invalid_workspace_name_test_case() {