document_event.rs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. use flowy_document2::entities::*;
  2. use flowy_document2::event_map::DocumentEvent;
  3. use flowy_folder2::entities::{CreateViewPayloadPB, ViewLayoutPB, ViewPB};
  4. use flowy_folder2::event_map::FolderEvent;
  5. use serde_json::Value;
  6. use std::collections::HashMap;
  7. use crate::document::utils::{gen_delta_str, gen_id, gen_text_block_data};
  8. use crate::event_builder::EventBuilder;
  9. use crate::FlowyCoreTest;
  10. const TEXT_BLOCK_TY: &str = "paragraph";
  11. pub struct DocumentEventTest {
  12. inner: FlowyCoreTest,
  13. }
  14. pub struct OpenDocumentData {
  15. pub id: String,
  16. pub data: DocumentDataPB,
  17. }
  18. impl DocumentEventTest {
  19. pub async fn new() -> Self {
  20. let sdk = FlowyCoreTest::new_with_guest_user().await;
  21. Self { inner: sdk }
  22. }
  23. pub fn new_with_core(core: FlowyCoreTest) -> Self {
  24. Self { inner: core }
  25. }
  26. pub async fn create_document(&self) -> ViewPB {
  27. let core = &self.inner;
  28. let current_workspace = core.get_current_workspace().await.workspace;
  29. let parent_id = current_workspace.id.clone();
  30. let payload = CreateViewPayloadPB {
  31. parent_view_id: parent_id.to_string(),
  32. name: "document".to_string(),
  33. desc: "".to_string(),
  34. thumbnail: None,
  35. layout: ViewLayoutPB::Document,
  36. initial_data: vec![],
  37. meta: Default::default(),
  38. set_as_current: true,
  39. index: None,
  40. };
  41. EventBuilder::new(core.clone())
  42. .event(FolderEvent::CreateView)
  43. .payload(payload)
  44. .async_send()
  45. .await
  46. .parse::<ViewPB>()
  47. }
  48. pub async fn open_document(&self, doc_id: String) -> OpenDocumentData {
  49. let core = &self.inner;
  50. let payload = OpenDocumentPayloadPB {
  51. document_id: doc_id.clone(),
  52. };
  53. let data = EventBuilder::new(core.clone())
  54. .event(DocumentEvent::OpenDocument)
  55. .payload(payload)
  56. .async_send()
  57. .await
  58. .parse::<DocumentDataPB>();
  59. OpenDocumentData { id: doc_id, data }
  60. }
  61. pub async fn get_block(&self, doc_id: &str, block_id: &str) -> Option<BlockPB> {
  62. let document = self.open_document(doc_id.to_string()).await;
  63. document.data.blocks.get(block_id).cloned()
  64. }
  65. pub async fn get_page_id(&self, doc_id: &str) -> String {
  66. let data = self.get_document_data(doc_id).await;
  67. data.page_id
  68. }
  69. pub async fn get_document_data(&self, doc_id: &str) -> DocumentDataPB {
  70. let document = self.open_document(doc_id.to_string()).await;
  71. document.data
  72. }
  73. pub async fn get_block_children(&self, doc_id: &str, block_id: &str) -> Option<Vec<String>> {
  74. let block = self.get_block(doc_id, block_id).await;
  75. block.as_ref()?;
  76. let document_data = self.get_document_data(doc_id).await;
  77. let children_map = document_data.meta.children_map;
  78. let children_id = block.unwrap().children_id;
  79. children_map.get(&children_id).map(|c| c.children.clone())
  80. }
  81. pub async fn get_block_text_delta(&self, doc_id: &str, text_id: &str) -> Option<String> {
  82. let document_data = self.get_document_data(doc_id).await;
  83. document_data.meta.text_map.get(text_id).cloned()
  84. }
  85. pub async fn apply_actions(&self, payload: ApplyActionPayloadPB) {
  86. let core = &self.inner;
  87. EventBuilder::new(core.clone())
  88. .event(DocumentEvent::ApplyAction)
  89. .payload(payload)
  90. .async_send()
  91. .await;
  92. }
  93. pub async fn create_text(&self, payload: TextDeltaPayloadPB) {
  94. let core = &self.inner;
  95. EventBuilder::new(core.clone())
  96. .event(DocumentEvent::CreateText)
  97. .payload(payload)
  98. .async_send()
  99. .await;
  100. }
  101. pub async fn apply_text_delta(&self, payload: TextDeltaPayloadPB) {
  102. let core = &self.inner;
  103. EventBuilder::new(core.clone())
  104. .event(DocumentEvent::ApplyTextDeltaEvent)
  105. .payload(payload)
  106. .async_send()
  107. .await;
  108. }
  109. pub async fn undo(&self, doc_id: String) -> DocumentRedoUndoResponsePB {
  110. let core = &self.inner;
  111. let payload = DocumentRedoUndoPayloadPB {
  112. document_id: doc_id.clone(),
  113. };
  114. EventBuilder::new(core.clone())
  115. .event(DocumentEvent::Undo)
  116. .payload(payload)
  117. .async_send()
  118. .await
  119. .parse::<DocumentRedoUndoResponsePB>()
  120. }
  121. pub async fn redo(&self, doc_id: String) -> DocumentRedoUndoResponsePB {
  122. let core = &self.inner;
  123. let payload = DocumentRedoUndoPayloadPB {
  124. document_id: doc_id.clone(),
  125. };
  126. EventBuilder::new(core.clone())
  127. .event(DocumentEvent::Redo)
  128. .payload(payload)
  129. .async_send()
  130. .await
  131. .parse::<DocumentRedoUndoResponsePB>()
  132. }
  133. pub async fn can_undo_redo(&self, doc_id: String) -> DocumentRedoUndoResponsePB {
  134. let core = &self.inner;
  135. let payload = DocumentRedoUndoPayloadPB {
  136. document_id: doc_id.clone(),
  137. };
  138. EventBuilder::new(core.clone())
  139. .event(DocumentEvent::CanUndoRedo)
  140. .payload(payload)
  141. .async_send()
  142. .await
  143. .parse::<DocumentRedoUndoResponsePB>()
  144. }
  145. pub async fn apply_delta_for_block(&self, document_id: &str, block_id: &str, delta: String) {
  146. let block = self.get_block(document_id, block_id).await;
  147. // Here is unsafe, but it should be fine for testing.
  148. let text_id = block.unwrap().external_id.unwrap();
  149. self
  150. .apply_text_delta(TextDeltaPayloadPB {
  151. document_id: document_id.to_string(),
  152. text_id,
  153. delta: Some(delta),
  154. })
  155. .await;
  156. }
  157. /// Insert a new text block at the index of parent's children.
  158. /// return the new block id.
  159. pub async fn insert_index(
  160. &self,
  161. document_id: &str,
  162. text: &str,
  163. index: usize,
  164. parent_id: Option<&str>,
  165. ) -> String {
  166. let text = text.to_string();
  167. let page_id = self.get_page_id(document_id).await;
  168. let parent_id = parent_id
  169. .map(|id| id.to_string())
  170. .unwrap_or_else(|| page_id);
  171. let parent_children = self.get_block_children(document_id, &parent_id).await;
  172. let prev_id = {
  173. // If index is 0, then the new block will be the first child of parent.
  174. if index == 0 {
  175. None
  176. } else {
  177. parent_children.and_then(|children| {
  178. // If index is greater than the length of children, then the new block will be the last child of parent.
  179. if index >= children.len() {
  180. children.last().cloned()
  181. } else {
  182. children.get(index - 1).cloned()
  183. }
  184. })
  185. }
  186. };
  187. let new_block_id = gen_id();
  188. let data = gen_text_block_data();
  189. let external_id = gen_id();
  190. let external_type = "text".to_string();
  191. self
  192. .create_text(TextDeltaPayloadPB {
  193. document_id: document_id.to_string(),
  194. text_id: external_id.clone(),
  195. delta: Some(gen_delta_str(&text)),
  196. })
  197. .await;
  198. let new_block = BlockPB {
  199. id: new_block_id.clone(),
  200. ty: TEXT_BLOCK_TY.to_string(),
  201. data,
  202. parent_id: parent_id.clone(),
  203. children_id: gen_id(),
  204. external_id: Some(external_id),
  205. external_type: Some(external_type),
  206. };
  207. let action = BlockActionPB {
  208. action: BlockActionTypePB::Insert,
  209. payload: BlockActionPayloadPB {
  210. block: Some(new_block),
  211. prev_id,
  212. parent_id: Some(parent_id),
  213. text_id: None,
  214. delta: None,
  215. },
  216. };
  217. let payload = ApplyActionPayloadPB {
  218. document_id: document_id.to_string(),
  219. actions: vec![action],
  220. };
  221. self.apply_actions(payload).await;
  222. new_block_id
  223. }
  224. pub async fn update_data(&self, document_id: &str, block_id: &str, data: HashMap<String, Value>) {
  225. let block = self.get_block(document_id, block_id).await.unwrap();
  226. let new_block = {
  227. let mut new_block = block.clone();
  228. new_block.data = serde_json::to_string(&data).unwrap();
  229. new_block
  230. };
  231. let action = BlockActionPB {
  232. action: BlockActionTypePB::Update,
  233. payload: BlockActionPayloadPB {
  234. block: Some(new_block),
  235. prev_id: None,
  236. parent_id: Some(block.parent_id.clone()),
  237. text_id: None,
  238. delta: None,
  239. },
  240. };
  241. let payload = ApplyActionPayloadPB {
  242. document_id: document_id.to_string(),
  243. actions: vec![action],
  244. };
  245. self.apply_actions(payload).await;
  246. }
  247. pub async fn delete(&self, document_id: &str, block_id: &str) {
  248. let block = self.get_block(document_id, block_id).await.unwrap();
  249. let parent_id = block.parent_id.clone();
  250. let action = BlockActionPB {
  251. action: BlockActionTypePB::Delete,
  252. payload: BlockActionPayloadPB {
  253. block: Some(block),
  254. prev_id: None,
  255. parent_id: Some(parent_id),
  256. text_id: None,
  257. delta: None,
  258. },
  259. };
  260. let payload = ApplyActionPayloadPB {
  261. document_id: document_id.to_string(),
  262. actions: vec![action],
  263. };
  264. self.apply_actions(payload).await;
  265. }
  266. }