mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #569 from AppFlowy-IO/feat/update_grid_test
Feat/update grid test
This commit is contained in:
commit
7014451a8e
@ -15,10 +15,32 @@ pub(crate) async fn get_grid_data_handler(
|
||||
) -> DataResult<Grid, FlowyError> {
|
||||
let grid_id: GridId = data.into_inner();
|
||||
let editor = manager.open_grid(grid_id).await?;
|
||||
let grid = editor.grid_data().await?;
|
||||
let grid = editor.get_grid_data().await?;
|
||||
data_result(grid)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn get_grid_setting_handler(
|
||||
data: Data<GridId>,
|
||||
manager: AppData<Arc<GridManager>>,
|
||||
) -> DataResult<GridSetting, FlowyError> {
|
||||
let grid_id: GridId = data.into_inner();
|
||||
let editor = manager.open_grid(grid_id).await?;
|
||||
let grid_setting = editor.get_grid_setting().await?;
|
||||
data_result(grid_setting.into())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn update_grid_setting_handler(
|
||||
data: Data<GridSettingChangesetPayload>,
|
||||
manager: AppData<Arc<GridManager>>,
|
||||
) -> Result<(), FlowyError> {
|
||||
let params: GridSettingChangesetParams = data.into_inner().try_into()?;
|
||||
let editor = manager.open_grid(¶ms.grid_id).await?;
|
||||
let _ = editor.update_grid_setting(params).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn get_grid_blocks_handler(
|
||||
data: Data<QueryGridBlocksPayload>,
|
||||
|
@ -10,6 +10,8 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
|
||||
module = module
|
||||
.event(GridEvent::GetGridData, get_grid_data_handler)
|
||||
.event(GridEvent::GetGridBlocks, get_grid_blocks_handler)
|
||||
.event(GridEvent::GetGridSetting, get_grid_setting_handler)
|
||||
.event(GridEvent::UpdateGridSetting, get_grid_setting_handler)
|
||||
// Field
|
||||
.event(GridEvent::GetFields, get_fields_handler)
|
||||
.event(GridEvent::UpdateField, update_field_handler)
|
||||
@ -49,6 +51,12 @@ pub enum GridEvent {
|
||||
#[event(input = "QueryGridBlocksPayload", output = "RepeatedGridBlock")]
|
||||
GetGridBlocks = 1,
|
||||
|
||||
#[event(input = "GridId", output = "GridSetting")]
|
||||
GetGridSetting = 2,
|
||||
|
||||
#[event(input = "GridId", input = "GridSettingChangesetPayload")]
|
||||
UpdateGridSetting = 3,
|
||||
|
||||
#[event(input = "QueryFieldPayload", output = "RepeatedField")]
|
||||
GetFields = 10,
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::services::grid_editor::GridMetaEditor;
|
||||
use crate::services::grid_editor::GridRevisionEditor;
|
||||
use crate::services::persistence::block_index::BlockIndexCache;
|
||||
use crate::services::persistence::kv::GridKVPersistence;
|
||||
use crate::services::persistence::GridDatabase;
|
||||
@ -6,7 +6,7 @@ use bytes::Bytes;
|
||||
use dashmap::DashMap;
|
||||
use flowy_database::ConnectionPool;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::revision::{BuildGridContext, GridInfoRevision, GridRevision};
|
||||
use flowy_grid_data_model::revision::{BuildGridContext, GridRevision, GridSettingRevision};
|
||||
use flowy_revision::disk::{SQLiteGridBlockMetaRevisionPersistence, SQLiteGridRevisionPersistence};
|
||||
use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket};
|
||||
use flowy_sync::client_grid::{make_block_meta_delta, make_grid_delta};
|
||||
@ -20,7 +20,7 @@ pub trait GridUser: Send + Sync {
|
||||
}
|
||||
|
||||
pub struct GridManager {
|
||||
editor_map: Arc<DashMap<String, Arc<GridMetaEditor>>>,
|
||||
editor_map: Arc<DashMap<String, Arc<GridRevisionEditor>>>,
|
||||
grid_user: Arc<dyn GridUser>,
|
||||
block_index_cache: Arc<BlockIndexCache>,
|
||||
#[allow(dead_code)]
|
||||
@ -67,7 +67,7 @@ impl GridManager {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all, fields(grid_id), err)]
|
||||
pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<Arc<GridMetaEditor>> {
|
||||
pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<Arc<GridRevisionEditor>> {
|
||||
let grid_id = grid_id.as_ref();
|
||||
tracing::Span::current().record("grid_id", &grid_id);
|
||||
self.get_or_create_grid_editor(grid_id).await
|
||||
@ -92,14 +92,14 @@ impl GridManager {
|
||||
// pub fn update_grid_info()
|
||||
|
||||
// #[tracing::instrument(level = "debug", skip(self), err)]
|
||||
pub fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<GridMetaEditor>> {
|
||||
pub fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<GridRevisionEditor>> {
|
||||
match self.editor_map.get(grid_id) {
|
||||
None => Err(FlowyError::internal().context("Should call open_grid function first")),
|
||||
Some(editor) => Ok(editor.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_or_create_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<GridMetaEditor>> {
|
||||
async fn get_or_create_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<GridRevisionEditor>> {
|
||||
match self.editor_map.get(grid_id) {
|
||||
None => {
|
||||
tracing::trace!("Create grid editor with id: {}", grid_id);
|
||||
@ -121,10 +121,10 @@ impl GridManager {
|
||||
&self,
|
||||
grid_id: &str,
|
||||
pool: Arc<ConnectionPool>,
|
||||
) -> Result<Arc<GridMetaEditor>, FlowyError> {
|
||||
) -> Result<Arc<GridRevisionEditor>, FlowyError> {
|
||||
let user = self.grid_user.clone();
|
||||
let rev_manager = self.make_grid_rev_manager(grid_id, pool.clone())?;
|
||||
let grid_editor = GridMetaEditor::new(grid_id, user, rev_manager, self.block_index_cache.clone()).await?;
|
||||
let grid_editor = GridRevisionEditor::new(grid_id, user, rev_manager, self.block_index_cache.clone()).await?;
|
||||
Ok(grid_editor)
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ pub async fn make_grid_view_data(
|
||||
grid_id: view_id.to_string(),
|
||||
fields: build_context.field_revs,
|
||||
blocks: build_context.blocks,
|
||||
info: GridInfoRevision::default(),
|
||||
setting: GridSettingRevision::default(),
|
||||
};
|
||||
|
||||
// Create grid
|
||||
|
@ -20,7 +20,7 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub struct GridMetaEditor {
|
||||
pub struct GridRevisionEditor {
|
||||
grid_id: String,
|
||||
user: Arc<dyn GridUser>,
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
@ -28,13 +28,13 @@ pub struct GridMetaEditor {
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
}
|
||||
|
||||
impl Drop for GridMetaEditor {
|
||||
impl Drop for GridRevisionEditor {
|
||||
fn drop(&mut self) {
|
||||
tracing::trace!("Drop GridMetaEditor");
|
||||
}
|
||||
}
|
||||
|
||||
impl GridMetaEditor {
|
||||
impl GridRevisionEditor {
|
||||
pub async fn new(
|
||||
grid_id: &str,
|
||||
user: Arc<dyn GridUser>,
|
||||
@ -46,7 +46,7 @@ impl GridMetaEditor {
|
||||
let grid_pad = rev_manager.load::<GridPadBuilder>(Some(cloud)).await?;
|
||||
let rev_manager = Arc::new(rev_manager);
|
||||
let grid_pad = Arc::new(RwLock::new(grid_pad));
|
||||
let blocks = grid_pad.read().await.get_block_metas();
|
||||
let blocks = grid_pad.read().await.get_block_revs();
|
||||
|
||||
let block_meta_manager = Arc::new(GridBlockManager::new(grid_id, &user, blocks, persistence).await?);
|
||||
Ok(Arc::new(Self {
|
||||
@ -165,13 +165,15 @@ impl GridMetaEditor {
|
||||
|
||||
pub async fn replace_field(&self, field_rev: FieldRevision) -> FlowyResult<()> {
|
||||
let field_id = field_rev.id.clone();
|
||||
let _ = self.modify(|pad| Ok(pad.replace_field_rev(field_rev)?)).await?;
|
||||
let _ = self
|
||||
.modify(|grid_pad| Ok(grid_pad.replace_field_rev(field_rev)?))
|
||||
.await?;
|
||||
let _ = self.notify_did_update_grid_field(&field_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_field(&self, field_id: &str) -> FlowyResult<()> {
|
||||
let _ = self.modify(|grid| Ok(grid.delete_field_rev(field_id)?)).await?;
|
||||
let _ = self.modify(|grid_pad| Ok(grid_pad.delete_field_rev(field_id)?)).await?;
|
||||
let field_order = FieldOrder::from(field_id);
|
||||
let notified_changeset = GridFieldChangeset::delete(&self.grid_id, vec![field_order]);
|
||||
let _ = self.notify_did_update_grid(notified_changeset).await?;
|
||||
@ -242,12 +244,16 @@ impl GridMetaEditor {
|
||||
}
|
||||
|
||||
pub async fn create_block(&self, grid_block: GridBlockRevision) -> FlowyResult<()> {
|
||||
let _ = self.modify(|grid| Ok(grid.create_block_meta(grid_block)?)).await?;
|
||||
let _ = self
|
||||
.modify(|grid_pad| Ok(grid_pad.create_block_rev(grid_block)?))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_block(&self, changeset: GridBlockRevisionChangeset) -> FlowyResult<()> {
|
||||
let _ = self.modify(|grid| Ok(grid.update_block_meta(changeset)?)).await?;
|
||||
let _ = self
|
||||
.modify(|grid_pad| Ok(grid_pad.update_block_rev(changeset)?))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -256,7 +262,7 @@ impl GridMetaEditor {
|
||||
let block_id = self.block_id().await?;
|
||||
|
||||
// insert empty row below the row whose id is upper_row_id
|
||||
let row_rev_ctx = CreateRowMetaBuilder::new(&field_revs).build();
|
||||
let row_rev_ctx = CreateRowRevisionBuilder::new(&field_revs).build();
|
||||
let row_rev = make_row_rev_from_context(&block_id, row_rev_ctx);
|
||||
let row_order = RowOrder::from(&row_rev);
|
||||
|
||||
@ -269,7 +275,7 @@ impl GridMetaEditor {
|
||||
Ok(row_order)
|
||||
}
|
||||
|
||||
pub async fn insert_rows(&self, contexts: Vec<CreateRowMetaPayload>) -> FlowyResult<Vec<RowOrder>> {
|
||||
pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<RowOrder>> {
|
||||
let block_id = self.block_id().await?;
|
||||
let mut rows_by_block_id: HashMap<String, Vec<RowRevision>> = HashMap::new();
|
||||
let mut row_orders = vec![];
|
||||
@ -400,7 +406,7 @@ impl GridMetaEditor {
|
||||
}
|
||||
|
||||
pub async fn get_block_metas(&self) -> FlowyResult<Vec<GridBlockRevision>> {
|
||||
let grid_blocks = self.grid_pad.read().await.get_block_metas();
|
||||
let grid_blocks = self.grid_pad.read().await.get_block_revs();
|
||||
Ok(grid_blocks)
|
||||
}
|
||||
|
||||
@ -412,11 +418,11 @@ impl GridMetaEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn grid_data(&self) -> FlowyResult<Grid> {
|
||||
pub async fn get_grid_data(&self) -> FlowyResult<Grid> {
|
||||
let pad_read_guard = self.grid_pad.read().await;
|
||||
let field_orders = pad_read_guard.get_field_orders();
|
||||
let mut block_orders = vec![];
|
||||
for block_order in pad_read_guard.get_block_metas() {
|
||||
for block_order in pad_read_guard.get_block_revs() {
|
||||
let row_orders = self.block_manager.get_row_orders(&block_order.block_id).await?;
|
||||
let block_order = GridBlockOrder {
|
||||
block_id: block_order.block_id,
|
||||
@ -432,13 +438,26 @@ impl GridMetaEditor {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_grid_setting(&self) -> FlowyResult<GridSettingRevision> {
|
||||
let pad_read_guard = self.grid_pad.read().await;
|
||||
let grid_setting_rev = pad_read_guard.get_grid_setting_rev();
|
||||
Ok(grid_setting_rev)
|
||||
}
|
||||
|
||||
pub async fn update_grid_setting(&self, params: GridSettingChangesetParams) -> FlowyResult<()> {
|
||||
let _ = self
|
||||
.modify(|grid_pad| Ok(grid_pad.update_grid_setting_rev(params)?))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn grid_block_snapshots(&self, block_ids: Option<Vec<String>>) -> FlowyResult<Vec<GridBlockSnapshot>> {
|
||||
let block_ids = match block_ids {
|
||||
None => self
|
||||
.grid_pad
|
||||
.read()
|
||||
.await
|
||||
.get_block_metas()
|
||||
.get_block_revs()
|
||||
.into_iter()
|
||||
.map(|block_meta| block_meta.block_id)
|
||||
.collect::<Vec<String>>(),
|
||||
@ -488,7 +507,7 @@ impl GridMetaEditor {
|
||||
|
||||
pub async fn duplicate_grid(&self) -> FlowyResult<BuildGridContext> {
|
||||
let grid_pad = self.grid_pad.read().await;
|
||||
let original_blocks = grid_pad.get_block_metas();
|
||||
let original_blocks = grid_pad.get_block_revs();
|
||||
let (duplicated_fields, duplicated_blocks) = grid_pad.duplicate_grid_meta().await;
|
||||
|
||||
let mut blocks_meta_data = vec![];
|
||||
@ -547,7 +566,7 @@ impl GridMetaEditor {
|
||||
}
|
||||
|
||||
async fn block_id(&self) -> FlowyResult<String> {
|
||||
match self.grid_pad.read().await.get_block_metas().last() {
|
||||
match self.grid_pad.read().await.get_block_revs().last() {
|
||||
None => Err(FlowyError::internal().context("There is no grid block in this grid")),
|
||||
Some(grid_block) => Ok(grid_block.block_id.clone()),
|
||||
}
|
||||
@ -593,7 +612,7 @@ impl GridMetaEditor {
|
||||
}
|
||||
|
||||
#[cfg(feature = "flowy_unit_test")]
|
||||
impl GridMetaEditor {
|
||||
impl GridRevisionEditor {
|
||||
pub fn rev_manager(&self) -> Arc<RevisionManager> {
|
||||
self.rev_manager.clone()
|
||||
}
|
||||
|
@ -5,19 +5,19 @@ use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, R
|
||||
use indexmap::IndexMap;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct CreateRowMetaBuilder<'a> {
|
||||
pub struct CreateRowRevisionBuilder<'a> {
|
||||
field_rev_map: HashMap<&'a String, &'a FieldRevision>,
|
||||
payload: CreateRowMetaPayload,
|
||||
payload: CreateRowRevisionPayload,
|
||||
}
|
||||
|
||||
impl<'a> CreateRowMetaBuilder<'a> {
|
||||
impl<'a> CreateRowRevisionBuilder<'a> {
|
||||
pub fn new(fields: &'a [FieldRevision]) -> Self {
|
||||
let field_rev_map = fields
|
||||
.iter()
|
||||
.map(|field| (&field.id, field))
|
||||
.collect::<HashMap<&String, &FieldRevision>>();
|
||||
|
||||
let payload = CreateRowMetaPayload {
|
||||
let payload = CreateRowRevisionPayload {
|
||||
row_id: gen_row_id(),
|
||||
cell_by_field_id: Default::default(),
|
||||
height: DEFAULT_ROW_HEIGHT,
|
||||
@ -70,12 +70,12 @@ impl<'a> CreateRowMetaBuilder<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> CreateRowMetaPayload {
|
||||
pub fn build(self) -> CreateRowRevisionPayload {
|
||||
self.payload
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_row_rev_from_context(block_id: &str, payload: CreateRowMetaPayload) -> RowRevision {
|
||||
pub fn make_row_rev_from_context(block_id: &str, payload: CreateRowRevisionPayload) -> RowRevision {
|
||||
RowRevision {
|
||||
id: payload.row_id,
|
||||
block_id: block_id.to_owned(),
|
||||
@ -85,7 +85,7 @@ pub fn make_row_rev_from_context(block_id: &str, payload: CreateRowMetaPayload)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CreateRowMetaPayload {
|
||||
pub struct CreateRowRevisionPayload {
|
||||
pub row_id: String,
|
||||
pub cell_by_field_id: IndexMap<String, CellRevision>,
|
||||
pub height: i32,
|
||||
|
40
frontend/rust-lib/flowy-grid/tests/grid/block_test.rs
Normal file
40
frontend/rust-lib/flowy-grid/tests/grid/block_test.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use crate::grid::script::EditorScript::*;
|
||||
use crate::grid::script::*;
|
||||
use flowy_grid_data_model::revision::{GridBlockRevision, GridBlockRevisionChangeset};
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_block() {
|
||||
let grid_block = GridBlockRevision::new();
|
||||
let scripts = vec![
|
||||
AssertBlockCount(1),
|
||||
CreateBlock { block: grid_block },
|
||||
AssertBlockCount(2),
|
||||
];
|
||||
GridEditorTest::new().await.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_update_block() {
|
||||
let grid_block = GridBlockRevision::new();
|
||||
let mut cloned_grid_block = grid_block.clone();
|
||||
let changeset = GridBlockRevisionChangeset {
|
||||
block_id: grid_block.block_id.clone(),
|
||||
start_row_index: Some(2),
|
||||
row_count: Some(10),
|
||||
};
|
||||
|
||||
cloned_grid_block.start_row_index = 2;
|
||||
cloned_grid_block.row_count = 10;
|
||||
|
||||
let scripts = vec![
|
||||
AssertBlockCount(1),
|
||||
CreateBlock { block: grid_block },
|
||||
UpdateBlock { changeset },
|
||||
AssertBlockCount(2),
|
||||
AssertBlockEqual {
|
||||
block_index: 1,
|
||||
block: cloned_grid_block,
|
||||
},
|
||||
];
|
||||
GridEditorTest::new().await.run_scripts(scripts).await;
|
||||
}
|
48
frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs
Normal file
48
frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use crate::grid::script::EditorScript::*;
|
||||
use crate::grid::script::*;
|
||||
use flowy_grid::services::field::{MultiSelectTypeOption, SelectOptionCellContentChangeset, SingleSelectTypeOption};
|
||||
use flowy_grid_data_model::entities::{CellChangeset, FieldType};
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_cell_update() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let field_revs = &test.field_revs;
|
||||
let row_revs = &test.row_revs;
|
||||
let grid_blocks = &test.grid_block_revs;
|
||||
|
||||
// For the moment, We only have one block to store rows
|
||||
let block_id = &grid_blocks.first().unwrap().block_id;
|
||||
|
||||
let mut scripts = vec![];
|
||||
for (_, row_rev) in row_revs.iter().enumerate() {
|
||||
for field_rev in field_revs {
|
||||
let data = match field_rev.field_type {
|
||||
FieldType::RichText => "".to_string(),
|
||||
FieldType::Number => "123".to_string(),
|
||||
FieldType::DateTime => make_date_cell_string("123"),
|
||||
FieldType::SingleSelect => {
|
||||
let type_option = SingleSelectTypeOption::from(field_rev);
|
||||
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let type_option = MultiSelectTypeOption::from(field_rev);
|
||||
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
|
||||
}
|
||||
FieldType::Checkbox => "1".to_string(),
|
||||
FieldType::URL => "1".to_string(),
|
||||
};
|
||||
|
||||
scripts.push(UpdateCell {
|
||||
changeset: CellChangeset {
|
||||
grid_id: block_id.to_string(),
|
||||
row_id: row_rev.id.clone(),
|
||||
field_id: field_rev.id.clone(),
|
||||
cell_content_changeset: Some(data),
|
||||
},
|
||||
is_err: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
113
frontend/rust-lib/flowy-grid/tests/grid/field_test.rs
Normal file
113
frontend/rust-lib/flowy-grid/tests/grid/field_test.rs
Normal file
@ -0,0 +1,113 @@
|
||||
use crate::grid::script::EditorScript::*;
|
||||
use crate::grid::script::*;
|
||||
use flowy_grid::services::field::{SelectOption, SingleSelectTypeOption};
|
||||
use flowy_grid_data_model::entities::FieldChangesetParams;
|
||||
use flowy_grid_data_model::revision::TypeOptionDataEntry;
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_field() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let (params, field_rev) = create_text_field(&test.grid_id);
|
||||
|
||||
let scripts = vec![
|
||||
CreateField { params },
|
||||
AssertFieldEqual {
|
||||
field_index: test.field_count,
|
||||
field_rev,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
|
||||
let (params, field_rev) = create_single_select_field(&test.grid_id);
|
||||
let scripts = vec![
|
||||
CreateField { params },
|
||||
AssertFieldEqual {
|
||||
field_index: test.field_count,
|
||||
field_rev,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_duplicate_field() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let (params, _) = create_text_field(&test.grid_id);
|
||||
let field_count = test.field_count;
|
||||
let expected_field_count = field_count + 1;
|
||||
let scripts = vec![
|
||||
CreateField { params: params.clone() },
|
||||
CreateField { params },
|
||||
AssertFieldCount(expected_field_count),
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_update_field_with_empty_change() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let (params, field_rev) = create_single_select_field(&test.grid_id);
|
||||
let changeset = FieldChangesetParams {
|
||||
field_id: field_rev.id.clone(),
|
||||
grid_id: test.grid_id.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let scripts = vec![
|
||||
CreateField { params },
|
||||
UpdateField { changeset },
|
||||
AssertFieldEqual {
|
||||
field_index: test.field_count,
|
||||
field_rev,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_update_field() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let (params, single_select_field) = create_single_select_field(&test.grid_id);
|
||||
|
||||
let mut single_select_type_option = SingleSelectTypeOption::from(&single_select_field);
|
||||
single_select_type_option.options.push(SelectOption::new("Unknown"));
|
||||
let changeset = FieldChangesetParams {
|
||||
field_id: single_select_field.id.clone(),
|
||||
grid_id: test.grid_id.clone(),
|
||||
frozen: Some(true),
|
||||
width: Some(1000),
|
||||
type_option_data: Some(single_select_type_option.protobuf_bytes().to_vec()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// The expected_field must be equal to the field that applied the changeset
|
||||
let mut expected_field_rev = single_select_field.clone();
|
||||
expected_field_rev.frozen = true;
|
||||
expected_field_rev.width = 1000;
|
||||
expected_field_rev.insert_type_option_entry(&single_select_type_option);
|
||||
|
||||
let scripts = vec![
|
||||
CreateField { params },
|
||||
UpdateField { changeset },
|
||||
AssertFieldEqual {
|
||||
field_index: test.field_count,
|
||||
field_rev: expected_field_rev,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_delete_field() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let original_field_count = test.field_count;
|
||||
let (params, text_field_rev) = create_text_field(&test.grid_id);
|
||||
let scripts = vec![
|
||||
CreateField { params },
|
||||
DeleteField {
|
||||
field_rev: text_field_rev,
|
||||
},
|
||||
AssertFieldCount(original_field_count),
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
@ -1,381 +0,0 @@
|
||||
use crate::grid::script::EditorScript::*;
|
||||
use crate::grid::script::*;
|
||||
use chrono::NaiveDateTime;
|
||||
use flowy_grid::services::field::{
|
||||
DateCellContentChangeset, DateCellData, MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset,
|
||||
SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
|
||||
};
|
||||
use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowMetaBuilder};
|
||||
use flowy_grid_data_model::entities::{CellChangeset, FieldChangesetParams, FieldType};
|
||||
use flowy_grid_data_model::revision::{
|
||||
GridBlockRevision, GridBlockRevisionChangeset, RowMetaChangeset, TypeOptionDataEntry,
|
||||
};
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_field() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let (text_field_params, text_field_rev) = create_text_field(&test.grid_id);
|
||||
let (single_select_params, single_select_field) = create_single_select_field(&test.grid_id);
|
||||
let scripts = vec![
|
||||
CreateField {
|
||||
params: text_field_params,
|
||||
},
|
||||
AssertFieldEqual {
|
||||
field_index: test.field_count,
|
||||
field_rev: text_field_rev,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
|
||||
let scripts = vec![
|
||||
CreateField {
|
||||
params: single_select_params,
|
||||
},
|
||||
AssertFieldEqual {
|
||||
field_index: test.field_count,
|
||||
field_rev: single_select_field,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_duplicate_field() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let (params, _) = create_text_field(&test.grid_id);
|
||||
let field_count = test.field_count;
|
||||
let expected_field_count = field_count + 1;
|
||||
let scripts = vec![
|
||||
CreateField { params: params.clone() },
|
||||
CreateField { params },
|
||||
AssertFieldCount(expected_field_count),
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_update_field_with_empty_change() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let (params, field_rev) = create_single_select_field(&test.grid_id);
|
||||
let changeset = FieldChangesetParams {
|
||||
field_id: field_rev.id.clone(),
|
||||
grid_id: test.grid_id.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let scripts = vec![
|
||||
CreateField { params },
|
||||
UpdateField { changeset },
|
||||
AssertFieldEqual {
|
||||
field_index: test.field_count,
|
||||
field_rev,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_update_field() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let (single_select_params, single_select_field) = create_single_select_field(&test.grid_id);
|
||||
let mut cloned_field = single_select_field.clone();
|
||||
|
||||
let mut single_select_type_option = SingleSelectTypeOption::from(&single_select_field);
|
||||
single_select_type_option.options.push(SelectOption::new("Unknown"));
|
||||
let changeset = FieldChangesetParams {
|
||||
field_id: single_select_field.id.clone(),
|
||||
grid_id: test.grid_id.clone(),
|
||||
frozen: Some(true),
|
||||
width: Some(1000),
|
||||
type_option_data: Some(single_select_type_option.protobuf_bytes().to_vec()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
cloned_field.frozen = true;
|
||||
cloned_field.width = 1000;
|
||||
cloned_field.insert_type_option_entry(&single_select_type_option);
|
||||
|
||||
let scripts = vec![
|
||||
CreateField {
|
||||
params: single_select_params,
|
||||
},
|
||||
UpdateField { changeset },
|
||||
AssertFieldEqual {
|
||||
field_index: test.field_count,
|
||||
field_rev: cloned_field,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_delete_field() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let expected_field_count = test.field_count;
|
||||
let (text_params, text_field) = create_text_field(&test.grid_id);
|
||||
let scripts = vec![
|
||||
CreateField { params: text_params },
|
||||
DeleteField { field_rev: text_field },
|
||||
AssertFieldCount(expected_field_count),
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_block() {
|
||||
let grid_block = GridBlockRevision::new();
|
||||
let scripts = vec![
|
||||
AssertBlockCount(1),
|
||||
CreateBlock { block: grid_block },
|
||||
AssertBlockCount(2),
|
||||
];
|
||||
GridEditorTest::new().await.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_update_block() {
|
||||
let grid_block = GridBlockRevision::new();
|
||||
let mut cloned_grid_block = grid_block.clone();
|
||||
let changeset = GridBlockRevisionChangeset {
|
||||
block_id: grid_block.block_id.clone(),
|
||||
start_row_index: Some(2),
|
||||
row_count: Some(10),
|
||||
};
|
||||
|
||||
cloned_grid_block.start_row_index = 2;
|
||||
cloned_grid_block.row_count = 10;
|
||||
|
||||
let scripts = vec![
|
||||
AssertBlockCount(1),
|
||||
CreateBlock { block: grid_block },
|
||||
UpdateBlock { changeset },
|
||||
AssertBlockCount(2),
|
||||
AssertBlockEqual {
|
||||
block_index: 1,
|
||||
block: cloned_grid_block,
|
||||
},
|
||||
];
|
||||
GridEditorTest::new().await.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_row() {
|
||||
let scripts = vec![AssertRowCount(3), CreateEmptyRow, CreateEmptyRow, AssertRowCount(5)];
|
||||
GridEditorTest::new().await.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_row2() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let create_row_context = CreateRowMetaBuilder::new(&test.field_revs).build();
|
||||
let scripts = vec![
|
||||
AssertRowCount(3),
|
||||
CreateRow {
|
||||
context: create_row_context,
|
||||
},
|
||||
AssertRowCount(4),
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_update_row() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let context = CreateRowMetaBuilder::new(&test.field_revs).build();
|
||||
let changeset = RowMetaChangeset {
|
||||
row_id: context.row_id.clone(),
|
||||
height: None,
|
||||
visibility: None,
|
||||
cell_by_field_id: Default::default(),
|
||||
};
|
||||
|
||||
let scripts = vec![
|
||||
AssertRowCount(3),
|
||||
CreateRow { context },
|
||||
UpdateRow {
|
||||
changeset: changeset.clone(),
|
||||
},
|
||||
AssertRow { changeset },
|
||||
AssertRowCount(4),
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_delete_row() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let context_1 = CreateRowMetaBuilder::new(&test.field_revs).build();
|
||||
let context_2 = CreateRowMetaBuilder::new(&test.field_revs).build();
|
||||
let row_ids = vec![context_1.row_id.clone(), context_2.row_id.clone()];
|
||||
let scripts = vec![
|
||||
AssertRowCount(3),
|
||||
CreateRow { context: context_1 },
|
||||
CreateRow { context: context_2 },
|
||||
AssertBlockCount(1),
|
||||
AssertBlock {
|
||||
block_index: 0,
|
||||
row_count: 5,
|
||||
start_row_index: 0,
|
||||
},
|
||||
DeleteRow { row_ids },
|
||||
AssertBlock {
|
||||
block_index: 0,
|
||||
row_count: 3,
|
||||
start_row_index: 0,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_row_add_cells_test() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let mut builder = CreateRowMetaBuilder::new(&test.field_revs);
|
||||
for field in &test.field_revs {
|
||||
match field.field_type {
|
||||
FieldType::RichText => {
|
||||
builder.add_cell(&field.id, "hello world".to_owned()).unwrap();
|
||||
}
|
||||
FieldType::Number => {
|
||||
builder.add_cell(&field.id, "18,443".to_owned()).unwrap();
|
||||
}
|
||||
FieldType::DateTime => {
|
||||
builder
|
||||
.add_cell(&field.id, make_date_cell_string("1647251762"))
|
||||
.unwrap();
|
||||
}
|
||||
FieldType::SingleSelect => {
|
||||
let type_option = SingleSelectTypeOption::from(field);
|
||||
let option = type_option.options.first().unwrap();
|
||||
builder.add_select_option_cell(&field.id, option.id.clone()).unwrap();
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let type_option = MultiSelectTypeOption::from(field);
|
||||
let ops_ids = type_option
|
||||
.options
|
||||
.iter()
|
||||
.map(|option| option.id.clone())
|
||||
.collect::<Vec<_>>()
|
||||
.join(SELECTION_IDS_SEPARATOR);
|
||||
builder.add_select_option_cell(&field.id, ops_ids).unwrap();
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
builder.add_cell(&field.id, "false".to_string()).unwrap();
|
||||
}
|
||||
FieldType::URL => {
|
||||
builder.add_cell(&field.id, "1".to_string()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
let context = builder.build();
|
||||
let scripts = vec![CreateRow { context }, AssertGridMetaPad];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_row_add_date_cell_test() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let mut builder = CreateRowMetaBuilder::new(&test.field_revs);
|
||||
let mut date_field = None;
|
||||
let timestamp = 1647390674;
|
||||
for field in &test.field_revs {
|
||||
if field.field_type == FieldType::DateTime {
|
||||
date_field = Some(field.clone());
|
||||
NaiveDateTime::from_timestamp(123, 0);
|
||||
// The data should not be empty
|
||||
assert!(builder.add_cell(&field.id, "".to_string()).is_err());
|
||||
assert!(builder.add_cell(&field.id, make_date_cell_string("123")).is_ok());
|
||||
assert!(builder
|
||||
.add_cell(&field.id, make_date_cell_string(×tamp.to_string()))
|
||||
.is_ok());
|
||||
}
|
||||
}
|
||||
let context = builder.build();
|
||||
let date_field = date_field.unwrap();
|
||||
let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
|
||||
assert_eq!(
|
||||
decode_cell_data_from_type_option_cell_data(cell_data.data.clone(), &date_field, &date_field.field_type)
|
||||
.parse::<DateCellData>()
|
||||
.unwrap()
|
||||
.date,
|
||||
"2022/03/16",
|
||||
);
|
||||
let scripts = vec![CreateRow { context }];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_cell_update() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let field_revs = &test.field_revs;
|
||||
let row_revs = &test.row_revs;
|
||||
let grid_blocks = &test.grid_block_revs;
|
||||
assert_eq!(row_revs.len(), 3);
|
||||
assert_eq!(grid_blocks.len(), 1);
|
||||
|
||||
let block_id = &grid_blocks.first().unwrap().block_id;
|
||||
let mut scripts = vec![];
|
||||
for (index, row_rev) in row_revs.iter().enumerate() {
|
||||
for field_rev in field_revs {
|
||||
if index == 0 {
|
||||
let data = match field_rev.field_type {
|
||||
FieldType::RichText => "".to_string(),
|
||||
FieldType::Number => "123".to_string(),
|
||||
FieldType::DateTime => make_date_cell_string("123"),
|
||||
FieldType::SingleSelect => {
|
||||
let type_option = SingleSelectTypeOption::from(field_rev);
|
||||
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let type_option = MultiSelectTypeOption::from(field_rev);
|
||||
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
|
||||
}
|
||||
FieldType::Checkbox => "1".to_string(),
|
||||
FieldType::URL => "1".to_string(),
|
||||
};
|
||||
|
||||
scripts.push(UpdateCell {
|
||||
changeset: CellChangeset {
|
||||
grid_id: block_id.to_string(),
|
||||
row_id: row_rev.id.clone(),
|
||||
field_id: field_rev.id.clone(),
|
||||
cell_content_changeset: Some(data),
|
||||
},
|
||||
is_err: false,
|
||||
});
|
||||
}
|
||||
|
||||
if index == 1 {
|
||||
let (data, is_err) = match field_rev.field_type {
|
||||
FieldType::RichText => ("1".to_string().repeat(10001), true),
|
||||
FieldType::Number => ("abc".to_string(), true),
|
||||
FieldType::DateTime => ("abc".to_string(), true),
|
||||
FieldType::SingleSelect => (SelectOptionCellContentChangeset::from_insert("abc").to_str(), false),
|
||||
FieldType::MultiSelect => (SelectOptionCellContentChangeset::from_insert("abc").to_str(), false),
|
||||
FieldType::Checkbox => ("2".to_string(), false),
|
||||
FieldType::URL => ("2".to_string(), false),
|
||||
};
|
||||
|
||||
scripts.push(UpdateCell {
|
||||
changeset: CellChangeset {
|
||||
grid_id: block_id.to_string(),
|
||||
row_id: row_rev.id.clone(),
|
||||
field_id: field_rev.id.clone(),
|
||||
cell_content_changeset: Some(data),
|
||||
},
|
||||
is_err,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
fn make_date_cell_string(s: &str) -> String {
|
||||
serde_json::to_string(&DateCellContentChangeset {
|
||||
date: Some(s.to_string()),
|
||||
time: None,
|
||||
})
|
||||
.unwrap()
|
||||
}
|
@ -1,2 +1,6 @@
|
||||
mod grid_test;
|
||||
mod block_test;
|
||||
mod cell_test;
|
||||
mod field_test;
|
||||
mod row_test;
|
||||
mod script;
|
||||
mod setting_test;
|
||||
|
147
frontend/rust-lib/flowy-grid/tests/grid/row_test.rs
Normal file
147
frontend/rust-lib/flowy-grid/tests/grid/row_test.rs
Normal file
@ -0,0 +1,147 @@
|
||||
use crate::grid::script::EditorScript::*;
|
||||
use crate::grid::script::*;
|
||||
use chrono::NaiveDateTime;
|
||||
use flowy_grid::services::field::{
|
||||
DateCellData, MultiSelectTypeOption, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
|
||||
};
|
||||
use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowRevisionBuilder};
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::revision::RowMetaChangeset;
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_create_row_count_test() {
|
||||
let test = GridEditorTest::new().await;
|
||||
let create_row_context = CreateRowRevisionBuilder::new(&test.field_revs).build();
|
||||
let scripts = vec![
|
||||
AssertRowCount(3),
|
||||
CreateEmptyRow,
|
||||
CreateEmptyRow,
|
||||
CreateRow {
|
||||
context: create_row_context,
|
||||
},
|
||||
AssertRowCount(6),
|
||||
];
|
||||
GridEditorTest::new().await.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_update_row() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let context = CreateRowRevisionBuilder::new(&test.field_revs).build();
|
||||
let changeset = RowMetaChangeset {
|
||||
row_id: context.row_id.clone(),
|
||||
height: None,
|
||||
visibility: None,
|
||||
cell_by_field_id: Default::default(),
|
||||
};
|
||||
|
||||
let scripts = vec![AssertRowCount(3), CreateRow { context }, UpdateRow { changeset }];
|
||||
test.run_scripts(scripts).await;
|
||||
|
||||
let expected_row = (&*test.row_revs.last().cloned().unwrap()).clone();
|
||||
let scripts = vec![AssertRow { expected_row }, AssertRowCount(4)];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_delete_row() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let context_1 = CreateRowRevisionBuilder::new(&test.field_revs).build();
|
||||
let context_2 = CreateRowRevisionBuilder::new(&test.field_revs).build();
|
||||
let row_ids = vec![context_1.row_id.clone(), context_2.row_id.clone()];
|
||||
let scripts = vec![
|
||||
AssertRowCount(3),
|
||||
CreateRow { context: context_1 },
|
||||
CreateRow { context: context_2 },
|
||||
AssertBlockCount(1),
|
||||
AssertBlock {
|
||||
block_index: 0,
|
||||
row_count: 5,
|
||||
start_row_index: 0,
|
||||
},
|
||||
DeleteRows { row_ids },
|
||||
AssertBlock {
|
||||
block_index: 0,
|
||||
row_count: 3,
|
||||
start_row_index: 0,
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_row_add_cells_test() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let mut builder = CreateRowRevisionBuilder::new(&test.field_revs);
|
||||
for field in &test.field_revs {
|
||||
match field.field_type {
|
||||
FieldType::RichText => {
|
||||
builder.add_cell(&field.id, "hello world".to_owned()).unwrap();
|
||||
}
|
||||
FieldType::Number => {
|
||||
builder.add_cell(&field.id, "18,443".to_owned()).unwrap();
|
||||
}
|
||||
FieldType::DateTime => {
|
||||
builder
|
||||
.add_cell(&field.id, make_date_cell_string("1647251762"))
|
||||
.unwrap();
|
||||
}
|
||||
FieldType::SingleSelect => {
|
||||
let type_option = SingleSelectTypeOption::from(field);
|
||||
let option = type_option.options.first().unwrap();
|
||||
builder.add_select_option_cell(&field.id, option.id.clone()).unwrap();
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let type_option = MultiSelectTypeOption::from(field);
|
||||
let ops_ids = type_option
|
||||
.options
|
||||
.iter()
|
||||
.map(|option| option.id.clone())
|
||||
.collect::<Vec<_>>()
|
||||
.join(SELECTION_IDS_SEPARATOR);
|
||||
builder.add_select_option_cell(&field.id, ops_ids).unwrap();
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
builder.add_cell(&field.id, "false".to_string()).unwrap();
|
||||
}
|
||||
FieldType::URL => {
|
||||
builder.add_cell(&field.id, "1".to_string()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
let context = builder.build();
|
||||
let scripts = vec![CreateRow { context }, AssertGridRevisionPad];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_row_add_date_cell_test() {
|
||||
let mut test = GridEditorTest::new().await;
|
||||
let mut builder = CreateRowRevisionBuilder::new(&test.field_revs);
|
||||
let mut date_field = None;
|
||||
let timestamp = 1647390674;
|
||||
for field in &test.field_revs {
|
||||
if field.field_type == FieldType::DateTime {
|
||||
date_field = Some(field.clone());
|
||||
NaiveDateTime::from_timestamp(123, 0);
|
||||
// The data should not be empty
|
||||
assert!(builder.add_cell(&field.id, "".to_string()).is_err());
|
||||
assert!(builder.add_cell(&field.id, make_date_cell_string("123")).is_ok());
|
||||
assert!(builder
|
||||
.add_cell(&field.id, make_date_cell_string(×tamp.to_string()))
|
||||
.is_ok());
|
||||
}
|
||||
}
|
||||
let context = builder.build();
|
||||
let date_field = date_field.unwrap();
|
||||
let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
|
||||
assert_eq!(
|
||||
decode_cell_data_from_type_option_cell_data(cell_data.data.clone(), &date_field, &date_field.field_type)
|
||||
.parse::<DateCellData>()
|
||||
.unwrap()
|
||||
.date,
|
||||
"2022/03/16",
|
||||
);
|
||||
let scripts = vec![CreateRow { context }];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
@ -1,14 +1,9 @@
|
||||
use bytes::Bytes;
|
||||
use flowy_grid::services::field::*;
|
||||
use flowy_grid::services::grid_editor::{GridMetaEditor, GridPadBuilder};
|
||||
use flowy_grid::services::row::CreateRowMetaPayload;
|
||||
use flowy_grid_data_model::entities::{
|
||||
CellChangeset, Field, FieldChangesetParams, FieldOrder, FieldType, InsertFieldParams, RowOrder,
|
||||
};
|
||||
use flowy_grid_data_model::revision::{
|
||||
BuildGridContext, FieldRevision, GridBlockRevision, GridBlockRevisionChangeset, RowMetaChangeset, RowRevision,
|
||||
TypeOptionDataEntry,
|
||||
};
|
||||
use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor};
|
||||
use flowy_grid::services::row::CreateRowRevisionPayload;
|
||||
use flowy_grid_data_model::entities::*;
|
||||
use flowy_grid_data_model::revision::*;
|
||||
use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS;
|
||||
use flowy_sync::client_grid::GridBuilder;
|
||||
use flowy_test::helper::ViewTest;
|
||||
@ -52,15 +47,15 @@ pub enum EditorScript {
|
||||
},
|
||||
CreateEmptyRow,
|
||||
CreateRow {
|
||||
context: CreateRowMetaPayload,
|
||||
context: CreateRowRevisionPayload,
|
||||
},
|
||||
UpdateRow {
|
||||
changeset: RowMetaChangeset,
|
||||
},
|
||||
AssertRow {
|
||||
changeset: RowMetaChangeset,
|
||||
expected_row: RowRevision,
|
||||
},
|
||||
DeleteRow {
|
||||
DeleteRows {
|
||||
row_ids: Vec<String>,
|
||||
},
|
||||
UpdateCell {
|
||||
@ -68,14 +63,19 @@ pub enum EditorScript {
|
||||
is_err: bool,
|
||||
},
|
||||
AssertRowCount(usize),
|
||||
// AssertRowEqual{ row_index: usize, row: RowMeta},
|
||||
AssertGridMetaPad,
|
||||
UpdateGridSetting {
|
||||
params: GridSettingChangesetParams,
|
||||
},
|
||||
AssertGridSetting {
|
||||
expected_setting: GridSettingRevision,
|
||||
},
|
||||
AssertGridRevisionPad,
|
||||
}
|
||||
|
||||
pub struct GridEditorTest {
|
||||
pub sdk: FlowySDKTest,
|
||||
pub grid_id: String,
|
||||
pub editor: Arc<GridMetaEditor>,
|
||||
pub editor: Arc<GridRevisionEditor>,
|
||||
pub field_revs: Vec<FieldRevision>,
|
||||
pub grid_block_revs: Vec<GridBlockRevision>,
|
||||
pub row_revs: Vec<Arc<RowRevision>>,
|
||||
@ -88,22 +88,28 @@ impl GridEditorTest {
|
||||
pub async fn new() -> Self {
|
||||
let sdk = FlowySDKTest::default();
|
||||
let _ = sdk.init_user().await;
|
||||
let build_context = make_template_1_grid();
|
||||
let build_context = make_test_grid();
|
||||
let view_data: Bytes = build_context.into();
|
||||
let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await;
|
||||
let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap();
|
||||
let field_revs = editor.get_field_revs::<FieldOrder>(None).await.unwrap();
|
||||
let grid_blocks = editor.get_block_metas().await.unwrap();
|
||||
let row_revs = get_row_revs(&editor).await;
|
||||
let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs;
|
||||
assert_eq!(row_revs.len(), 3);
|
||||
assert_eq!(grid_blocks.len(), 1);
|
||||
|
||||
// It seems like you should add the field in the make_test_grid() function.
|
||||
// Because we assert the initialize count of the fields is equal to FieldType::COUNT.
|
||||
assert_eq!(field_revs.len(), FieldType::COUNT);
|
||||
|
||||
let grid_id = test.view.id;
|
||||
Self {
|
||||
sdk,
|
||||
grid_id,
|
||||
editor,
|
||||
field_revs: field_revs,
|
||||
field_revs,
|
||||
grid_block_revs: grid_blocks,
|
||||
row_revs: row_revs,
|
||||
row_revs,
|
||||
field_count: FieldType::COUNT,
|
||||
row_order_by_row_id: HashMap::default(),
|
||||
}
|
||||
@ -192,7 +198,7 @@ impl GridEditorTest {
|
||||
self.grid_block_revs = self.editor.get_block_metas().await.unwrap();
|
||||
}
|
||||
EditorScript::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(),
|
||||
EditorScript::DeleteRow { row_ids } => {
|
||||
EditorScript::DeleteRows { row_ids } => {
|
||||
let row_orders = row_ids
|
||||
.into_iter()
|
||||
.map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone())
|
||||
@ -202,16 +208,21 @@ impl GridEditorTest {
|
||||
self.row_revs = self.get_row_revs().await;
|
||||
self.grid_block_revs = self.editor.get_block_metas().await.unwrap();
|
||||
}
|
||||
EditorScript::AssertRow { changeset } => {
|
||||
let row = self.row_revs.iter().find(|row| row.id == changeset.row_id).unwrap();
|
||||
|
||||
if let Some(visibility) = changeset.visibility {
|
||||
assert_eq!(row.visibility, visibility);
|
||||
}
|
||||
|
||||
if let Some(height) = changeset.height {
|
||||
assert_eq!(row.height, height);
|
||||
}
|
||||
EditorScript::AssertRow { expected_row } => {
|
||||
let row = &*self
|
||||
.row_revs
|
||||
.iter()
|
||||
.find(|row| row.id == expected_row.id)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
assert_eq!(&expected_row, row);
|
||||
// if let Some(visibility) = changeset.visibility {
|
||||
// assert_eq!(row.visibility, visibility);
|
||||
// }
|
||||
//
|
||||
// if let Some(height) = changeset.height {
|
||||
// assert_eq!(row.height, height);
|
||||
// }
|
||||
}
|
||||
EditorScript::UpdateCell { changeset, is_err } => {
|
||||
let result = self.editor.update_cell(changeset).await;
|
||||
@ -222,10 +233,17 @@ impl GridEditorTest {
|
||||
self.row_revs = self.get_row_revs().await;
|
||||
}
|
||||
}
|
||||
EditorScript::AssertRowCount(count) => {
|
||||
assert_eq!(self.row_revs.len(), count);
|
||||
EditorScript::AssertRowCount(expected_row_count) => {
|
||||
assert_eq!(expected_row_count, self.row_revs.len());
|
||||
}
|
||||
EditorScript::AssertGridMetaPad => {
|
||||
EditorScript::UpdateGridSetting { params } => {
|
||||
let _ = self.editor.update_grid_setting(params).await.unwrap();
|
||||
}
|
||||
EditorScript::AssertGridSetting { expected_setting } => {
|
||||
let setting = self.editor.get_grid_setting().await.unwrap();
|
||||
assert_eq!(expected_setting, setting);
|
||||
}
|
||||
EditorScript::AssertGridRevisionPad => {
|
||||
sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await;
|
||||
let mut grid_rev_manager = grid_manager.make_grid_rev_manager(&self.grid_id, pool.clone()).unwrap();
|
||||
let grid_pad = grid_rev_manager.load::<GridPadBuilder>(None).await.unwrap();
|
||||
@ -235,14 +253,16 @@ impl GridEditorTest {
|
||||
}
|
||||
|
||||
async fn get_row_revs(&self) -> Vec<Arc<RowRevision>> {
|
||||
get_row_revs(&self.editor).await
|
||||
self.editor
|
||||
.grid_block_snapshots(None)
|
||||
.await
|
||||
.unwrap()
|
||||
.pop()
|
||||
.unwrap()
|
||||
.row_revs
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_row_revs(editor: &Arc<GridMetaEditor>) -> Vec<Arc<RowRevision>> {
|
||||
editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs
|
||||
}
|
||||
|
||||
pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
|
||||
let field_rev = FieldBuilder::new(RichTextTypeOptionBuilder::default())
|
||||
.name("Name")
|
||||
@ -310,7 +330,7 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev
|
||||
(params, cloned_field_rev)
|
||||
}
|
||||
|
||||
fn make_template_1_grid() -> BuildGridContext {
|
||||
fn make_test_grid() -> BuildGridContext {
|
||||
let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default())
|
||||
.name("Name")
|
||||
.visibility(true)
|
||||
@ -365,3 +385,11 @@ fn make_template_1_grid() -> BuildGridContext {
|
||||
.add_empty_row()
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn make_date_cell_string(s: &str) -> String {
|
||||
serde_json::to_string(&DateCellContentChangeset {
|
||||
date: Some(s.to_string()),
|
||||
time: None,
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
1
frontend/rust-lib/flowy-grid/tests/grid/setting_test.rs
Normal file
1
frontend/rust-lib/flowy-grid/tests/grid/setting_test.rs
Normal file
@ -0,0 +1 @@
|
||||
|
@ -1,28 +1,42 @@
|
||||
use crate::parser::{NotEmptyStr, ViewFilterParser, ViewGroupParser, ViewSortParser};
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error_code::ErrorCode;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct ViewExtData {
|
||||
pub struct GridSetting {
|
||||
#[pb(index = 1)]
|
||||
pub filter: ViewFilter,
|
||||
pub filter: HashMap<String, GridFilter>,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub group: ViewGroup,
|
||||
pub group: HashMap<String, GridGroup>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub sort: ViewSort,
|
||||
pub sort: HashMap<String, GridSort>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
|
||||
#[repr(u8)]
|
||||
pub enum GridLayoutType {
|
||||
Table = 0,
|
||||
Board = 1,
|
||||
}
|
||||
|
||||
impl std::default::Default for GridLayoutType {
|
||||
fn default() -> Self {
|
||||
GridLayoutType::Table
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct ViewFilter {
|
||||
pub struct GridFilter {
|
||||
#[pb(index = 1, one_of)]
|
||||
pub field_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct ViewGroup {
|
||||
pub struct GridGroup {
|
||||
#[pb(index = 1, one_of)]
|
||||
pub group_field_id: Option<String>,
|
||||
|
||||
@ -31,37 +45,41 @@ pub struct ViewGroup {
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct ViewSort {
|
||||
pub struct GridSort {
|
||||
#[pb(index = 1, one_of)]
|
||||
pub field_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, ProtoBuf)]
|
||||
pub struct GridInfoChangesetPayload {
|
||||
pub struct GridSettingChangesetPayload {
|
||||
#[pb(index = 1)]
|
||||
pub grid_id: String,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub filter: Option<ViewFilter>,
|
||||
#[pb(index = 2)]
|
||||
pub layout_type: GridLayoutType,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub group: Option<ViewGroup>,
|
||||
pub filter: Option<GridFilter>,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub sort: Option<ViewSort>,
|
||||
pub group: Option<GridGroup>,
|
||||
|
||||
#[pb(index = 5, one_of)]
|
||||
pub sort: Option<GridSort>,
|
||||
}
|
||||
|
||||
pub struct GridInfoChangesetParams {
|
||||
pub view_id: String,
|
||||
pub filter: Option<ViewFilter>,
|
||||
pub group: Option<ViewGroup>,
|
||||
pub sort: Option<ViewSort>,
|
||||
pub struct GridSettingChangesetParams {
|
||||
pub grid_id: String,
|
||||
pub layout_type: GridLayoutType,
|
||||
pub filter: Option<GridFilter>,
|
||||
pub group: Option<GridGroup>,
|
||||
pub sort: Option<GridSort>,
|
||||
}
|
||||
|
||||
impl TryInto<GridInfoChangesetParams> for GridInfoChangesetPayload {
|
||||
impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayload {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<GridInfoChangesetParams, Self::Error> {
|
||||
fn try_into(self) -> Result<GridSettingChangesetParams, Self::Error> {
|
||||
let view_id = NotEmptyStr::parse(self.grid_id)
|
||||
.map_err(|_| ErrorCode::FieldIdIsEmpty)?
|
||||
.0;
|
||||
@ -81,8 +99,9 @@ impl TryInto<GridInfoChangesetParams> for GridInfoChangesetPayload {
|
||||
Some(sort) => Some(ViewSortParser::parse(sort)?),
|
||||
};
|
||||
|
||||
Ok(GridInfoChangesetParams {
|
||||
view_id,
|
||||
Ok(GridSettingChangesetParams {
|
||||
grid_id: view_id,
|
||||
layout_type: self.layout_type,
|
||||
filter,
|
||||
group,
|
||||
sort,
|
@ -1,7 +1,7 @@
|
||||
mod field;
|
||||
mod grid;
|
||||
mod grid_info;
|
||||
mod grid_setting;
|
||||
|
||||
pub use field::*;
|
||||
pub use grid::*;
|
||||
pub use grid_info::*;
|
||||
pub use grid_setting::*;
|
||||
|
@ -1,24 +1,24 @@
|
||||
use crate::entities::{ViewFilter, ViewGroup, ViewSort};
|
||||
use crate::entities::{GridFilter, GridGroup, GridSort};
|
||||
use crate::parser::NotEmptyStr;
|
||||
use flowy_error_code::ErrorCode;
|
||||
|
||||
pub struct ViewFilterParser(pub ViewFilter);
|
||||
pub struct ViewFilterParser(pub GridFilter);
|
||||
|
||||
impl ViewFilterParser {
|
||||
pub fn parse(value: ViewFilter) -> Result<ViewFilter, ErrorCode> {
|
||||
pub fn parse(value: GridFilter) -> Result<GridFilter, ErrorCode> {
|
||||
let field_id = match value.field_id {
|
||||
None => None,
|
||||
Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
|
||||
};
|
||||
|
||||
Ok(ViewFilter { field_id })
|
||||
Ok(GridFilter { field_id })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ViewGroupParser(pub ViewGroup);
|
||||
pub struct ViewGroupParser(pub GridGroup);
|
||||
|
||||
impl ViewGroupParser {
|
||||
pub fn parse(value: ViewGroup) -> Result<ViewGroup, ErrorCode> {
|
||||
pub fn parse(value: GridGroup) -> Result<GridGroup, ErrorCode> {
|
||||
let group_field_id = match value.group_field_id {
|
||||
None => None,
|
||||
Some(group_field_id) => Some(
|
||||
@ -37,22 +37,22 @@ impl ViewGroupParser {
|
||||
),
|
||||
};
|
||||
|
||||
Ok(ViewGroup {
|
||||
Ok(GridGroup {
|
||||
group_field_id,
|
||||
sub_group_field_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ViewSortParser(pub ViewSort);
|
||||
pub struct ViewSortParser(pub GridSort);
|
||||
|
||||
impl ViewSortParser {
|
||||
pub fn parse(value: ViewSort) -> Result<ViewSort, ErrorCode> {
|
||||
pub fn parse(value: GridSort) -> Result<GridSort, ErrorCode> {
|
||||
let field_id = match value.field_id {
|
||||
None => None,
|
||||
Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
|
||||
};
|
||||
|
||||
Ok(ViewSort { field_id })
|
||||
Ok(GridSort { field_id })
|
||||
}
|
||||
}
|
||||
|
@ -1,66 +0,0 @@
|
||||
use crate::entities::{ViewFilter, ViewGroup, ViewSort};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::*;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct GridInfoRevision {
|
||||
pub filter: GridFilterRevision,
|
||||
pub group: GridGroupRevision,
|
||||
pub sort: GridSortRevision,
|
||||
pub layout: GridLayoutRevision,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct GridLayoutRevision {
|
||||
pub ty: GridLayoutType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize_repr, Deserialize_repr)]
|
||||
#[repr(u8)]
|
||||
pub enum GridLayoutType {
|
||||
Table = 0,
|
||||
Board = 1,
|
||||
}
|
||||
|
||||
impl std::default::Default for GridLayoutType {
|
||||
fn default() -> Self {
|
||||
GridLayoutType::Table
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct GridFilterRevision {
|
||||
pub field_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct GridGroupRevision {
|
||||
pub group_field_id: Option<String>,
|
||||
pub sub_group_field_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct GridSortRevision {
|
||||
field_id: Option<String>,
|
||||
}
|
||||
|
||||
impl std::convert::From<GridFilterRevision> for ViewFilter {
|
||||
fn from(rev: GridFilterRevision) -> Self {
|
||||
ViewFilter { field_id: rev.field_id }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridGroupRevision> for ViewGroup {
|
||||
fn from(rev: GridGroupRevision) -> Self {
|
||||
ViewGroup {
|
||||
group_field_id: rev.group_field_id,
|
||||
sub_group_field_id: rev.sub_group_field_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridSortRevision> for ViewSort {
|
||||
fn from(rev: GridSortRevision) -> Self {
|
||||
ViewSort { field_id: rev.field_id }
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::entities::{CellChangeset, Field, FieldOrder, FieldType, RowOrder};
|
||||
use crate::revision::GridInfoRevision;
|
||||
use crate::revision::GridSettingRevision;
|
||||
use bytes::Bytes;
|
||||
use indexmap::IndexMap;
|
||||
use nanoid::nanoid;
|
||||
@ -32,8 +32,8 @@ pub struct GridRevision {
|
||||
pub fields: Vec<FieldRevision>,
|
||||
pub blocks: Vec<GridBlockRevision>,
|
||||
|
||||
#[serde(default, skip)]
|
||||
pub info: GridInfoRevision,
|
||||
#[serde(skip)]
|
||||
pub setting: GridSettingRevision,
|
||||
}
|
||||
|
||||
impl GridRevision {
|
||||
@ -42,7 +42,7 @@ impl GridRevision {
|
||||
grid_id: grid_id.to_owned(),
|
||||
fields: vec![],
|
||||
blocks: vec![],
|
||||
info: GridInfoRevision::default(),
|
||||
setting: GridSettingRevision::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,116 @@
|
||||
use crate::entities::{GridFilter, GridGroup, GridLayoutType, GridSetting, GridSort};
|
||||
use indexmap::IndexMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
|
||||
pub struct GridSettingRevision {
|
||||
#[serde(with = "indexmap::serde_seq")]
|
||||
pub filter: IndexMap<GridLayoutRevision, GridFilterRevision>,
|
||||
|
||||
#[serde(with = "indexmap::serde_seq")]
|
||||
pub group: IndexMap<GridLayoutRevision, GridGroupRevision>,
|
||||
|
||||
#[serde(with = "indexmap::serde_seq")]
|
||||
pub sort: IndexMap<GridLayoutRevision, GridSortRevision>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
|
||||
#[repr(u8)]
|
||||
pub enum GridLayoutRevision {
|
||||
Table = 0,
|
||||
Board = 1,
|
||||
}
|
||||
|
||||
impl ToString for GridLayoutRevision {
|
||||
fn to_string(&self) -> String {
|
||||
let layout_rev = self.clone() as u8;
|
||||
layout_rev.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for GridLayoutRevision {
|
||||
fn default() -> Self {
|
||||
GridLayoutRevision::Table
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridLayoutRevision> for GridLayoutType {
|
||||
fn from(rev: GridLayoutRevision) -> Self {
|
||||
match rev {
|
||||
GridLayoutRevision::Table => GridLayoutType::Table,
|
||||
GridLayoutRevision::Board => GridLayoutType::Board,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridLayoutType> for GridLayoutRevision {
|
||||
fn from(layout: GridLayoutType) -> Self {
|
||||
match layout {
|
||||
GridLayoutType::Table => GridLayoutRevision::Table,
|
||||
GridLayoutType::Board => GridLayoutRevision::Board,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
|
||||
pub struct GridFilterRevision {
|
||||
pub field_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
|
||||
pub struct GridGroupRevision {
|
||||
pub group_field_id: Option<String>,
|
||||
pub sub_group_field_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
|
||||
pub struct GridSortRevision {
|
||||
pub field_id: Option<String>,
|
||||
}
|
||||
|
||||
impl std::convert::From<GridFilterRevision> for GridFilter {
|
||||
fn from(rev: GridFilterRevision) -> Self {
|
||||
GridFilter { field_id: rev.field_id }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridGroupRevision> for GridGroup {
|
||||
fn from(rev: GridGroupRevision) -> Self {
|
||||
GridGroup {
|
||||
group_field_id: rev.group_field_id,
|
||||
sub_group_field_id: rev.sub_group_field_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridSortRevision> for GridSort {
|
||||
fn from(rev: GridSortRevision) -> Self {
|
||||
GridSort { field_id: rev.field_id }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridSettingRevision> for GridSetting {
|
||||
fn from(rev: GridSettingRevision) -> Self {
|
||||
let filter: HashMap<String, GridFilter> = rev
|
||||
.filter
|
||||
.into_iter()
|
||||
.map(|(layout_rev, filter_rev)| (layout_rev.to_string(), filter_rev.into()))
|
||||
.collect();
|
||||
|
||||
let group: HashMap<String, GridGroup> = rev
|
||||
.group
|
||||
.into_iter()
|
||||
.map(|(layout_rev, group_rev)| (layout_rev.to_string(), group_rev.into()))
|
||||
.collect();
|
||||
|
||||
let sort: HashMap<String, GridSort> = rev
|
||||
.sort
|
||||
.into_iter()
|
||||
.map(|(layout_rev, sort_rev)| (layout_rev.to_string(), sort_rev.into()))
|
||||
.collect();
|
||||
|
||||
GridSetting { filter, group, sort }
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
mod grid_info_rev;
|
||||
mod grid_rev;
|
||||
mod grid_setting_rev;
|
||||
|
||||
pub use grid_info_rev::*;
|
||||
pub use grid_rev::*;
|
||||
pub use grid_setting_rev::*;
|
||||
|
@ -79,7 +79,7 @@ mod tests {
|
||||
grid_id,
|
||||
fields: build_context.field_revs,
|
||||
blocks: build_context.blocks,
|
||||
info: Default::default(),
|
||||
setting: Default::default(),
|
||||
};
|
||||
|
||||
let grid_meta_delta = make_grid_delta(&grid_rev);
|
||||
|
@ -2,10 +2,11 @@ use crate::entities::revision::{md5, RepeatedRevision, Revision};
|
||||
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
|
||||
use crate::util::{cal_diff, make_delta_from_revisions};
|
||||
use bytes::Bytes;
|
||||
use flowy_grid_data_model::entities::FieldType;
|
||||
use flowy_grid_data_model::entities::{FieldChangesetParams, FieldOrder};
|
||||
use flowy_grid_data_model::entities::{FieldType, GridSettingChangesetParams};
|
||||
use flowy_grid_data_model::revision::{
|
||||
gen_block_id, gen_grid_id, FieldRevision, GridBlockRevision, GridBlockRevisionChangeset, GridRevision,
|
||||
gen_block_id, gen_grid_id, FieldRevision, GridBlockRevision, GridBlockRevisionChangeset, GridFilterRevision,
|
||||
GridGroupRevision, GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision,
|
||||
};
|
||||
use lib_infra::util::move_vec_element;
|
||||
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
|
||||
@ -279,7 +280,7 @@ impl GridRevisionPad {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_block_meta(&mut self, block: GridBlockRevision) -> CollaborateResult<Option<GridChangeset>> {
|
||||
pub fn create_block_rev(&mut self, block: GridBlockRevision) -> CollaborateResult<Option<GridChangeset>> {
|
||||
self.modify_grid(|grid_meta| {
|
||||
if grid_meta.blocks.iter().any(|b| b.block_id == block.block_id) {
|
||||
tracing::warn!("Duplicate grid block");
|
||||
@ -302,11 +303,11 @@ impl GridRevisionPad {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_block_metas(&self) -> Vec<GridBlockRevision> {
|
||||
pub fn get_block_revs(&self) -> Vec<GridBlockRevision> {
|
||||
self.grid_rev.blocks.clone()
|
||||
}
|
||||
|
||||
pub fn update_block_meta(
|
||||
pub fn update_block_rev(
|
||||
&mut self,
|
||||
changeset: GridBlockRevisionChangeset,
|
||||
) -> CollaborateResult<Option<GridChangeset>> {
|
||||
@ -328,6 +329,53 @@ impl GridRevisionPad {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_grid_setting_rev(&self) -> GridSettingRevision {
|
||||
self.grid_rev.setting.clone()
|
||||
}
|
||||
|
||||
pub fn update_grid_setting_rev(
|
||||
&mut self,
|
||||
changeset: GridSettingChangesetParams,
|
||||
) -> CollaborateResult<Option<GridChangeset>> {
|
||||
self.modify_grid(|grid_rev| {
|
||||
let mut is_changed = None;
|
||||
let layout_rev: GridLayoutRevision = changeset.layout_type.into();
|
||||
|
||||
if let Some(filter) = changeset.filter {
|
||||
grid_rev.setting.filter.insert(
|
||||
layout_rev.clone(),
|
||||
GridFilterRevision {
|
||||
field_id: filter.field_id,
|
||||
},
|
||||
);
|
||||
is_changed = Some(())
|
||||
}
|
||||
|
||||
if let Some(group) = changeset.group {
|
||||
grid_rev.setting.group.insert(
|
||||
layout_rev.clone(),
|
||||
GridGroupRevision {
|
||||
group_field_id: group.group_field_id,
|
||||
sub_group_field_id: group.sub_group_field_id,
|
||||
},
|
||||
);
|
||||
is_changed = Some(())
|
||||
}
|
||||
|
||||
if let Some(sort) = changeset.sort {
|
||||
grid_rev.setting.sort.insert(
|
||||
layout_rev,
|
||||
GridSortRevision {
|
||||
field_id: sort.field_id,
|
||||
},
|
||||
);
|
||||
is_changed = Some(())
|
||||
}
|
||||
|
||||
Ok(is_changed)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn md5(&self) -> String {
|
||||
md5(&self.delta.to_delta_bytes())
|
||||
}
|
||||
@ -365,32 +413,32 @@ impl GridRevisionPad {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify_block<F>(&mut self, block_id: &str, f: F) -> CollaborateResult<Option<GridChangeset>>
|
||||
fn modify_block<F>(&mut self, block_id: &str, f: F) -> CollaborateResult<Option<GridChangeset>>
|
||||
where
|
||||
F: FnOnce(&mut GridBlockRevision) -> CollaborateResult<Option<()>>,
|
||||
{
|
||||
self.modify_grid(
|
||||
|grid_meta| match grid_meta.blocks.iter().position(|block| block.block_id == block_id) {
|
||||
|grid_rev| match grid_rev.blocks.iter().position(|block| block.block_id == block_id) {
|
||||
None => {
|
||||
tracing::warn!("[GridMetaPad]: Can't find any block with id: {}", block_id);
|
||||
Ok(None)
|
||||
}
|
||||
Some(index) => f(&mut grid_meta.blocks[index]),
|
||||
Some(index) => f(&mut grid_rev.blocks[index]),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn modify_field<F>(&mut self, field_id: &str, f: F) -> CollaborateResult<Option<GridChangeset>>
|
||||
fn modify_field<F>(&mut self, field_id: &str, f: F) -> CollaborateResult<Option<GridChangeset>>
|
||||
where
|
||||
F: FnOnce(&mut FieldRevision) -> CollaborateResult<Option<()>>,
|
||||
{
|
||||
self.modify_grid(
|
||||
|grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) {
|
||||
|grid_rev| match grid_rev.fields.iter().position(|field| field.id == field_id) {
|
||||
None => {
|
||||
tracing::warn!("[GridMetaPad]: Can't find any field with id: {}", field_id);
|
||||
Ok(None)
|
||||
}
|
||||
Some(index) => f(&mut grid_meta.fields[index]),
|
||||
Some(index) => f(&mut grid_rev.fields[index]),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use walkdir::WalkDir;
|
||||
|
||||
pub fn parse_protobuf_context_from(crate_paths: Vec<String>) -> Vec<ProtobufCrateContext> {
|
||||
let crate_infos = parse_crate_info_from_path(crate_paths);
|
||||
let contexts = crate_infos
|
||||
crate_infos
|
||||
.into_iter()
|
||||
.map(|crate_info| {
|
||||
let proto_output_path = crate_info.proto_output_path();
|
||||
@ -28,9 +28,7 @@ pub fn parse_protobuf_context_from(crate_paths: Vec<String>) -> Vec<ProtobufCrat
|
||||
|
||||
ProtobufCrateContext::from_crate_info(crate_info, files)
|
||||
})
|
||||
.collect::<Vec<ProtobufCrateContext>>();
|
||||
|
||||
contexts
|
||||
.collect::<Vec<ProtobufCrateContext>>()
|
||||
}
|
||||
|
||||
fn parse_files_protobuf(proto_crate_path: &Path, proto_output_path: &Path) -> Vec<ProtoFile> {
|
||||
@ -71,7 +69,7 @@ fn parse_files_protobuf(proto_crate_path: &Path, proto_output_path: &Path) -> Ve
|
||||
.iter()
|
||||
.filter(|field| field.attrs.pb_index().is_some())
|
||||
.for_each(|field| {
|
||||
ref_types.push(field.ty_as_str().to_string());
|
||||
ref_types.push(field.ty_as_str());
|
||||
struct_template.set_field(field);
|
||||
});
|
||||
|
||||
@ -95,8 +93,8 @@ fn parse_files_protobuf(proto_crate_path: &Path, proto_output_path: &Path) -> Ve
|
||||
if !enums.is_empty() || !structs.is_empty() {
|
||||
let structs: Vec<String> = structs.iter().map(|s| s.name.clone()).collect();
|
||||
let enums: Vec<String> = enums.iter().map(|e| e.name.clone()).collect();
|
||||
ref_types.retain(|s| !structs.contains(&s));
|
||||
ref_types.retain(|s| !enums.contains(&s));
|
||||
ref_types.retain(|s| !structs.contains(s));
|
||||
ref_types.retain(|s| !enums.contains(s));
|
||||
|
||||
let info = ProtoFile {
|
||||
file_path: path.clone(),
|
||||
|
@ -76,7 +76,7 @@ fn write_proto_files(crate_contexts: &[ProtobufCrateContext]) {
|
||||
let mut file_content = file.syntax.clone();
|
||||
|
||||
// import
|
||||
file_content.push_str(&gen_import_content(&file, &file_path_content_map));
|
||||
file_content.push_str(&gen_import_content(file, &file_path_content_map));
|
||||
|
||||
// content
|
||||
file_content.push_str(&file.content);
|
||||
|
@ -69,7 +69,7 @@ impl ProtobufCrate {
|
||||
ProtobufCrate {
|
||||
crate_path: config.crate_path,
|
||||
crate_folder: config.crate_folder,
|
||||
flowy_config: config.flowy_config.clone(),
|
||||
flowy_config: config.flowy_config,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user