fix: create the default group for grid

This commit is contained in:
appflowy 2022-09-23 11:23:35 +08:00
parent 6a1b84a098
commit 44ad0a2623
11 changed files with 125 additions and 48 deletions

View File

@ -283,7 +283,12 @@ class IGridCellController<T, D> extends Equatable {
_loadDataOperation?.cancel();
_loadDataOperation = Timer(const Duration(milliseconds: 10), () {
_cellDataLoader.loadData().then((data) {
_cellsCache.insert(_cacheKey, GridCell(object: data));
if (data != null) {
_cellsCache.insert(_cacheKey, GridCell(object: data));
} else {
_cellsCache.remove(_cacheKey);
}
_cellDataNotifier?.value = data;
});
});

View File

@ -221,8 +221,9 @@ impl DefaultFolderBuilder {
initial_quill_delta_string()
};
let _ = view_controller.set_latest_view(&view.id);
let layout_type = ViewLayoutTypePB::from(view.layout.clone());
let _ = view_controller
.create_view(&view.id, ViewDataTypePB::Text, Bytes::from(view_data))
.create_view(&view.id, ViewDataTypePB::Text, layout_type, Bytes::from(view_data))
.await?;
}
}
@ -249,7 +250,13 @@ impl FolderManager {
pub trait ViewDataProcessor {
fn initialize(&self) -> FutureResult<(), FlowyError>;
fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError>;
fn create_container(
&self,
user_id: &str,
view_id: &str,
layout: ViewLayoutTypePB,
delta_data: Bytes,
) -> FutureResult<(), FlowyError>;
fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
@ -267,6 +274,7 @@ pub trait ViewDataProcessor {
user_id: &str,
view_id: &str,
data: Vec<u8>,
layout: ViewLayoutTypePB,
) -> FutureResult<Bytes, FlowyError>;
fn data_type(&self) -> ViewDataTypePB;

View File

@ -1,5 +1,5 @@
pub use crate::entities::view::ViewDataTypePB;
use crate::entities::ViewInfoPB;
use crate::entities::{ViewInfoPB, ViewLayoutTypePB};
use crate::manager::{ViewDataProcessor, ViewDataProcessorMap};
use crate::{
dart_notification::{send_dart_notification, FolderNotification},
@ -67,10 +67,20 @@ impl ViewController {
params.view_content_data = view_data.to_vec();
} else {
let delta_data = processor
.create_view_from_delta_data(&user_id, &params.view_id, params.view_content_data.clone())
.create_view_from_delta_data(
&user_id,
&params.view_id,
params.view_content_data.clone(),
params.layout.clone(),
)
.await?;
let _ = self
.create_view(&params.view_id, params.data_type.clone(), delta_data)
.create_view(
&params.view_id,
params.data_type.clone(),
params.layout.clone(),
delta_data,
)
.await?;
};
@ -84,6 +94,7 @@ impl ViewController {
&self,
view_id: &str,
data_type: ViewDataTypePB,
layout_type: ViewLayoutTypePB,
delta_data: Bytes,
) -> Result<(), FlowyError> {
if delta_data.is_empty() {
@ -91,7 +102,9 @@ impl ViewController {
}
let user_id = self.user.user_id()?;
let processor = self.get_data_processor(data_type)?;
let _ = processor.create_container(&user_id, view_id, delta_data).await?;
let _ = processor
.create_container(&user_id, view_id, layout_type, delta_data)
.await?;
Ok(())
}

View File

@ -1,3 +1,4 @@
use crate::entities::GridLayout;
use crate::services::block_editor::GridBlockRevisionCompactor;
use crate::services::grid_editor::{GridRevisionCompactor, GridRevisionEditor};
use crate::services::grid_view_manager::make_grid_view_rev_manager;
@ -178,6 +179,7 @@ impl GridManager {
pub async fn make_grid_view_data(
user_id: &str,
view_id: &str,
layout: GridLayout,
grid_manager: Arc<GridManager>,
build_context: BuildGridContext,
) -> FlowyResult<Bytes> {
@ -208,7 +210,7 @@ pub async fn make_grid_view_data(
let _ = grid_manager.create_grid(&grid_id, repeated_revision).await?;
// Create grid view
let grid_view = GridViewRevision::new(grid_id, view_id.to_owned());
let grid_view = GridViewRevision::new(grid_id, view_id.to_owned(), layout.into());
let grid_view_delta = make_grid_view_delta(&grid_view);
let grid_view_delta_bytes = grid_view_delta.json_bytes();
let repeated_revision: RepeatedRevision =

View File

@ -277,6 +277,7 @@ impl GridViewRevisionEditor {
Ok(())
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn group_by_field(&self, field_id: &str) -> FlowyResult<()> {
if let Some(field_rev) = self.field_delegate.get_field_rev(field_id).await {
let new_group_controller = new_group_controller_with_field_rev(
@ -374,13 +375,14 @@ impl GridViewRevisionEditor {
async fn new_group_controller(
user_id: String,
view_id: String,
pad: Arc<RwLock<GridViewRevisionPad>>,
view_rev_pad: Arc<RwLock<GridViewRevisionPad>>,
rev_manager: Arc<RevisionManager>,
field_delegate: Arc<dyn GridViewFieldDelegate>,
row_delegate: Arc<dyn GridViewRowDelegate>,
) -> FlowyResult<Box<dyn GroupController>> {
let configuration_reader = GroupConfigurationReaderImpl(pad.clone());
let configuration_reader = GroupConfigurationReaderImpl(view_rev_pad.clone());
let field_revs = field_delegate.get_field_revs().await;
let layout = view_rev_pad.read().await.layout();
// Read the group field or find a new group field
let field_rev = configuration_reader
.get_configuration()
@ -391,24 +393,24 @@ async fn new_group_controller(
.find(|field_rev| field_rev.id == configuration.field_id)
.cloned()
})
.unwrap_or_else(|| find_group_field(&field_revs).unwrap());
.unwrap_or_else(|| find_group_field(&field_revs, &layout).unwrap());
new_group_controller_with_field_rev(user_id, view_id, pad, rev_manager, field_rev, row_delegate).await
new_group_controller_with_field_rev(user_id, view_id, view_rev_pad, rev_manager, field_rev, row_delegate).await
}
async fn new_group_controller_with_field_rev(
user_id: String,
view_id: String,
pad: Arc<RwLock<GridViewRevisionPad>>,
view_rev_pad: Arc<RwLock<GridViewRevisionPad>>,
rev_manager: Arc<RevisionManager>,
field_rev: Arc<FieldRevision>,
row_delegate: Arc<dyn GridViewRowDelegate>,
) -> FlowyResult<Box<dyn GroupController>> {
let configuration_reader = GroupConfigurationReaderImpl(pad.clone());
let configuration_reader = GroupConfigurationReaderImpl(view_rev_pad.clone());
let configuration_writer = GroupConfigurationWriterImpl {
user_id,
rev_manager,
view_pad: pad,
view_pad: view_rev_pad,
};
let row_revs = row_delegate.gv_row_revs().await;
make_group_controller(view_id, field_rev, row_revs, configuration_reader, configuration_writer).await

View File

@ -8,7 +8,7 @@ use crate::services::group::{
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
CheckboxGroupConfigurationRevision, DateGroupConfigurationRevision, FieldRevision, GroupConfigurationRevision,
NumberGroupConfigurationRevision, RowRevision, SelectOptionGroupConfigurationRevision,
LayoutRevision, NumberGroupConfigurationRevision, RowRevision, SelectOptionGroupConfigurationRevision,
TextGroupConfigurationRevision, UrlGroupConfigurationRevision,
};
use std::sync::Arc;
@ -62,15 +62,17 @@ where
Ok(group_controller)
}
pub fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<Arc<FieldRevision>> {
let field_rev = field_revs
.iter()
.find(|field_rev| {
let field_type: FieldType = field_rev.ty.into();
field_type.can_be_group()
})
.cloned();
field_rev
pub fn find_group_field(field_revs: &[Arc<FieldRevision>], layout: &LayoutRevision) -> Option<Arc<FieldRevision>> {
match layout {
LayoutRevision::Table => field_revs.iter().find(|field_rev| field_rev.is_primary).cloned(),
LayoutRevision::Board => field_revs
.iter()
.find(|field_rev| {
let field_type: FieldType = field_rev.ty.into();
field_type.can_be_group()
})
.cloned(),
}
}
pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurationRevision {

View File

@ -7,6 +7,7 @@ use flowy_folder::{
event_map::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser},
manager::FolderManager,
};
use flowy_grid::entities::GridLayout;
use flowy_grid::manager::{make_grid_view_data, GridManager};
use flowy_grid::util::{make_default_board, make_default_grid};
use flowy_grid_data_model::revision::BuildGridContext;
@ -142,7 +143,15 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
FutureResult::new(async move { manager.init() })
}
fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError> {
fn create_container(
&self,
user_id: &str,
view_id: &str,
layout: ViewLayoutTypePB,
delta_data: Bytes,
) -> FutureResult<(), FlowyError> {
// Only accept Document type
debug_assert_eq!(layout, ViewLayoutTypePB::Document);
let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, delta_data).into();
let view_id = view_id.to_string();
let manager = self.0.clone();
@ -196,7 +205,9 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
_user_id: &str,
_view_id: &str,
data: Vec<u8>,
layout: ViewLayoutTypePB,
) -> FutureResult<Bytes, FlowyError> {
debug_assert_eq!(layout, ViewLayoutTypePB::Document);
FutureResult::new(async move { Ok(Bytes::from(data)) })
}
@ -211,7 +222,13 @@ impl ViewDataProcessor for GridViewDataProcessor {
FutureResult::new(async { Ok(()) })
}
fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError> {
fn create_container(
&self,
user_id: &str,
view_id: &str,
_layout: ViewLayoutTypePB,
delta_data: Bytes,
) -> FutureResult<(), FlowyError> {
let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, delta_data).into();
let view_id = view_id.to_string();
let grid_manager = self.0.clone();
@ -246,19 +263,22 @@ impl ViewDataProcessor for GridViewDataProcessor {
view_id: &str,
layout: ViewLayoutTypePB,
) -> FutureResult<Bytes, FlowyError> {
let build_context = match layout {
ViewLayoutTypePB::Grid => make_default_grid(),
ViewLayoutTypePB::Board => make_default_board(),
let (build_context, layout) = match layout {
ViewLayoutTypePB::Grid => (make_default_grid(), GridLayout::Table),
ViewLayoutTypePB::Board => (make_default_board(), GridLayout::Board),
ViewLayoutTypePB::Document => {
return FutureResult::new(async move {
Err(FlowyError::internal().context(format!("Can't handle {:?} layout type", layout)))
});
}
};
let user_id = user_id.to_string();
let view_id = view_id.to_string();
let grid_manager = self.0.clone();
FutureResult::new(async move { make_grid_view_data(&user_id, &view_id, grid_manager, build_context).await })
FutureResult::new(
async move { make_grid_view_data(&user_id, &view_id, layout, grid_manager, build_context).await },
)
}
fn create_view_from_delta_data(
@ -266,15 +286,26 @@ impl ViewDataProcessor for GridViewDataProcessor {
user_id: &str,
view_id: &str,
data: Vec<u8>,
layout: ViewLayoutTypePB,
) -> FutureResult<Bytes, FlowyError> {
let user_id = user_id.to_string();
let view_id = view_id.to_string();
let grid_manager = self.0.clone();
let layout = match layout {
ViewLayoutTypePB::Grid => GridLayout::Table,
ViewLayoutTypePB::Board => GridLayout::Board,
ViewLayoutTypePB::Document => {
return FutureResult::new(async move {
Err(FlowyError::internal().context(format!("Can't handle {:?} layout type", layout)))
});
}
};
FutureResult::new(async move {
let bytes = Bytes::from(data);
let build_context = BuildGridContext::try_from(bytes)?;
make_grid_view_data(&user_id, &view_id, grid_manager, build_context).await
make_grid_view_data(&user_id, &view_id, layout, grid_manager, build_context).await
})
}

View File

@ -48,11 +48,11 @@ pub struct GridViewRevision {
}
impl GridViewRevision {
pub fn new(grid_id: String, view_id: String) -> Self {
pub fn new(grid_id: String, view_id: String, layout: LayoutRevision) -> Self {
GridViewRevision {
view_id,
grid_id,
layout: Default::default(),
layout,
filters: Default::default(),
groups: Default::default(),
// row_orders: vec![],

View File

@ -1,5 +1,5 @@
use crate::entities::revision::{md5, RepeatedRevision, Revision};
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::errors::{internal_error, CollaborateError, CollaborateResult };
use crate::util::{cal_diff, make_text_delta_from_revisions};
use bytes::Bytes;
use flowy_grid_data_model::revision::{
@ -103,8 +103,12 @@ impl GridRevisionPad {
|grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) {
None => Ok(None),
Some(index) => {
grid_meta.fields.remove(index);
Ok(Some(()))
if grid_meta.fields[index].is_primary {
Err(CollaborateError::can_not_delete_primary_field())
} else {
grid_meta.fields.remove(index);
Ok(Some(()))
}
}
},
)

View File

@ -3,7 +3,7 @@ use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_text_delta_from_revisions};
use flowy_grid_data_model::revision::{
FieldRevision, FieldTypeRevision, FilterConfigurationRevision, FilterConfigurationsByFieldId, GridViewRevision,
GroupConfigurationRevision, GroupConfigurationsByFieldId,
GroupConfigurationRevision, GroupConfigurationsByFieldId, LayoutRevision,
};
use lib_ot::core::{Delta, DeltaBuilder, EmptyAttributes, OperationTransform};
use std::sync::Arc;
@ -25,8 +25,8 @@ impl std::ops::Deref for GridViewRevisionPad {
impl GridViewRevisionPad {
// For the moment, the view_id is equal to grid_id. The grid_id represents the database id.
// A database can be referenced by multiple views.
pub fn new(grid_id: String, view_id: String) -> Self {
let view = Arc::new(GridViewRevision::new(grid_id, view_id));
pub fn new(grid_id: String, view_id: String, layout: LayoutRevision) -> Self {
let view = Arc::new(GridViewRevision::new(grid_id, view_id, layout));
let json = serde_json::to_string(&view).unwrap();
let delta = DeltaBuilder::new().insert(&json).build();
Self { view, delta }
@ -34,7 +34,11 @@ impl GridViewRevisionPad {
pub fn from_delta(view_id: &str, delta: Delta) -> CollaborateResult<Self> {
if delta.is_empty() {
return Ok(GridViewRevisionPad::new(view_id.to_owned(), view_id.to_owned()));
return Ok(GridViewRevisionPad::new(
view_id.to_owned(),
view_id.to_owned(),
LayoutRevision::Table,
));
}
let s = delta.content()?;
let view: GridViewRevision = serde_json::from_str(&s).map_err(|e| {
@ -163,6 +167,10 @@ impl GridViewRevisionPad {
make_grid_view_rev_json_str(&self.view)
}
pub fn layout(&self) -> LayoutRevision {
self.layout.clone()
}
fn modify<F>(&mut self, f: F) -> CollaborateResult<Option<GridViewRevisionChangeset>>
where
F: FnOnce(&mut GridViewRevision) -> CollaborateResult<Option<()>>,

View File

@ -1,7 +1,7 @@
use std::{fmt, fmt::Debug};
use strum_macros::Display;
macro_rules! static_doc_error {
macro_rules! static_error {
($name:ident, $status:expr) => {
#[allow(non_snake_case, missing_docs)]
pub fn $name() -> CollaborateError {
@ -34,12 +34,13 @@ impl CollaborateError {
self
}
static_doc_error!(internal, ErrorCode::InternalError);
static_doc_error!(undo, ErrorCode::UndoFail);
static_doc_error!(redo, ErrorCode::RedoFail);
static_doc_error!(out_of_bound, ErrorCode::OutOfBound);
static_doc_error!(record_not_found, ErrorCode::RecordNotFound);
static_doc_error!(revision_conflict, ErrorCode::RevisionConflict);
static_error!(internal, ErrorCode::InternalError);
static_error!(undo, ErrorCode::UndoFail);
static_error!(redo, ErrorCode::RedoFail);
static_error!(out_of_bound, ErrorCode::OutOfBound);
static_error!(record_not_found, ErrorCode::RecordNotFound);
static_error!(revision_conflict, ErrorCode::RevisionConflict);
static_error!(can_not_delete_primary_field, ErrorCode::CannotDeleteThePrimaryField);
}
impl fmt::Display for CollaborateError {
@ -57,6 +58,7 @@ pub enum ErrorCode {
OutOfBound = 202,
RevisionConflict = 203,
RecordNotFound = 300,
CannotDeleteThePrimaryField = 301,
InternalError = 1000,
}