Merge pull request #1260 from AppFlowy-IO/refactor/switch_to_field

This commit is contained in:
Nathan.fooo 2022-10-11 07:58:59 +08:00 committed by GitHub
commit a20e92f08a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 228 additions and 337 deletions

View File

@ -67,25 +67,6 @@ class FieldService {
return GridEventUpdateField(payload).send();
}
// Create the field if it does not exist. Otherwise, update the field.
static Future<Either<Unit, FlowyError>> insertField({
required String gridId,
required FieldPB field,
List<int>? typeOptionData,
String? startFieldId,
}) {
var payload = InsertFieldPayloadPB.create()
..gridId = gridId
..field_2 = field
..typeOptionData = typeOptionData ?? [];
if (startFieldId != null) {
payload.startFieldId = startFieldId;
}
return GridEventInsertField(payload).send();
}
static Future<Either<Unit, FlowyError>> updateFieldTypeOption({
required String gridId,
required String fieldId,

View File

@ -145,7 +145,7 @@ abstract class IFieldTypeOptionLoader {
String get gridId;
Future<Either<FieldTypeOptionDataPB, FlowyError>> load();
Future<Either<FieldTypeOptionDataPB, FlowyError>> switchToField(
Future<Either<Unit, FlowyError>> switchToField(
String fieldId, FieldType fieldType) {
final payload = EditFieldPayloadPB.create()
..gridId = gridId

View File

@ -47,64 +47,41 @@ class TypeOptionDataController {
return _data.field_2;
}
set field(FieldPB field) {
_updateData(newField: field);
}
T getTypeOption<T>(TypeOptionDataParser<T> parser) {
return parser.fromBuffer(_data.typeOptionData);
}
set fieldName(String name) {
_updateData(newName: name);
}
set typeOptionData(List<int> typeOptionData) {
_updateData(newTypeOptionData: typeOptionData);
}
void _updateData({
String? newName,
FieldPB? newField,
List<int>? newTypeOptionData,
}) {
_data = _data.rebuild((rebuildData) {
if (newName != null) {
rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
rebuildField.name = newName;
});
}
if (newField != null) {
rebuildData.field_2 = newField;
}
if (newTypeOptionData != null) {
rebuildData.typeOptionData = newTypeOptionData;
}
rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
rebuildField.name = name;
});
});
_fieldNotifier.value = _data.field_2;
FieldService.insertField(
FieldService(gridId: gridId, fieldId: field.id).updateField(name: name);
}
set typeOptionData(List<int> typeOptionData) {
_data = _data.rebuild((rebuildData) {
if (typeOptionData.isNotEmpty) {
rebuildData.typeOptionData = typeOptionData;
}
});
FieldService.updateFieldTypeOption(
gridId: gridId,
field: field,
typeOptionData: _data.typeOptionData,
fieldId: field.id,
typeOptionData: typeOptionData,
);
}
Future<void> switchToField(FieldType newFieldType) {
return loader.switchToField(field.id, newFieldType).then((result) {
return result.fold(
(fieldTypeOptionData) {
_updateData(
newField: fieldTypeOptionData.field_2,
newTypeOptionData: fieldTypeOptionData.typeOptionData,
);
},
(err) {
Log.error(err);
},
(_) {},
(err) => Log.error(err),
);
});
}

View File

@ -164,11 +164,16 @@ pub struct CreateFieldPayloadPB {
#[pb(index = 2)]
pub field_type: FieldType,
#[pb(index = 3, one_of)]
pub type_option_data: Option<Vec<u8>>,
}
#[derive(Clone)]
pub struct CreateFieldParams {
pub grid_id: String,
pub field_type: FieldType,
pub type_option_data: Option<Vec<u8>>,
}
impl TryInto<CreateFieldParams> for CreateFieldPayloadPB {
@ -179,6 +184,7 @@ impl TryInto<CreateFieldParams> for CreateFieldPayloadPB {
Ok(CreateFieldParams {
grid_id: grid_id.0,
field_type: self.field_type,
type_option_data: self.type_option_data,
})
}
}
@ -314,50 +320,6 @@ impl std::convert::From<String> for RepeatedFieldIdPB {
}
}
#[derive(ProtoBuf, Default)]
pub struct InsertFieldPayloadPB {
#[pb(index = 1)]
pub grid_id: String,
#[pb(index = 2)]
pub field: FieldPB,
#[pb(index = 3)]
pub type_option_data: Vec<u8>,
#[pb(index = 4, one_of)]
pub start_field_id: Option<String>,
}
#[derive(Clone)]
pub struct InsertFieldParams {
pub grid_id: String,
pub field: FieldPB,
pub type_option_data: Vec<u8>,
pub start_field_id: Option<String>,
}
impl TryInto<InsertFieldParams> for InsertFieldPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<InsertFieldParams, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let _ = NotEmptyStr::parse(self.field.id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?;
let start_field_id = match self.start_field_id {
None => None,
Some(id) => Some(NotEmptyStr::parse(id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
};
Ok(InsertFieldParams {
grid_id: grid_id.0,
field: self.field,
type_option_data: self.type_option_data,
start_field_id,
})
}
}
/// [UpdateFieldTypeOptionPayloadPB] is used to update the type option data.
#[derive(ProtoBuf, Default)]
pub struct UpdateFieldTypeOptionPayloadPB {

View File

@ -101,17 +101,6 @@ pub(crate) async fn update_field_handler(
Ok(())
}
#[tracing::instrument(level = "trace", skip(data, manager), err)]
pub(crate) async fn insert_field_handler(
data: Data<InsertFieldPayloadPB>,
manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> {
let params: InsertFieldParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let _ = editor.insert_field(params).await?;
Ok(())
}
#[tracing::instrument(level = "trace", skip(data, manager), err)]
pub(crate) async fn update_field_type_option_handler(
data: Data<UpdateFieldTypeOptionPayloadPB>,
@ -140,27 +129,25 @@ pub(crate) async fn delete_field_handler(
pub(crate) async fn switch_to_field_handler(
data: Data<EditFieldPayloadPB>,
manager: AppData<Arc<GridManager>>,
) -> DataResult<FieldTypeOptionDataPB, FlowyError> {
) -> Result<(), FlowyError> {
let params: EditFieldParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
editor
.switch_to_field_type(&params.field_id, &params.field_type)
.await?;
// Get the FieldMeta with field_id, if it doesn't exist, we create the default FieldMeta from the FieldType.
// Get the field_rev with field_id, if it doesn't exist, we create the default FieldMeta from the FieldType.
let field_rev = editor
.get_field_rev(&params.field_id)
.await
.unwrap_or(Arc::new(editor.next_field_rev(&params.field_type).await?));
let type_option_data = get_type_option_data(&field_rev, &params.field_type).await?;
let data = FieldTypeOptionDataPB {
grid_id: params.grid_id,
field: field_rev.into(),
type_option_data,
};
let _ = editor
.update_field_type_option(&params.grid_id, &field_rev.id, type_option_data)
.await?;
data_result(data)
Ok(())
}
#[tracing::instrument(level = "trace", skip(data, manager), err)]
@ -205,7 +192,9 @@ pub(crate) async fn create_field_type_option_data_handler(
) -> DataResult<FieldTypeOptionDataPB, FlowyError> {
let params: CreateFieldParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let field_rev = editor.create_next_field_rev(&params.field_type).await?;
let field_rev = editor
.create_new_field_rev(&params.field_type, params.type_option_data)
.await?;
let field_type: FieldType = field_rev.ty.into();
let type_option_data = get_type_option_data(&field_rev, &field_type).await?;
@ -227,7 +216,7 @@ pub(crate) async fn move_field_handler(
Ok(())
}
/// The FieldMeta contains multiple data, each of them belongs to a specific FieldType.
/// The [FieldRevision] contains multiple data, each of them belongs to a specific FieldType.
async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType) -> FlowyResult<Vec<u8>> {
let s = field_rev.get_type_option_str(field_type).unwrap_or_else(|| {
default_type_option_builder_from_type(field_type)
@ -346,38 +335,52 @@ pub(crate) async fn update_select_option_handler(
let changeset: SelectOptionChangeset = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&changeset.cell_identifier.grid_id)?;
if let Some(mut field_rev) = editor.get_field_rev(&changeset.cell_identifier.field_id).await {
let mut_field_rev = Arc::make_mut(&mut field_rev);
let mut type_option = select_option_operation(mut_field_rev)?;
let mut cell_content_changeset = None;
let _ = editor
.modify_field_rev(&changeset.cell_identifier.field_id, |field_rev| {
let mut type_option = select_option_operation(field_rev)?;
let mut cell_content_changeset = None;
let mut is_changed = None;
if let Some(option) = changeset.insert_option {
cell_content_changeset = Some(SelectOptionCellChangeset::from_insert(&option.id).to_str());
type_option.insert_option(option);
}
if let Some(option) = changeset.insert_option {
cell_content_changeset = Some(SelectOptionCellChangeset::from_insert(&option.id).to_str());
type_option.insert_option(option);
is_changed = Some(());
}
if let Some(option) = changeset.update_option {
type_option.insert_option(option);
}
if let Some(option) = changeset.update_option {
type_option.insert_option(option);
is_changed = Some(());
}
if let Some(option) = changeset.delete_option {
cell_content_changeset = Some(SelectOptionCellChangeset::from_delete(&option.id).to_str());
type_option.delete_option(option);
}
if let Some(option) = changeset.delete_option {
cell_content_changeset = Some(SelectOptionCellChangeset::from_delete(&option.id).to_str());
type_option.delete_option(option);
is_changed = Some(());
}
mut_field_rev.insert_type_option(&*type_option);
let _ = editor.replace_field(field_rev).await?;
if is_changed.is_some() {
field_rev.insert_type_option(&*type_option);
}
if let Some(cell_content_changeset) = cell_content_changeset {
let changeset = CellChangesetPB {
grid_id: changeset.cell_identifier.grid_id,
row_id: changeset.cell_identifier.row_id,
field_id: changeset.cell_identifier.field_id.clone(),
content: cell_content_changeset,
};
let cloned_editor = editor.clone();
tokio::spawn(async move {
match cloned_editor.update_cell(changeset).await {
Ok(_) => {}
Err(_) => {}
}
});
}
Ok(is_changed)
})
.await?;
if let Some(cell_content_changeset) = cell_content_changeset {
let changeset = CellChangesetPB {
grid_id: changeset.cell_identifier.grid_id,
row_id: changeset.cell_identifier.row_id,
field_id: changeset.cell_identifier.field_id,
content: cell_content_changeset,
};
let _ = editor.update_cell(changeset).await?;
}
}
Ok(())
}

View File

@ -15,7 +15,6 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
// Field
.event(GridEvent::GetFields, get_fields_handler)
.event(GridEvent::UpdateField, update_field_handler)
.event(GridEvent::InsertField, insert_field_handler)
.event(GridEvent::UpdateFieldTypeOption, update_field_type_option_handler)
.event(GridEvent::DeleteField, delete_field_handler)
.event(GridEvent::SwitchToField, switch_to_field_handler)
@ -106,11 +105,6 @@ pub enum GridEvent {
#[event(input = "UpdateFieldTypeOptionPayloadPB")]
UpdateFieldTypeOption = 12,
/// [InsertField] event is used to insert a new Field. If the Field already exists, the event
/// handler will replace the value with the new Field value.
#[event(input = "InsertFieldPayloadPB")]
InsertField = 13,
/// [DeleteField] event is used to delete a Field. [DeleteFieldPayloadPB] is the context that
/// is used to delete the field from the Grid.
#[event(input = "DeleteFieldPayloadPB")]
@ -119,7 +113,7 @@ pub enum GridEvent {
/// [SwitchToField] event is used to update the current Field's type.
/// It will insert a new FieldTypeOptionData if the new FieldType doesn't exist before, otherwise
/// reuse the existing FieldTypeOptionData. You could check the [GridRevisionPad] for more details.
#[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")]
#[event(input = "EditFieldPayloadPB")]
SwitchToField = 20,
/// [DuplicateField] event is used to duplicate a Field. The duplicated field data is kind of

View File

@ -1,7 +1,8 @@
use crate::entities::{FieldPB, FieldType};
use crate::services::field::type_options::*;
use bytes::Bytes;
use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataFormat};
use crate::services::field::{default_type_option_builder_from_type, TypeOptionBuilder};
use flowy_grid_data_model::revision::FieldRevision;
use indexmap::IndexMap;
pub struct FieldBuilder {
@ -82,47 +83,3 @@ impl FieldBuilder {
field_rev
}
}
pub trait TypeOptionBuilder {
fn field_type(&self) -> FieldType;
fn data_format(&self) -> &dyn TypeOptionDataFormat;
}
pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
let s: String = match field_type {
FieldType::RichText => RichTextTypeOptionPB::default().into(),
FieldType::Number => NumberTypeOptionPB::default().into(),
FieldType::DateTime => DateTypeOptionPB::default().into(),
FieldType::SingleSelect => SingleSelectTypeOptionPB::default().into(),
FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(),
FieldType::Checkbox => CheckboxTypeOptionPB::default().into(),
FieldType::URL => URLTypeOptionPB::default().into(),
};
type_option_builder_from_json_str(&s, field_type)
}
pub fn type_option_builder_from_json_str(s: &str, field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
match field_type {
FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_json_str(s)),
FieldType::Number => Box::new(NumberTypeOptionBuilder::from_json_str(s)),
FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_json_str(s)),
FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_json_str(s)),
FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_json_str(s)),
FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_json_str(s)),
FieldType::URL => Box::new(URLTypeOptionBuilder::from_json_str(s)),
}
}
pub fn type_option_builder_from_bytes<T: Into<Bytes>>(bytes: T, field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
let bytes = bytes.into();
match field_type {
FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::Number => Box::new(NumberTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::URL => Box::new(URLTypeOptionBuilder::from_protobuf_bytes(bytes)),
}
}

View File

@ -1,7 +1,9 @@
mod field_builder;
mod field_operation;
mod type_option_builder;
pub(crate) mod type_options;
pub use field_builder::*;
pub use field_operation::*;
pub use type_option_builder::*;
pub use type_options::*;

View File

@ -0,0 +1,48 @@
use crate::entities::FieldType;
use crate::services::field::type_options::*;
use bytes::Bytes;
use flowy_grid_data_model::revision::TypeOptionDataFormat;
pub trait TypeOptionBuilder {
fn field_type(&self) -> FieldType;
fn data_format(&self) -> &dyn TypeOptionDataFormat;
}
pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
let s: String = match field_type {
FieldType::RichText => RichTextTypeOptionPB::default().into(),
FieldType::Number => NumberTypeOptionPB::default().into(),
FieldType::DateTime => DateTypeOptionPB::default().into(),
FieldType::SingleSelect => SingleSelectTypeOptionPB::default().into(),
FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(),
FieldType::Checkbox => CheckboxTypeOptionPB::default().into(),
FieldType::URL => URLTypeOptionPB::default().into(),
};
type_option_builder_from_json_str(&s, field_type)
}
pub fn type_option_builder_from_json_str(s: &str, field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
match field_type {
FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_json_str(s)),
FieldType::Number => Box::new(NumberTypeOptionBuilder::from_json_str(s)),
FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_json_str(s)),
FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_json_str(s)),
FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_json_str(s)),
FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_json_str(s)),
FieldType::URL => Box::new(URLTypeOptionBuilder::from_json_str(s)),
}
}
pub fn type_option_builder_from_bytes<T: Into<Bytes>>(bytes: T, field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
let bytes = bytes.into();
match field_type {
FieldType::RichText => Box::new(RichTextTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::Number => Box::new(NumberTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::DateTime => Box::new(DateTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::SingleSelect => Box::new(SingleSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_protobuf_bytes(bytes)),
FieldType::URL => Box::new(URLTypeOptionBuilder::from_protobuf_bytes(bytes)),
}
}

View File

@ -16,7 +16,7 @@ use flowy_grid_data_model::revision::*;
use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeserializer};
use flowy_sync::entities::revision::Revision;
use flowy_sync::errors::CollaborateResult;
use flowy_sync::errors::{CollaborateError, CollaborateResult};
use flowy_sync::util::make_operations_from_revisions;
use lib_infra::future::{wrap_future, FutureResult};
@ -87,43 +87,6 @@ impl GridRevisionEditor {
Ok(editor)
}
pub async fn insert_field(&self, params: InsertFieldParams) -> FlowyResult<()> {
let InsertFieldParams {
field,
type_option_data,
start_field_id,
grid_id,
} = params;
let field_id = field.id.clone();
if self.contain_field(&field_id).await {
let changeset = FieldChangesetParams {
field_id: field.id,
grid_id,
name: Some(field.name),
desc: Some(field.desc),
field_type: Some(field.field_type.clone().into()),
frozen: Some(field.frozen),
visibility: Some(field.visibility),
width: Some(field.width),
type_option_data: Some(type_option_data),
};
let _ = self.update_field_rev(changeset, field.field_type).await?;
let _ = self.notify_did_update_grid_field(&field_id).await?;
} else {
let _ = self
.modify(|grid| {
let builder = type_option_builder_from_bytes(type_option_data, &field.field_type);
let field_rev = FieldBuilder::from_field(field, builder).build();
Ok(grid.create_field_rev(field_rev, start_field_id)?)
})
.await?;
let _ = self.notify_did_insert_grid_field(&field_id).await?;
}
Ok(())
}
pub async fn update_field_type_option(
&self,
grid_id: &str,
@ -153,8 +116,16 @@ impl GridRevisionEditor {
Ok(field_rev)
}
pub async fn create_next_field_rev(&self, field_type: &FieldType) -> FlowyResult<FieldRevision> {
let field_rev = self.next_field_rev(field_type).await?;
pub async fn create_new_field_rev(
&self,
field_type: &FieldType,
type_option_data: Option<Vec<u8>>,
) -> FlowyResult<FieldRevision> {
let mut field_rev = self.next_field_rev(field_type).await?;
if let Some(type_option_data) = type_option_data {
let type_option_builder = type_option_builder_from_bytes(type_option_data, field_type);
field_rev.insert_type_option(type_option_builder.data_format());
}
let _ = self
.modify(|grid| Ok(grid.create_field_rev(field_rev.clone(), None)?))
.await?;
@ -186,18 +157,28 @@ impl GridRevisionEditor {
}
}
// Replaces the field revision with new field revision.
pub async fn replace_field(&self, field_rev: Arc<FieldRevision>) -> FlowyResult<()> {
let field_id = field_rev.id.clone();
pub async fn modify_field_rev<F>(&self, field_id: &str, f: F) -> FlowyResult<()>
where
F: for<'a> FnOnce(&'a mut FieldRevision) -> FlowyResult<Option<()>>,
{
let mut is_changed = false;
let _ = self
.modify(|grid_pad| Ok(grid_pad.replace_field_rev(field_rev.clone())?))
.modify(|grid| {
let changeset = grid.modify_field(field_id, |field_rev| {
Ok(f(field_rev).map_err(|e| CollaborateError::internal().context(e))?)
})?;
is_changed = changeset.is_some();
Ok(changeset)
})
.await?;
match self.view_manager.did_update_view_field(&field_rev.id).await {
Ok(_) => {}
Err(e) => tracing::error!("View manager update field failed: {:?}", e),
if is_changed {
match self.view_manager.did_update_view_field_type_option(field_id).await {
Ok(_) => {}
Err(e) => tracing::error!("View manager update field failed: {:?}", e),
}
let _ = self.notify_did_update_grid_field(field_id).await?;
}
let _ = self.notify_did_update_grid_field(&field_id).await?;
Ok(())
}

View File

@ -283,15 +283,8 @@ impl GridViewRevisionEditor {
.await
}
#[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) async fn did_update_view_field(&self, field_id: &str) -> FlowyResult<()> {
if let Some(field_rev) = self.field_delegate.get_field_rev(field_id).await {
match self.group_controller.write().await.did_update_group_field(&field_rev)? {
None => {}
Some(changeset) => {
self.notify_did_update_view(changeset).await;
}
}
}
pub(crate) async fn did_update_view_field(&self, _field_id: &str) -> FlowyResult<()> {
// Do nothing
Ok(())
}

View File

@ -179,8 +179,7 @@ impl GridViewManager {
#[tracing::instrument(level = "trace", skip(self), err)]
pub(crate) async fn did_update_view_field(&self, field_id: &str) -> FlowyResult<()> {
let view_editor = self.get_default_view_editor().await?;
// Only the field_id of the updated field is equal to the field_id of the group.
// Update the group
// Update the group if the group_id equal to the field_id
if view_editor.group_id().await != field_id {
return Ok(());
}

View File

@ -172,7 +172,7 @@ where
/// [GroupConfigurationRevision] as old groups. The old groups and the new groups will be merged
/// while keeping the order of the old groups.
///
#[tracing::instrument(level = "debug", skip(self, generated_group_configs), err)]
#[tracing::instrument(level = "trace", skip(self, generated_group_configs), err)]
pub(crate) fn init_groups(
&mut self,
generated_group_configs: Vec<GeneratedGroupConfig>,

View File

@ -319,11 +319,8 @@ where
}
}
fn did_update_group_field(&mut self, field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> {
let type_option = field_rev.get_type_option::<T>(field_rev.ty);
let groups = G::generate_groups(&field_rev.id, &self.group_ctx, &type_option);
let changeset = self.group_ctx.init_groups(groups)?;
Ok(changeset)
fn did_update_group_field(&mut self, _field_rev: &FieldRevision) -> FlowyResult<Option<GroupViewChangesetPB>> {
Ok(None)
}
}

View File

@ -1,10 +1,10 @@
use crate::grid::grid_editor::GridEditorTest;
use flowy_grid::entities::{FieldChangesetParams, InsertFieldParams};
use flowy_grid::entities::{CreateFieldParams, FieldChangesetParams};
use flowy_grid_data_model::revision::FieldRevision;
pub enum FieldScript {
CreateField {
params: InsertFieldParams,
params: CreateFieldParams,
},
UpdateField {
changeset: FieldChangesetParams,
@ -13,9 +13,9 @@ pub enum FieldScript {
field_rev: FieldRevision,
},
AssertFieldCount(usize),
AssertFieldEqual {
AssertFieldTypeOptionEqual {
field_index: usize,
field_rev: FieldRevision,
expected_type_option_data: String,
},
}
@ -46,11 +46,11 @@ impl GridFieldTest {
pub async fn run_script(&mut self, script: FieldScript) {
match script {
FieldScript::CreateField { params } => {
if !self.editor.contain_field(&params.field.id).await {
self.field_count += 1;
}
self.editor.insert_field(params).await.unwrap();
self.field_count += 1;
self.editor
.create_new_field_rev(&params.field_type, params.type_option_data)
.await
.unwrap();
self.field_revs = self.editor.get_field_revs(None).await.unwrap();
assert_eq!(self.field_count, self.field_revs.len());
}
@ -70,9 +70,14 @@ impl GridFieldTest {
FieldScript::AssertFieldCount(count) => {
assert_eq!(self.editor.get_field_revs(None).await.unwrap().len(), count);
}
FieldScript::AssertFieldEqual { field_index, field_rev } => {
FieldScript::AssertFieldTypeOptionEqual {
field_index,
expected_type_option_data,
} => {
let field_revs = self.editor.get_field_revs(None).await.unwrap();
assert_eq!(field_revs[field_index].as_ref(), &field_rev);
let field_rev = field_revs[field_index].as_ref();
let type_option_data = field_rev.get_type_option_str(field_rev.ty.clone()).unwrap();
assert_eq!(type_option_data, expected_type_option_data);
}
}
}

View File

@ -13,9 +13,9 @@ async fn grid_create_field() {
let scripts = vec![
CreateField { params },
AssertFieldEqual {
AssertFieldTypeOptionEqual {
field_index: test.field_count(),
field_rev,
expected_type_option_data: field_rev.get_type_option_str(field_rev.ty.clone()).unwrap(),
},
];
test.run_scripts(scripts).await;
@ -23,9 +23,9 @@ async fn grid_create_field() {
let (params, field_rev) = create_single_select_field(&test.grid_id());
let scripts = vec![
CreateField { params },
AssertFieldEqual {
AssertFieldTypeOptionEqual {
field_index: test.field_count(),
field_rev,
expected_type_option_data: field_rev.get_type_option_str(field_rev.ty.clone()).unwrap(),
},
];
test.run_scripts(scripts).await;
@ -39,7 +39,6 @@ async fn grid_create_duplicate_field() {
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;
@ -48,7 +47,12 @@ async fn grid_create_duplicate_field() {
#[tokio::test]
async fn grid_update_field_with_empty_change() {
let mut test = GridFieldTest::new().await;
let (params, field_rev) = create_single_select_field(&test.grid_id());
let (params, _) = create_single_select_field(&test.grid_id());
let create_field_index = test.field_count();
let scripts = vec![CreateField { params }];
test.run_scripts(scripts).await;
let field_rev = (&*test.field_revs.clone().pop().unwrap()).clone();
let changeset = FieldChangesetParams {
field_id: field_rev.id.clone(),
grid_id: test.grid_id(),
@ -56,11 +60,10 @@ async fn grid_update_field_with_empty_change() {
};
let scripts = vec![
CreateField { params },
UpdateField { changeset },
AssertFieldEqual {
field_index: test.field_count(),
field_rev,
AssertFieldTypeOptionEqual {
field_index: create_field_index,
expected_type_option_data: field_rev.get_type_option_str(field_rev.ty.clone()).unwrap(),
},
];
test.run_scripts(scripts).await;
@ -69,10 +72,15 @@ async fn grid_update_field_with_empty_change() {
#[tokio::test]
async fn grid_update_field() {
let mut test = GridFieldTest::new().await;
let (params, single_select_field) = create_single_select_field(&test.grid_id());
let (params, _) = create_single_select_field(&test.grid_id());
let scripts = vec![CreateField { params }];
let create_field_index = test.field_count();
test.run_scripts(scripts).await;
//
let single_select_field = (&*test.field_revs.clone().pop().unwrap()).clone();
let mut single_select_type_option = SingleSelectTypeOptionPB::from(&single_select_field);
single_select_type_option.options.push(SelectOptionPB::new("Unknown"));
let changeset = FieldChangesetParams {
field_id: single_select_field.id.clone(),
grid_id: test.grid_id(),
@ -89,11 +97,12 @@ async fn grid_update_field() {
expected_field_rev.insert_type_option(&single_select_type_option);
let scripts = vec![
CreateField { params },
UpdateField { changeset },
AssertFieldEqual {
field_index: test.field_count(),
field_rev: expected_field_rev,
AssertFieldTypeOptionEqual {
field_index: create_field_index,
expected_type_option_data: expected_field_rev
.get_type_option_str(expected_field_rev.ty.clone())
.unwrap(),
},
];
test.run_scripts(scripts).await;
@ -103,9 +112,12 @@ async fn grid_update_field() {
async fn grid_delete_field() {
let mut test = GridFieldTest::new().await;
let original_field_count = test.field_count();
let (params, text_field_rev) = create_text_field(&test.grid_id());
let (params, _) = create_text_field(&test.grid_id());
let scripts = vec![CreateField { params }];
test.run_scripts(scripts).await;
let text_field_rev = (&*test.field_revs.clone().pop().unwrap()).clone();
let scripts = vec![
CreateField { params },
DeleteField {
field_rev: text_field_rev,
},

View File

@ -3,8 +3,8 @@ use flowy_grid::services::field::selection_type_option::SelectOptionPB;
use flowy_grid::services::field::*;
use flowy_grid_data_model::revision::*;
pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
let field_rev = FieldBuilder::new(RichTextTypeOptionBuilder::default())
pub fn create_text_field(grid_id: &str) -> (CreateFieldParams, FieldRevision) {
let mut field_rev = FieldBuilder::new(RichTextTypeOptionBuilder::default())
.name("Name")
.visibility(true)
.build();
@ -17,32 +17,23 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
.protobuf_bytes()
.to_vec();
let field = FieldPB {
id: field_rev.id,
name: field_rev.name,
desc: field_rev.desc,
field_type: field_rev.ty.into(),
frozen: field_rev.frozen,
visibility: field_rev.visibility,
width: field_rev.width,
is_primary: false,
};
let type_option_builder = type_option_builder_from_bytes(type_option_data.clone(), &field_rev.ty.into());
field_rev.insert_type_option(type_option_builder.data_format());
let params = InsertFieldParams {
let params = CreateFieldParams {
grid_id: grid_id.to_owned(),
field,
type_option_data,
start_field_id: None,
field_type: field_rev.ty.into(),
type_option_data: Some(type_option_data),
};
(params, cloned_field_rev)
}
pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) {
pub fn create_single_select_field(grid_id: &str) -> (CreateFieldParams, FieldRevision) {
let single_select = SingleSelectTypeOptionBuilder::default()
.add_option(SelectOptionPB::new("Done"))
.add_option(SelectOptionPB::new("Progress"));
let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build();
let mut field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build();
let cloned_field_rev = field_rev.clone();
let type_option_data = field_rev
.get_type_option::<SingleSelectTypeOptionPB>(field_rev.ty)
@ -50,22 +41,13 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev
.protobuf_bytes()
.to_vec();
let field = FieldPB {
id: field_rev.id,
name: field_rev.name,
desc: field_rev.desc,
field_type: field_rev.ty.into(),
frozen: field_rev.frozen,
visibility: field_rev.visibility,
width: field_rev.width,
is_primary: false,
};
let type_option_builder = type_option_builder_from_bytes(type_option_data.clone(), &field_rev.ty.into());
field_rev.insert_type_option(type_option_builder.data_format());
let params = InsertFieldParams {
let params = CreateFieldParams {
grid_id: grid_id.to_owned(),
field,
type_option_data,
start_field_id: None,
field_type: field_rev.ty.into(),
type_option_data: Some(type_option_data),
};
(params, cloned_field_rev)
}

View File

@ -157,7 +157,6 @@ impl FieldRevision {
pub fn get_type_option<T: TypeOptionDataDeserializer>(&self, field_type_rev: FieldTypeRevision) -> Option<T> {
let id = field_type_rev.to_string();
// TODO: cache the deserialized type option
self.type_options.get(&id).map(|s| T::from_json_str(s))
}

View File

@ -472,7 +472,7 @@ mod tests {
use flowy_folder_data_model::revision::{
AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision,
};
use lib_ot::core::{DeltaBuilder, OperationTransform};
use lib_ot::core::OperationTransform;
#[test]
fn folder_add_workspace() {

View File

@ -1,5 +1,4 @@
use crate::core::{AttributeHashMap, DeltaOperation, DeltaOperations, OperationBuilder, OperationTransform};
use std::fmt::Debug;
use crate::core::{AttributeHashMap, DeltaOperation, DeltaOperations, OperationBuilder};
pub type TextOperations = DeltaOperations<AttributeHashMap>;
pub type TextOperationBuilder = OperationBuilder<AttributeHashMap>;