grid_editor.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. #![allow(clippy::all)]
  2. #![allow(dead_code)]
  3. #![allow(unused_imports)]
  4. use crate::grid::block_test::util::GridRowTestBuilder;
  5. use bytes::Bytes;
  6. use flowy_error::FlowyResult;
  7. use flowy_grid::entities::*;
  8. use flowy_grid::services::cell::ToCellChangesetString;
  9. use flowy_grid::services::field::SelectOptionPB;
  10. use flowy_grid::services::field::*;
  11. use flowy_grid::services::grid_editor::{GridRevisionEditor, GridRevisionSerde};
  12. use flowy_grid::services::row::{CreateRowRevisionPayload, RowRevisionBuilder};
  13. use flowy_grid::services::setting::GridSettingChangesetBuilder;
  14. use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS;
  15. use flowy_sync::client_grid::GridBuilder;
  16. use flowy_test::helper::ViewTest;
  17. use flowy_test::FlowySDKTest;
  18. use grid_rev_model::*;
  19. use std::collections::HashMap;
  20. use std::sync::Arc;
  21. use std::time::Duration;
  22. use strum::EnumCount;
  23. use strum::IntoEnumIterator;
  24. use tokio::time::sleep;
  25. pub struct GridEditorTest {
  26. pub sdk: FlowySDKTest,
  27. pub view_id: String,
  28. pub editor: Arc<GridRevisionEditor>,
  29. pub field_revs: Vec<Arc<FieldRevision>>,
  30. pub block_meta_revs: Vec<Arc<GridBlockMetaRevision>>,
  31. pub row_revs: Vec<Arc<RowRevision>>,
  32. pub field_count: usize,
  33. pub row_by_row_id: HashMap<String, RowPB>,
  34. }
  35. impl GridEditorTest {
  36. pub async fn new_table() -> Self {
  37. Self::new(GridLayout::Table).await
  38. }
  39. pub async fn new_board() -> Self {
  40. Self::new(GridLayout::Board).await
  41. }
  42. pub async fn new(layout: GridLayout) -> Self {
  43. let sdk = FlowySDKTest::default();
  44. let _ = sdk.init_user().await;
  45. let test = match layout {
  46. GridLayout::Table => {
  47. let build_context = make_test_grid();
  48. let view_data: Bytes = build_context.into();
  49. ViewTest::new_grid_view(&sdk, view_data.to_vec()).await
  50. }
  51. GridLayout::Board => {
  52. let build_context = make_test_board();
  53. let view_data: Bytes = build_context.into();
  54. ViewTest::new_board_view(&sdk, view_data.to_vec()).await
  55. }
  56. };
  57. let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap();
  58. let field_revs = editor.get_field_revs(None).await.unwrap();
  59. let block_meta_revs = editor.get_block_meta_revs().await.unwrap();
  60. let row_pbs = editor.get_all_row_revs(&test.view.id).await.unwrap();
  61. assert_eq!(block_meta_revs.len(), 1);
  62. // It seems like you should add the field in the make_test_grid() function.
  63. // Because we assert the initialize count of the fields is equal to FieldType::COUNT.
  64. assert_eq!(field_revs.len(), FieldType::COUNT);
  65. let grid_id = test.view.id;
  66. Self {
  67. sdk,
  68. view_id: grid_id,
  69. editor,
  70. field_revs,
  71. block_meta_revs,
  72. row_revs: row_pbs,
  73. field_count: FieldType::COUNT,
  74. row_by_row_id: HashMap::default(),
  75. }
  76. }
  77. pub async fn get_row_revs(&self) -> Vec<Arc<RowRevision>> {
  78. self.editor.get_all_row_revs(&self.view_id).await.unwrap()
  79. }
  80. pub async fn grid_filters(&self) -> Vec<FilterPB> {
  81. self.editor.get_all_filters().await.unwrap()
  82. }
  83. pub fn get_field_rev(&self, field_id: &str, field_type: FieldType) -> &Arc<FieldRevision> {
  84. self.field_revs
  85. .iter()
  86. .filter(|field_rev| {
  87. let t_field_type: FieldType = field_rev.ty.into();
  88. field_rev.id == field_id && t_field_type == field_type
  89. })
  90. .collect::<Vec<_>>()
  91. .pop()
  92. .unwrap()
  93. }
  94. /// returns the first `FieldRevision` in the build-in test grid.
  95. /// Not support duplicate `FieldType` in test grid yet.
  96. pub fn get_first_field_rev(&self, field_type: FieldType) -> &Arc<FieldRevision> {
  97. self.field_revs
  98. .iter()
  99. .filter(|field_rev| {
  100. let t_field_type: FieldType = field_rev.ty.into();
  101. t_field_type == field_type
  102. })
  103. .collect::<Vec<_>>()
  104. .pop()
  105. .unwrap()
  106. }
  107. pub fn get_multi_select_type_option(&self, field_id: &str) -> Vec<SelectOptionPB> {
  108. let field_type = FieldType::MultiSelect;
  109. let field_rev = self.get_field_rev(field_id, field_type.clone());
  110. let type_option = field_rev
  111. .get_type_option::<MultiSelectTypeOptionPB>(field_type.into())
  112. .unwrap();
  113. type_option.options
  114. }
  115. pub fn get_single_select_type_option(&self, field_id: &str) -> SingleSelectTypeOptionPB {
  116. let field_type = FieldType::SingleSelect;
  117. let field_rev = self.get_field_rev(field_id, field_type.clone());
  118. let type_option = field_rev
  119. .get_type_option::<SingleSelectTypeOptionPB>(field_type.into())
  120. .unwrap();
  121. type_option
  122. }
  123. pub fn get_checklist_type_option(&self, field_id: &str) -> ChecklistTypeOptionPB {
  124. let field_type = FieldType::Checklist;
  125. let field_rev = self.get_field_rev(field_id, field_type.clone());
  126. let type_option = field_rev
  127. .get_type_option::<ChecklistTypeOptionPB>(field_type.into())
  128. .unwrap();
  129. type_option
  130. }
  131. pub fn get_checkbox_type_option(&self, field_id: &str) -> CheckboxTypeOptionPB {
  132. let field_type = FieldType::Checkbox;
  133. let field_rev = self.get_field_rev(field_id, field_type.clone());
  134. let type_option = field_rev
  135. .get_type_option::<CheckboxTypeOptionPB>(field_type.into())
  136. .unwrap();
  137. type_option
  138. }
  139. pub fn block_id(&self) -> &str {
  140. &self.block_meta_revs.last().unwrap().block_id
  141. }
  142. pub async fn update_cell<T: ToCellChangesetString>(&mut self, field_id: &str, row_id: String, cell_changeset: T) {
  143. let field_rev = self
  144. .field_revs
  145. .iter()
  146. .find(|field_rev| field_rev.id == field_id)
  147. .unwrap();
  148. self.editor
  149. .update_cell_with_changeset(&row_id, &field_rev.id, cell_changeset)
  150. .await
  151. .unwrap();
  152. }
  153. pub(crate) async fn update_text_cell(&mut self, row_id: String, content: &str) {
  154. let field_rev = self
  155. .field_revs
  156. .iter()
  157. .find(|field_rev| {
  158. let field_type: FieldType = field_rev.ty.into();
  159. field_type == FieldType::RichText
  160. })
  161. .unwrap()
  162. .clone();
  163. self.update_cell(&field_rev.id, row_id, content.to_string()).await;
  164. }
  165. pub(crate) async fn update_single_select_cell(&mut self, row_id: String, option_id: &str) {
  166. let field_rev = self
  167. .field_revs
  168. .iter()
  169. .find(|field_rev| {
  170. let field_type: FieldType = field_rev.ty.into();
  171. field_type == FieldType::SingleSelect
  172. })
  173. .unwrap()
  174. .clone();
  175. let cell_changeset = SelectOptionCellChangeset::from_insert_option_id(&option_id);
  176. self.update_cell(&field_rev.id, row_id, cell_changeset).await;
  177. }
  178. }
  179. pub const GOOGLE: &str = "Google";
  180. pub const FACEBOOK: &str = "Facebook";
  181. pub const TWITTER: &str = "Twitter";
  182. pub const COMPLETED: &str = "Completed";
  183. pub const PLANNED: &str = "Planned";
  184. pub const PAUSED: &str = "Paused";
  185. pub const FIRST_THING: &str = "Wake up at 6:00 am";
  186. pub const SECOND_THING: &str = "Get some coffee";
  187. pub const THIRD_THING: &str = "Start working";
  188. /// The build-in test data for grid. Currently, there are five rows in this grid, if you want to add
  189. /// more rows or alter the data in this grid. Some tests may fail. So you need to fix the failed tests.
  190. fn make_test_grid() -> BuildGridContext {
  191. let mut grid_builder = GridBuilder::new();
  192. // Iterate through the FieldType to create the corresponding Field.
  193. for field_type in FieldType::iter() {
  194. let field_type: FieldType = field_type;
  195. // The
  196. match field_type {
  197. FieldType::RichText => {
  198. let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default())
  199. .name("Name")
  200. .visibility(true)
  201. .primary(true)
  202. .build();
  203. grid_builder.add_field(text_field);
  204. }
  205. FieldType::Number => {
  206. // Number
  207. let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD);
  208. let number_field = FieldBuilder::new(number).name("Price").visibility(true).build();
  209. grid_builder.add_field(number_field);
  210. }
  211. FieldType::DateTime => {
  212. // Date
  213. let date = DateTypeOptionBuilder::default()
  214. .date_format(DateFormat::US)
  215. .time_format(TimeFormat::TwentyFourHour);
  216. let date_field = FieldBuilder::new(date).name("Time").visibility(true).build();
  217. grid_builder.add_field(date_field);
  218. }
  219. FieldType::SingleSelect => {
  220. // Single Select
  221. let single_select = SingleSelectTypeOptionBuilder::default()
  222. .add_option(SelectOptionPB::new(COMPLETED))
  223. .add_option(SelectOptionPB::new(PLANNED))
  224. .add_option(SelectOptionPB::new(PAUSED));
  225. let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build();
  226. grid_builder.add_field(single_select_field);
  227. }
  228. FieldType::MultiSelect => {
  229. // MultiSelect
  230. let multi_select = MultiSelectTypeOptionBuilder::default()
  231. .add_option(SelectOptionPB::new(GOOGLE))
  232. .add_option(SelectOptionPB::new(FACEBOOK))
  233. .add_option(SelectOptionPB::new(TWITTER));
  234. let multi_select_field = FieldBuilder::new(multi_select)
  235. .name("Platform")
  236. .visibility(true)
  237. .build();
  238. grid_builder.add_field(multi_select_field);
  239. }
  240. FieldType::Checkbox => {
  241. // Checkbox
  242. let checkbox = CheckboxTypeOptionBuilder::default();
  243. let checkbox_field = FieldBuilder::new(checkbox).name("is urgent").visibility(true).build();
  244. grid_builder.add_field(checkbox_field);
  245. }
  246. FieldType::URL => {
  247. // URL
  248. let url = URLTypeOptionBuilder::default();
  249. let url_field = FieldBuilder::new(url).name("link").visibility(true).build();
  250. grid_builder.add_field(url_field);
  251. }
  252. FieldType::Checklist => {
  253. let checklist = ChecklistTypeOptionBuilder::default()
  254. .add_option(SelectOptionPB::new(FIRST_THING))
  255. .add_option(SelectOptionPB::new(SECOND_THING))
  256. .add_option(SelectOptionPB::new(THIRD_THING));
  257. let checklist_field = FieldBuilder::new(checklist).name("TODO").visibility(true).build();
  258. grid_builder.add_field(checklist_field);
  259. }
  260. }
  261. }
  262. for i in 0..6 {
  263. let block_id = grid_builder.block_id().to_owned();
  264. let field_revs = grid_builder.field_revs();
  265. let mut row_builder = GridRowTestBuilder::new(&block_id, field_revs);
  266. match i {
  267. 0 => {
  268. for field_type in FieldType::iter() {
  269. match field_type {
  270. FieldType::RichText => row_builder.insert_text_cell("A"),
  271. FieldType::Number => row_builder.insert_number_cell("1"),
  272. FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
  273. FieldType::MultiSelect => row_builder
  274. .insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(0)]),
  275. FieldType::Checklist => row_builder.insert_checklist_cell(|options| options),
  276. FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
  277. FieldType::URL => row_builder.insert_url_cell("AppFlowy website - https://www.appflowy.io"),
  278. _ => "".to_owned(),
  279. };
  280. }
  281. }
  282. 1 => {
  283. for field_type in FieldType::iter() {
  284. match field_type {
  285. FieldType::RichText => row_builder.insert_text_cell(""),
  286. FieldType::Number => row_builder.insert_number_cell("2"),
  287. FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
  288. FieldType::MultiSelect => row_builder
  289. .insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(1)]),
  290. FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
  291. _ => "".to_owned(),
  292. };
  293. }
  294. }
  295. 2 => {
  296. for field_type in FieldType::iter() {
  297. match field_type {
  298. FieldType::RichText => row_builder.insert_text_cell("C"),
  299. FieldType::Number => row_builder.insert_number_cell("3"),
  300. FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
  301. FieldType::SingleSelect => {
  302. row_builder.insert_single_select_cell(|mut options| options.remove(0))
  303. }
  304. FieldType::MultiSelect => {
  305. row_builder.insert_multi_select_cell(|mut options| vec![options.remove(1)])
  306. }
  307. FieldType::Checkbox => row_builder.insert_checkbox_cell("false"),
  308. _ => "".to_owned(),
  309. };
  310. }
  311. }
  312. 3 => {
  313. for field_type in FieldType::iter() {
  314. match field_type {
  315. FieldType::RichText => row_builder.insert_text_cell("DA"),
  316. FieldType::Number => row_builder.insert_number_cell("4"),
  317. FieldType::DateTime => row_builder.insert_date_cell("1668704685"),
  318. FieldType::SingleSelect => {
  319. row_builder.insert_single_select_cell(|mut options| options.remove(0))
  320. }
  321. FieldType::Checkbox => row_builder.insert_checkbox_cell("false"),
  322. _ => "".to_owned(),
  323. };
  324. }
  325. }
  326. 4 => {
  327. for field_type in FieldType::iter() {
  328. match field_type {
  329. FieldType::RichText => row_builder.insert_text_cell("AE"),
  330. FieldType::Number => row_builder.insert_number_cell(""),
  331. FieldType::DateTime => row_builder.insert_date_cell("1668359085"),
  332. FieldType::SingleSelect => {
  333. row_builder.insert_single_select_cell(|mut options| options.remove(1))
  334. }
  335. FieldType::Checkbox => row_builder.insert_checkbox_cell("false"),
  336. _ => "".to_owned(),
  337. };
  338. }
  339. }
  340. 5 => {
  341. for field_type in FieldType::iter() {
  342. match field_type {
  343. FieldType::RichText => row_builder.insert_text_cell("AE"),
  344. FieldType::Number => row_builder.insert_number_cell("5"),
  345. FieldType::DateTime => row_builder.insert_date_cell("1671938394"),
  346. FieldType::SingleSelect => {
  347. row_builder.insert_single_select_cell(|mut options| options.remove(1))
  348. }
  349. FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
  350. _ => "".to_owned(),
  351. };
  352. }
  353. }
  354. _ => {}
  355. }
  356. let row_rev = row_builder.build();
  357. grid_builder.add_row(row_rev);
  358. }
  359. grid_builder.build()
  360. }
  361. fn make_test_board() -> BuildGridContext {
  362. let mut grid_builder = GridBuilder::new();
  363. // Iterate through the FieldType to create the corresponding Field.
  364. for field_type in FieldType::iter() {
  365. let field_type: FieldType = field_type;
  366. // The
  367. match field_type {
  368. FieldType::RichText => {
  369. let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default())
  370. .name("Name")
  371. .visibility(true)
  372. .primary(true)
  373. .build();
  374. grid_builder.add_field(text_field);
  375. }
  376. FieldType::Number => {
  377. // Number
  378. let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD);
  379. let number_field = FieldBuilder::new(number).name("Price").visibility(true).build();
  380. grid_builder.add_field(number_field);
  381. }
  382. FieldType::DateTime => {
  383. // Date
  384. let date = DateTypeOptionBuilder::default()
  385. .date_format(DateFormat::US)
  386. .time_format(TimeFormat::TwentyFourHour);
  387. let date_field = FieldBuilder::new(date).name("Time").visibility(true).build();
  388. grid_builder.add_field(date_field);
  389. }
  390. FieldType::SingleSelect => {
  391. // Single Select
  392. let single_select = SingleSelectTypeOptionBuilder::default()
  393. .add_option(SelectOptionPB::new(COMPLETED))
  394. .add_option(SelectOptionPB::new(PLANNED))
  395. .add_option(SelectOptionPB::new(PAUSED));
  396. let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build();
  397. grid_builder.add_field(single_select_field);
  398. }
  399. FieldType::MultiSelect => {
  400. // MultiSelect
  401. let multi_select = MultiSelectTypeOptionBuilder::default()
  402. .add_option(SelectOptionPB::new(GOOGLE))
  403. .add_option(SelectOptionPB::new(FACEBOOK))
  404. .add_option(SelectOptionPB::new(TWITTER));
  405. let multi_select_field = FieldBuilder::new(multi_select)
  406. .name("Platform")
  407. .visibility(true)
  408. .build();
  409. grid_builder.add_field(multi_select_field);
  410. }
  411. FieldType::Checkbox => {
  412. // Checkbox
  413. let checkbox = CheckboxTypeOptionBuilder::default();
  414. let checkbox_field = FieldBuilder::new(checkbox).name("is urgent").visibility(true).build();
  415. grid_builder.add_field(checkbox_field);
  416. }
  417. FieldType::URL => {
  418. // URL
  419. let url = URLTypeOptionBuilder::default();
  420. let url_field = FieldBuilder::new(url).name("link").visibility(true).build();
  421. grid_builder.add_field(url_field);
  422. }
  423. FieldType::Checklist => {
  424. let checklist = ChecklistTypeOptionBuilder::default()
  425. .add_option(SelectOptionPB::new(FIRST_THING))
  426. .add_option(SelectOptionPB::new(SECOND_THING))
  427. .add_option(SelectOptionPB::new(THIRD_THING));
  428. let checklist_field = FieldBuilder::new(checklist).name("TODO").visibility(true).build();
  429. grid_builder.add_field(checklist_field);
  430. }
  431. }
  432. }
  433. // We have many assumptions base on the number of the rows, so do not change the number of the loop.
  434. for i in 0..5 {
  435. let block_id = grid_builder.block_id().to_owned();
  436. let field_revs = grid_builder.field_revs();
  437. let mut row_builder = GridRowTestBuilder::new(&block_id, field_revs);
  438. match i {
  439. 0 => {
  440. for field_type in FieldType::iter() {
  441. match field_type {
  442. FieldType::RichText => row_builder.insert_text_cell("A"),
  443. FieldType::Number => row_builder.insert_number_cell("1"),
  444. // 1647251762 => Mar 14,2022
  445. FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
  446. FieldType::SingleSelect => {
  447. row_builder.insert_single_select_cell(|mut options| options.remove(0))
  448. }
  449. FieldType::MultiSelect => row_builder
  450. .insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(0)]),
  451. FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
  452. _ => "".to_owned(),
  453. };
  454. }
  455. }
  456. 1 => {
  457. for field_type in FieldType::iter() {
  458. match field_type {
  459. FieldType::RichText => row_builder.insert_text_cell("B"),
  460. FieldType::Number => row_builder.insert_number_cell("2"),
  461. // 1647251762 => Mar 14,2022
  462. FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
  463. FieldType::SingleSelect => {
  464. row_builder.insert_single_select_cell(|mut options| options.remove(0))
  465. }
  466. FieldType::MultiSelect => row_builder
  467. .insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(0)]),
  468. FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
  469. _ => "".to_owned(),
  470. };
  471. }
  472. }
  473. 2 => {
  474. for field_type in FieldType::iter() {
  475. match field_type {
  476. FieldType::RichText => row_builder.insert_text_cell("C"),
  477. FieldType::Number => row_builder.insert_number_cell("3"),
  478. // 1647251762 => Mar 14,2022
  479. FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
  480. FieldType::SingleSelect => {
  481. row_builder.insert_single_select_cell(|mut options| options.remove(1))
  482. }
  483. FieldType::MultiSelect => {
  484. row_builder.insert_multi_select_cell(|mut options| vec![options.remove(0)])
  485. }
  486. FieldType::Checkbox => row_builder.insert_checkbox_cell("false"),
  487. _ => "".to_owned(),
  488. };
  489. }
  490. }
  491. 3 => {
  492. for field_type in FieldType::iter() {
  493. match field_type {
  494. FieldType::RichText => row_builder.insert_text_cell("DA"),
  495. FieldType::Number => row_builder.insert_number_cell("4"),
  496. FieldType::DateTime => row_builder.insert_date_cell("1668704685"),
  497. FieldType::SingleSelect => {
  498. row_builder.insert_single_select_cell(|mut options| options.remove(1))
  499. }
  500. FieldType::Checkbox => row_builder.insert_checkbox_cell("false"),
  501. _ => "".to_owned(),
  502. };
  503. }
  504. }
  505. 4 => {
  506. for field_type in FieldType::iter() {
  507. match field_type {
  508. FieldType::RichText => row_builder.insert_text_cell("AE"),
  509. FieldType::Number => row_builder.insert_number_cell(""),
  510. FieldType::DateTime => row_builder.insert_date_cell("1668359085"),
  511. FieldType::SingleSelect => {
  512. row_builder.insert_single_select_cell(|mut options| options.remove(2))
  513. }
  514. FieldType::Checkbox => row_builder.insert_checkbox_cell("false"),
  515. _ => "".to_owned(),
  516. };
  517. }
  518. }
  519. _ => {}
  520. }
  521. let row_rev = row_builder.build();
  522. grid_builder.add_row(row_rev);
  523. }
  524. grid_builder.build()
  525. }