mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: insert cell content when creating card
This commit is contained in:
@ -52,8 +52,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
|||||||
_startListening();
|
_startListening();
|
||||||
await _loadGrid(emit);
|
await _loadGrid(emit);
|
||||||
},
|
},
|
||||||
createRow: () async {
|
createRow: (groupId) async {
|
||||||
final result = await _dataController.createRow();
|
final result = await _dataController.createBoardCard(groupId);
|
||||||
result.fold(
|
result.fold(
|
||||||
(rowPB) {
|
(rowPB) {
|
||||||
emit(state.copyWith(editingRow: some(rowPB)));
|
emit(state.copyWith(editingRow: some(rowPB)));
|
||||||
@ -153,7 +153,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
|||||||
@freezed
|
@freezed
|
||||||
class BoardEvent with _$BoardEvent {
|
class BoardEvent with _$BoardEvent {
|
||||||
const factory BoardEvent.initial() = InitialGrid;
|
const factory BoardEvent.initial() = InitialGrid;
|
||||||
const factory BoardEvent.createRow() = _CreateRow;
|
const factory BoardEvent.createRow(String groupId) = _CreateRow;
|
||||||
const factory BoardEvent.endEditRow(String rowId) = _EndEditRow;
|
const factory BoardEvent.endEditRow(String rowId) = _EndEditRow;
|
||||||
const factory BoardEvent.didReceiveGroups(List<GroupPB> groups) =
|
const factory BoardEvent.didReceiveGroups(List<GroupPB> groups) =
|
||||||
_DidReceiveGroup;
|
_DidReceiveGroup;
|
||||||
|
@ -21,7 +21,7 @@ typedef OnError = void Function(FlowyError);
|
|||||||
|
|
||||||
class BoardDataController {
|
class BoardDataController {
|
||||||
final String gridId;
|
final String gridId;
|
||||||
final GridService _gridFFIService;
|
final GridFFIService _gridFFIService;
|
||||||
final GridFieldCache fieldCache;
|
final GridFieldCache fieldCache;
|
||||||
|
|
||||||
// key: the block id
|
// key: the block id
|
||||||
@ -45,7 +45,7 @@ class BoardDataController {
|
|||||||
BoardDataController({required ViewPB view})
|
BoardDataController({required ViewPB view})
|
||||||
: gridId = view.id,
|
: gridId = view.id,
|
||||||
_blocks = LinkedHashMap.new(),
|
_blocks = LinkedHashMap.new(),
|
||||||
_gridFFIService = GridService(gridId: view.id),
|
_gridFFIService = GridFFIService(gridId: view.id),
|
||||||
fieldCache = GridFieldCache(gridId: view.id);
|
fieldCache = GridFieldCache(gridId: view.id);
|
||||||
|
|
||||||
void addListener({
|
void addListener({
|
||||||
@ -88,8 +88,8 @@ class BoardDataController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Either<RowPB, FlowyError>> createRow() {
|
Future<Either<RowPB, FlowyError>> createBoardCard(String groupId) {
|
||||||
return _gridFFIService.createRow();
|
return _gridFFIService.createBoardCard(groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
|
@ -88,7 +88,7 @@ class BoardContent extends StatelessWidget {
|
|||||||
height: 50,
|
height: 50,
|
||||||
margin: config.columnItemPadding,
|
margin: config.columnItemPadding,
|
||||||
onAddButtonClick: () {
|
onAddButtonClick: () {
|
||||||
context.read<BoardBloc>().add(const BoardEvent.createRow());
|
context.read<BoardBloc>().add(BoardEvent.createRow(columnData.id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ typedef ListenOnRowChangedCondition = bool Function();
|
|||||||
|
|
||||||
class GridDataController {
|
class GridDataController {
|
||||||
final String gridId;
|
final String gridId;
|
||||||
final GridService _gridFFIService;
|
final GridFFIService _gridFFIService;
|
||||||
final GridFieldCache fieldCache;
|
final GridFieldCache fieldCache;
|
||||||
|
|
||||||
// key: the block id
|
// key: the block id
|
||||||
@ -47,7 +47,7 @@ class GridDataController {
|
|||||||
GridDataController({required ViewPB view})
|
GridDataController({required ViewPB view})
|
||||||
: gridId = view.id,
|
: gridId = view.id,
|
||||||
_blocks = LinkedHashMap.new(),
|
_blocks = LinkedHashMap.new(),
|
||||||
_gridFFIService = GridService(gridId: view.id),
|
_gridFFIService = GridFFIService(gridId: view.id),
|
||||||
fieldCache = GridFieldCache(gridId: view.id);
|
fieldCache = GridFieldCache(gridId: view.id);
|
||||||
|
|
||||||
void addListener({
|
void addListener({
|
||||||
|
@ -3,14 +3,15 @@ import 'package:flowy_sdk/dispatch/dispatch.dart';
|
|||||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid/board_card.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/group.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/group.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
|
||||||
|
|
||||||
class GridService {
|
class GridFFIService {
|
||||||
final String gridId;
|
final String gridId;
|
||||||
GridService({
|
GridFFIService({
|
||||||
required this.gridId,
|
required this.gridId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -27,6 +28,13 @@ class GridService {
|
|||||||
return GridEventCreateRow(payload).send();
|
return GridEventCreateRow(payload).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Either<RowPB, FlowyError>> createBoardCard(String groupId) {
|
||||||
|
CreateBoardCardPayloadPB payload = CreateBoardCardPayloadPB.create()
|
||||||
|
..gridId = gridId
|
||||||
|
..groupId = groupId;
|
||||||
|
return GridEventCreateBoardCard(payload).send();
|
||||||
|
}
|
||||||
|
|
||||||
Future<Either<RepeatedFieldPB, FlowyError>> getFields(
|
Future<Either<RepeatedFieldPB, FlowyError>> getFields(
|
||||||
{required List<FieldIdPB> fieldIds}) {
|
{required List<FieldIdPB> fieldIds}) {
|
||||||
final payload = QueryFieldPayloadPB.create()
|
final payload = QueryFieldPayloadPB.create()
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::entities::RowPB;
|
||||||
use flowy_derive::ProtoBuf;
|
use flowy_derive::ProtoBuf;
|
||||||
use flowy_error::ErrorCode;
|
use flowy_error::ErrorCode;
|
||||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||||
@ -27,3 +28,43 @@ impl TryInto<CreateBoardCardParams> for CreateBoardCardPayloadPB {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, ProtoBuf)]
|
||||||
|
pub struct BoardCardChangesetPB {
|
||||||
|
#[pb(index = 1)]
|
||||||
|
pub group_id: String,
|
||||||
|
|
||||||
|
#[pb(index = 2)]
|
||||||
|
pub inserted_cards: Vec<RowPB>,
|
||||||
|
|
||||||
|
#[pb(index = 3)]
|
||||||
|
pub deleted_cards: Vec<String>,
|
||||||
|
|
||||||
|
#[pb(index = 4)]
|
||||||
|
pub updated_cards: Vec<RowPB>,
|
||||||
|
}
|
||||||
|
impl BoardCardChangesetPB {
|
||||||
|
pub fn insert(group_id: String, inserted_cards: Vec<RowPB>) -> Self {
|
||||||
|
Self {
|
||||||
|
group_id,
|
||||||
|
inserted_cards,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete(group_id: String, deleted_cards: Vec<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
group_id,
|
||||||
|
deleted_cards,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(group_id: String, updated_cards: Vec<RowPB>) -> Self {
|
||||||
|
Self {
|
||||||
|
group_id,
|
||||||
|
updated_cards,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -424,6 +424,6 @@ pub(crate) async fn create_board_card_handler(
|
|||||||
) -> DataResult<RowPB, FlowyError> {
|
) -> DataResult<RowPB, FlowyError> {
|
||||||
let params: CreateBoardCardParams = data.into_inner().try_into()?;
|
let params: CreateBoardCardParams = data.into_inner().try_into()?;
|
||||||
let editor = manager.get_grid_editor(params.grid_id.as_ref())?;
|
let editor = manager.get_grid_editor(params.grid_id.as_ref())?;
|
||||||
let row = editor.create_board_card().await?;
|
let row = editor.create_board_card(¶ms.group_id).await?;
|
||||||
data_result(row)
|
data_result(row)
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
|
|||||||
// Date
|
// Date
|
||||||
.event(GridEvent::UpdateDateCell, update_date_cell_handler)
|
.event(GridEvent::UpdateDateCell, update_date_cell_handler)
|
||||||
// Group
|
// Group
|
||||||
.event(GridEvent::CreateBoardCard, create_row_handler)
|
.event(GridEvent::CreateBoardCard, create_board_card_handler)
|
||||||
.event(GridEvent::GetGroup, get_groups_handler);
|
.event(GridEvent::GetGroup, get_groups_handler);
|
||||||
|
|
||||||
module
|
module
|
||||||
|
@ -135,6 +135,47 @@ pub fn try_decode_cell_data(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_text_cell(s: String, field_rev: &FieldRevision) -> CellRevision {
|
||||||
|
let data = apply_cell_data_changeset(s, None, field_rev).unwrap();
|
||||||
|
CellRevision::new(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_number_cell(num: i64, field_rev: &FieldRevision) -> CellRevision {
|
||||||
|
let data = apply_cell_data_changeset(num, None, field_rev).unwrap();
|
||||||
|
CellRevision::new(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_url_cell(url: String, field_rev: &FieldRevision) -> CellRevision {
|
||||||
|
let data = apply_cell_data_changeset(url, None, field_rev).unwrap();
|
||||||
|
CellRevision::new(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_checkbox_cell(is_check: bool, field_rev: &FieldRevision) -> CellRevision {
|
||||||
|
let s = if is_check {
|
||||||
|
CHECK.to_string()
|
||||||
|
} else {
|
||||||
|
UNCHECK.to_string()
|
||||||
|
};
|
||||||
|
let data = apply_cell_data_changeset(s, None, field_rev).unwrap();
|
||||||
|
CellRevision::new(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_date_cell(timestamp: i64, field_rev: &FieldRevision) -> CellRevision {
|
||||||
|
let cell_data = serde_json::to_string(&DateCellChangesetPB {
|
||||||
|
date: Some(timestamp.to_string()),
|
||||||
|
time: None,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
|
||||||
|
CellRevision::new(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_select_option_cell(option_id: String, field_rev: &FieldRevision) -> CellRevision {
|
||||||
|
let cell_data = SelectOptionCellChangeset::from_insert(&option_id).to_str();
|
||||||
|
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
|
||||||
|
CellRevision::new(data)
|
||||||
|
}
|
||||||
|
|
||||||
/// If the cell data is not String type, it should impl this trait.
|
/// If the cell data is not String type, it should impl this trait.
|
||||||
/// Deserialize the String into cell specific data type.
|
/// Deserialize the String into cell specific data type.
|
||||||
pub trait FromCellString {
|
pub trait FromCellString {
|
||||||
|
@ -552,9 +552,15 @@ impl GridRevisionEditor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_board_card(&self) -> FlowyResult<RowPB> {
|
pub async fn create_board_card(&self, group_id: &str) -> FlowyResult<RowPB> {
|
||||||
let mut row_rev = self.create_row_rev().await?;
|
let mut row_rev = self.create_row_rev().await?;
|
||||||
let _ = self.group_service.write().await.create_board_card(&mut row_rev).await;
|
let _ = self
|
||||||
|
.group_service
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.create_board_card(&mut row_rev, group_id)
|
||||||
|
.await;
|
||||||
|
|
||||||
self.create_row_pb(row_rev, None).await
|
self.create_row_pb(row_rev, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,6 +579,7 @@ impl GridRevisionEditor {
|
|||||||
Ok(row_rev)
|
Ok(row_rev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||||
async fn create_row_pb(&self, row_rev: RowRevision, start_row_id: Option<String>) -> FlowyResult<RowPB> {
|
async fn create_row_pb(&self, row_rev: RowRevision, start_row_id: Option<String>) -> FlowyResult<RowPB> {
|
||||||
let row_pb = RowPB::from(&row_rev);
|
let row_pb = RowPB::from(&row_rev);
|
||||||
let block_id = row_rev.block_id.clone();
|
let block_id = row_rev.block_id.clone();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::entities::{CheckboxGroupConfigurationPB, RowPB};
|
use crate::entities::{CheckboxGroupConfigurationPB, RowPB};
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
use flowy_grid_data_model::revision::RowRevision;
|
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
|
use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
|
||||||
use crate::services::group::{
|
use crate::services::group::{
|
||||||
@ -19,15 +20,19 @@ impl Groupable for CheckboxGroupController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GroupActionHandler for CheckboxGroupController {
|
impl GroupActionHandler for CheckboxGroupController {
|
||||||
|
fn field_id(&self) -> &str {
|
||||||
|
&self.field_id
|
||||||
|
}
|
||||||
|
|
||||||
fn get_groups(&self) -> Vec<Group> {
|
fn get_groups(&self) -> Vec<Group> {
|
||||||
self.groups()
|
self.make_groups()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()> {
|
fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
|
||||||
self.handle_row(row_rev)
|
self.handle_rows(row_revs, field_rev)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_card(&self, row_rev: &mut RowRevision) {
|
fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
use crate::entities::{GroupPB, RowPB};
|
use crate::entities::{GroupPB, RowPB};
|
||||||
use crate::services::cell::{decode_any_cell_data, CellBytesParser};
|
use crate::services::cell::{decode_any_cell_data, CellBytesParser};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::{FlowyError, FlowyResult};
|
||||||
use flowy_grid_data_model::revision::{
|
use flowy_grid_data_model::revision::{
|
||||||
FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer,
|
FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer,
|
||||||
};
|
};
|
||||||
|
use futures::future::BoxFuture;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
use lib_infra::future::{BoxResultFuture, FutureResult};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -34,15 +36,14 @@ pub trait Groupable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait GroupActionHandler: Send + Sync {
|
pub trait GroupActionHandler: Send + Sync {
|
||||||
|
fn field_id(&self) -> &str;
|
||||||
fn get_groups(&self) -> Vec<Group>;
|
fn get_groups(&self) -> Vec<Group>;
|
||||||
fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()>;
|
fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()>;
|
||||||
fn group_rows(&mut self, row_revs: &[Arc<RowRevision>]) -> FlowyResult<()> {
|
fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
|
||||||
for row_rev in row_revs {
|
}
|
||||||
let _ = self.group_row(row_rev)?;
|
|
||||||
}
|
pub trait GroupActionHandler2: Send + Sync {
|
||||||
Ok(())
|
fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str);
|
||||||
}
|
|
||||||
fn create_card(&self, row_rev: &mut RowRevision);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_GROUP_ID: &str = "default_group";
|
const DEFAULT_GROUP_ID: &str = "default_group";
|
||||||
@ -52,8 +53,8 @@ const DEFAULT_GROUP_ID: &str = "default_group";
|
|||||||
/// G: the group container generator
|
/// G: the group container generator
|
||||||
/// P: the parser that impl [CellBytesParser] for the CellBytes
|
/// P: the parser that impl [CellBytesParser] for the CellBytes
|
||||||
pub struct GroupController<C, T, G, P> {
|
pub struct GroupController<C, T, G, P> {
|
||||||
pub field_rev: Arc<FieldRevision>,
|
pub field_id: String,
|
||||||
groups: IndexMap<String, Group>,
|
pub groups_map: IndexMap<String, Group>,
|
||||||
default_group: Group,
|
default_group: Group,
|
||||||
pub type_option: Option<T>,
|
pub type_option: Option<T>,
|
||||||
pub configuration: Option<C>,
|
pub configuration: Option<C>,
|
||||||
@ -86,7 +87,7 @@ where
|
|||||||
G: GroupGenerator<ConfigurationType = C, TypeOptionType = T>,
|
G: GroupGenerator<ConfigurationType = C, TypeOptionType = T>,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
field_rev: Arc<FieldRevision>,
|
field_rev: &Arc<FieldRevision>,
|
||||||
configuration: GroupConfigurationRevision,
|
configuration: GroupConfigurationRevision,
|
||||||
cell_content_provider: &dyn GroupCellContentProvider,
|
cell_content_provider: &dyn GroupCellContentProvider,
|
||||||
) -> FlowyResult<Self> {
|
) -> FlowyResult<Self> {
|
||||||
@ -106,8 +107,8 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
field_rev,
|
field_id: field_rev.id.clone(),
|
||||||
groups: groups.into_iter().map(|group| (group.id.clone(), group)).collect(),
|
groups_map: groups.into_iter().map(|group| (group.id.clone(), group)).collect(),
|
||||||
default_group,
|
default_group,
|
||||||
type_option,
|
type_option,
|
||||||
configuration,
|
configuration,
|
||||||
@ -116,9 +117,9 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn groups(&self) -> Vec<Group> {
|
pub fn make_groups(&self) -> Vec<Group> {
|
||||||
let default_group = self.default_group.clone();
|
let default_group = self.default_group.clone();
|
||||||
let mut groups: Vec<Group> = self.groups.values().cloned().collect();
|
let mut groups: Vec<Group> = self.groups_map.values().cloned().collect();
|
||||||
if !default_group.rows.is_empty() {
|
if !default_group.rows.is_empty() {
|
||||||
groups.push(default_group);
|
groups.push(default_group);
|
||||||
}
|
}
|
||||||
@ -131,34 +132,38 @@ where
|
|||||||
P: CellBytesParser,
|
P: CellBytesParser,
|
||||||
Self: Groupable<CellDataType = P::Object>,
|
Self: Groupable<CellDataType = P::Object>,
|
||||||
{
|
{
|
||||||
pub fn handle_row(&mut self, row: &RowRevision) -> FlowyResult<()> {
|
pub fn handle_rows(&mut self, rows: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
|
||||||
|
// The field_rev might be None if corresponding field_rev is deleted.
|
||||||
if self.configuration.is_none() {
|
if self.configuration.is_none() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if let Some(cell_rev) = row.cells.get(&self.field_rev.id) {
|
|
||||||
let mut records: Vec<GroupRecord> = vec![];
|
|
||||||
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &self.field_rev);
|
|
||||||
let cell_data = cell_bytes.parser::<P>()?;
|
|
||||||
for group in self.groups.values() {
|
|
||||||
if self.can_group(&group.content, &cell_data) {
|
|
||||||
records.push(GroupRecord {
|
|
||||||
row: row.into(),
|
|
||||||
group_id: group.id.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if records.is_empty() {
|
for row in rows {
|
||||||
self.default_group.rows.push(row.into());
|
if let Some(cell_rev) = row.cells.get(&self.field_id) {
|
||||||
} else {
|
let mut records: Vec<GroupRecord> = vec![];
|
||||||
for record in records {
|
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), &field_rev);
|
||||||
if let Some(group) = self.groups.get_mut(&record.group_id) {
|
let cell_data = cell_bytes.parser::<P>()?;
|
||||||
group.rows.push(record.row);
|
for group in self.groups_map.values() {
|
||||||
|
if self.can_group(&group.content, &cell_data) {
|
||||||
|
records.push(GroupRecord {
|
||||||
|
row: row.into(),
|
||||||
|
group_id: group.id.clone(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if records.is_empty() {
|
||||||
|
self.default_group.rows.push(row.into());
|
||||||
|
} else {
|
||||||
|
for record in records {
|
||||||
|
if let Some(group) = self.groups_map.get_mut(&record.group_id) {
|
||||||
|
group.rows.push(record.row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.default_group.rows.push(row.into());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.default_group.rows.push(row.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -166,7 +171,7 @@ where
|
|||||||
|
|
||||||
pub fn group_rows(&mut self, rows: &[Arc<RowRevision>]) -> FlowyResult<()> {
|
pub fn group_rows(&mut self, rows: &[Arc<RowRevision>]) -> FlowyResult<()> {
|
||||||
for row in rows {
|
for row in rows {
|
||||||
let _ = self.handle_row(row)?;
|
// let _ = self.handle_row(row)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use crate::entities::{RowPB, SelectOptionGroupConfigurationPB};
|
use crate::entities::{RowPB, SelectOptionGroupConfigurationPB};
|
||||||
use flowy_error::FlowyResult;
|
use crate::services::cell::insert_select_option_cell;
|
||||||
use flowy_grid_data_model::revision::RowRevision;
|
use flowy_error::{FlowyError, FlowyResult};
|
||||||
|
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
|
||||||
|
use lib_infra::future::FutureResult;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB,
|
MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB,
|
||||||
@ -25,16 +28,27 @@ impl Groupable for SingleSelectGroupController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GroupActionHandler for SingleSelectGroupController {
|
impl GroupActionHandler for SingleSelectGroupController {
|
||||||
|
fn field_id(&self) -> &str {
|
||||||
|
&self.field_id
|
||||||
|
}
|
||||||
|
|
||||||
fn get_groups(&self) -> Vec<Group> {
|
fn get_groups(&self) -> Vec<Group> {
|
||||||
self.groups()
|
self.make_groups()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()> {
|
fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
|
||||||
self.handle_row(row_rev)
|
self.handle_rows(row_revs, field_rev)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_card(&self, row_rev: &mut RowRevision) {
|
fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
|
||||||
todo!()
|
let group: Option<&Group> = self.groups_map.get(group_id);
|
||||||
|
match group {
|
||||||
|
None => {}
|
||||||
|
Some(group) => {
|
||||||
|
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
|
||||||
|
row_rev.cells.insert(field_rev.id.clone(), cell_rev);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,16 +93,27 @@ impl Groupable for MultiSelectGroupController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GroupActionHandler for MultiSelectGroupController {
|
impl GroupActionHandler for MultiSelectGroupController {
|
||||||
|
fn field_id(&self) -> &str {
|
||||||
|
&self.field_id
|
||||||
|
}
|
||||||
|
|
||||||
fn get_groups(&self) -> Vec<Group> {
|
fn get_groups(&self) -> Vec<Group> {
|
||||||
self.groups()
|
self.make_groups()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group_row(&mut self, row_rev: &RowRevision) -> FlowyResult<()> {
|
fn group_rows(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
|
||||||
self.handle_row(row_rev)
|
self.handle_rows(row_revs, field_rev)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_card(&self, row_rev: &mut RowRevision) {
|
fn create_card(&self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
|
||||||
todo!()
|
let group: Option<&Group> = self.groups_map.get(group_id);
|
||||||
|
match group {
|
||||||
|
None => tracing::warn!("Can not find the group: {}", group_id),
|
||||||
|
Some(group) => {
|
||||||
|
let cell_rev = insert_select_option_cell(group.id.clone(), field_rev);
|
||||||
|
row_rev.cells.insert(field_rev.id.clone(), cell_rev);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ use bytes::Bytes;
|
|||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
use flowy_grid_data_model::revision::{gen_grid_group_id, FieldRevision, GroupConfigurationRevision, RowRevision};
|
use flowy_grid_data_model::revision::{gen_grid_group_id, FieldRevision, GroupConfigurationRevision, RowRevision};
|
||||||
use flowy_sync::client_grid::GridRevisionPad;
|
use flowy_sync::client_grid::GridRevisionPad;
|
||||||
|
use futures::future::BoxFuture;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
@ -61,9 +62,24 @@ impl GridGroupService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn create_board_card(&self, row_rev: &mut RowRevision) {
|
#[tracing::instrument(level = "debug", skip(self, row_rev))]
|
||||||
|
pub(crate) async fn create_board_card(&self, row_rev: &mut RowRevision, group_id: &str) {
|
||||||
if let Some(group_action_handler) = self.group_action_handler.as_ref() {
|
if let Some(group_action_handler) = self.group_action_handler.as_ref() {
|
||||||
group_action_handler.write().await.create_card(row_rev);
|
match self
|
||||||
|
.grid_pad
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.get_field_rev(group_action_handler.read().await.field_id())
|
||||||
|
{
|
||||||
|
None => tracing::warn!("Fail to create card because the field does not exist"),
|
||||||
|
Some((_, field_rev)) => {
|
||||||
|
tracing::trace!("Create card");
|
||||||
|
group_action_handler
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.create_card(row_rev, field_rev, group_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,15 +116,15 @@ impl GridGroupService {
|
|||||||
// let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
|
// let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
|
||||||
}
|
}
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
let controller = SingleSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
|
let controller = SingleSelectGroupController::new(field_rev, configuration, &self.grid_pad)?;
|
||||||
self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
|
self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
|
||||||
}
|
}
|
||||||
FieldType::MultiSelect => {
|
FieldType::MultiSelect => {
|
||||||
let controller = MultiSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
|
let controller = MultiSelectGroupController::new(field_rev, configuration, &self.grid_pad)?;
|
||||||
self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
|
self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
|
||||||
}
|
}
|
||||||
FieldType::Checkbox => {
|
FieldType::Checkbox => {
|
||||||
let controller = CheckboxGroupController::new(field_rev.clone(), configuration, &self.grid_pad)?;
|
let controller = CheckboxGroupController::new(field_rev, configuration, &self.grid_pad)?;
|
||||||
self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
|
self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
|
||||||
}
|
}
|
||||||
FieldType::URL => {
|
FieldType::URL => {
|
||||||
@ -119,7 +135,7 @@ impl GridGroupService {
|
|||||||
let mut groups = vec![];
|
let mut groups = vec![];
|
||||||
if let Some(group_action_handler) = self.group_action_handler.as_ref() {
|
if let Some(group_action_handler) = self.group_action_handler.as_ref() {
|
||||||
let mut write_guard = group_action_handler.write().await;
|
let mut write_guard = group_action_handler.write().await;
|
||||||
let _ = write_guard.group_rows(&row_revs)?;
|
let _ = write_guard.group_rows(&row_revs, field_rev)?;
|
||||||
groups = write_guard.get_groups();
|
groups = write_guard.get_groups();
|
||||||
drop(write_guard);
|
drop(write_guard);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use crate::services::cell::apply_cell_data_changeset;
|
use crate::services::cell::{
|
||||||
|
apply_cell_data_changeset, insert_checkbox_cell, insert_date_cell, insert_number_cell, insert_select_option_cell,
|
||||||
|
insert_text_cell, insert_url_cell,
|
||||||
|
};
|
||||||
use crate::services::field::{DateCellChangesetPB, SelectOptionCellChangeset};
|
use crate::services::field::{DateCellChangesetPB, SelectOptionCellChangeset};
|
||||||
use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT};
|
use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
@ -34,47 +37,68 @@ impl<'a> RowRevisionBuilder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_cell(&mut self, field_id: &str, data: String) {
|
pub fn insert_text_cell(&mut self, field_id: &str, data: String) {
|
||||||
match self.field_rev_map.get(&field_id.to_owned()) {
|
match self.field_rev_map.get(&field_id.to_owned()) {
|
||||||
None => {
|
None => tracing::warn!("Can't find the text field with id: {}", field_id),
|
||||||
tracing::warn!("Can't find the field with id: {}", field_id);
|
|
||||||
}
|
|
||||||
Some(field_rev) => {
|
Some(field_rev) => {
|
||||||
let data = apply_cell_data_changeset(data, None, field_rev).unwrap();
|
self.payload
|
||||||
let cell = CellRevision::new(data);
|
.cell_by_field_id
|
||||||
self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
|
.insert(field_id.to_owned(), insert_text_cell(data, field_rev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_url_cell(&mut self, field_id: &str, data: String) {
|
||||||
|
match self.field_rev_map.get(&field_id.to_owned()) {
|
||||||
|
None => tracing::warn!("Can't find the url field with id: {}", field_id),
|
||||||
|
Some(field_rev) => {
|
||||||
|
self.payload
|
||||||
|
.cell_by_field_id
|
||||||
|
.insert(field_id.to_owned(), insert_url_cell(data, field_rev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_number_cell(&mut self, field_id: &str, num: i64) {
|
||||||
|
match self.field_rev_map.get(&field_id.to_owned()) {
|
||||||
|
None => tracing::warn!("Can't find the number field with id: {}", field_id),
|
||||||
|
Some(field_rev) => {
|
||||||
|
self.payload
|
||||||
|
.cell_by_field_id
|
||||||
|
.insert(field_id.to_owned(), insert_number_cell(num, field_rev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_checkbox_cell(&mut self, field_id: &str, is_check: bool) {
|
||||||
|
match self.field_rev_map.get(&field_id.to_owned()) {
|
||||||
|
None => tracing::warn!("Can't find the checkbox field with id: {}", field_id),
|
||||||
|
Some(field_rev) => {
|
||||||
|
self.payload
|
||||||
|
.cell_by_field_id
|
||||||
|
.insert(field_id.to_owned(), insert_checkbox_cell(is_check, field_rev));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_date_cell(&mut self, field_id: &str, timestamp: i64) {
|
pub fn insert_date_cell(&mut self, field_id: &str, timestamp: i64) {
|
||||||
match self.field_rev_map.get(&field_id.to_owned()) {
|
match self.field_rev_map.get(&field_id.to_owned()) {
|
||||||
None => {
|
None => tracing::warn!("Can't find the date field with id: {}", field_id),
|
||||||
tracing::warn!("Invalid field_id: {}", field_id);
|
|
||||||
}
|
|
||||||
Some(field_rev) => {
|
Some(field_rev) => {
|
||||||
let cell_data = serde_json::to_string(&DateCellChangesetPB {
|
self.payload
|
||||||
date: Some(timestamp.to_string()),
|
.cell_by_field_id
|
||||||
time: None,
|
.insert(field_id.to_owned(), insert_date_cell(timestamp, field_rev));
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
|
|
||||||
let cell = CellRevision::new(data);
|
|
||||||
self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_select_option_cell(&mut self, field_id: &str, data: String) {
|
pub fn insert_select_option_cell(&mut self, field_id: &str, data: String) {
|
||||||
match self.field_rev_map.get(&field_id.to_owned()) {
|
match self.field_rev_map.get(&field_id.to_owned()) {
|
||||||
None => {
|
None => tracing::warn!("Can't find the select option field with id: {}", field_id),
|
||||||
tracing::warn!("Invalid field_id: {}", field_id);
|
|
||||||
}
|
|
||||||
Some(field_rev) => {
|
Some(field_rev) => {
|
||||||
let cell_data = SelectOptionCellChangeset::from_insert(&data).to_str();
|
self.payload
|
||||||
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
|
.cell_by_field_id
|
||||||
let cell = CellRevision::new(data);
|
.insert(field_id.to_owned(), insert_select_option_cell(data, field_rev));
|
||||||
self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,20 +114,15 @@ pub fn make_default_board() -> BuildGridContext {
|
|||||||
row_builder.insert_select_option_cell(&multi_select_field_id, apple_option.id.clone());
|
row_builder.insert_select_option_cell(&multi_select_field_id, apple_option.id.clone());
|
||||||
row_builder.insert_select_option_cell(&multi_select_field_id, banana_option.id.clone());
|
row_builder.insert_select_option_cell(&multi_select_field_id, banana_option.id.clone());
|
||||||
// insert text
|
// insert text
|
||||||
row_builder.insert_cell(&text_field_id, format!("Card {}", i));
|
row_builder.insert_text_cell(&text_field_id, format!("Card {}", i));
|
||||||
// insert date
|
// insert date
|
||||||
row_builder.insert_date_cell(&date_field_id, timestamp);
|
row_builder.insert_date_cell(&date_field_id, timestamp);
|
||||||
// number
|
// number
|
||||||
row_builder.insert_cell(&number_field_id, format!("{}", i));
|
row_builder.insert_number_cell(&number_field_id, i);
|
||||||
// checkbox
|
// checkbox
|
||||||
let is_check = if i % 2 == 0 {
|
row_builder.insert_checkbox_cell(&checkbox_field_id, i % 2 == 0);
|
||||||
CHECK.to_string()
|
|
||||||
} else {
|
|
||||||
UNCHECK.to_string()
|
|
||||||
};
|
|
||||||
row_builder.insert_cell(&checkbox_field_id, is_check);
|
|
||||||
// url
|
// url
|
||||||
row_builder.insert_cell(&url_field_id, "https://appflowy.io".to_string());
|
row_builder.insert_url_cell(&url_field_id, "https://appflowy.io".to_string());
|
||||||
|
|
||||||
let row = row_builder.build();
|
let row = row_builder.build();
|
||||||
grid_builder.add_row(row);
|
grid_builder.add_row(row);
|
||||||
|
@ -26,14 +26,14 @@ impl<'a> GridRowTestBuilder<'a> {
|
|||||||
|
|
||||||
pub fn insert_text_cell(&mut self, data: &str) -> String {
|
pub fn insert_text_cell(&mut self, data: &str) -> String {
|
||||||
let text_field = self.field_rev_with_type(&FieldType::RichText);
|
let text_field = self.field_rev_with_type(&FieldType::RichText);
|
||||||
self.inner_builder.insert_cell(&text_field.id, data.to_string());
|
self.inner_builder.insert_text_cell(&text_field.id, data.to_string());
|
||||||
|
|
||||||
text_field.id.clone()
|
text_field.id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_number_cell(&mut self, data: &str) -> String {
|
pub fn insert_number_cell(&mut self, data: &str) -> String {
|
||||||
let number_field = self.field_rev_with_type(&FieldType::Number);
|
let number_field = self.field_rev_with_type(&FieldType::Number);
|
||||||
self.inner_builder.insert_cell(&number_field.id, data.to_string());
|
self.inner_builder.insert_text_cell(&number_field.id, data.to_string());
|
||||||
number_field.id.clone()
|
number_field.id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,20 +44,21 @@ impl<'a> GridRowTestBuilder<'a> {
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let date_field = self.field_rev_with_type(&FieldType::DateTime);
|
let date_field = self.field_rev_with_type(&FieldType::DateTime);
|
||||||
self.inner_builder.insert_cell(&date_field.id, value);
|
self.inner_builder.insert_text_cell(&date_field.id, value);
|
||||||
date_field.id.clone()
|
date_field.id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_checkbox_cell(&mut self, data: &str) -> String {
|
pub fn insert_checkbox_cell(&mut self, data: &str) -> String {
|
||||||
let checkbox_field = self.field_rev_with_type(&FieldType::Checkbox);
|
let checkbox_field = self.field_rev_with_type(&FieldType::Checkbox);
|
||||||
self.inner_builder.insert_cell(&checkbox_field.id, data.to_string());
|
self.inner_builder
|
||||||
|
.insert_text_cell(&checkbox_field.id, data.to_string());
|
||||||
|
|
||||||
checkbox_field.id.clone()
|
checkbox_field.id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_url_cell(&mut self, data: &str) -> String {
|
pub fn insert_url_cell(&mut self, data: &str) -> String {
|
||||||
let url_field = self.field_rev_with_type(&FieldType::URL);
|
let url_field = self.field_rev_with_type(&FieldType::URL);
|
||||||
self.inner_builder.insert_cell(&url_field.id, data.to_string());
|
self.inner_builder.insert_text_cell(&url_field.id, data.to_string());
|
||||||
url_field.id.clone()
|
url_field.id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ impl GridRevisionPad {
|
|||||||
.blocks
|
.blocks
|
||||||
.iter()
|
.iter()
|
||||||
.map(|block| {
|
.map(|block| {
|
||||||
let mut duplicated_block = (&*block.clone()).clone();
|
let mut duplicated_block = (&**block).clone();
|
||||||
duplicated_block.block_id = gen_block_id();
|
duplicated_block.block_id = gen_block_id();
|
||||||
duplicated_block
|
duplicated_block
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user