mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: row document (#2792)
* chore: create orphan view handler * feat: save icon url and cover url in view * feat: implement emoji picker UI * chore: config ui * chore: config ui again * chore: replace RowPB with RowMetaPB to exposing more row information * fix: compile error * feat: show emoji in row * chore: update * test: insert emoji test * test: add update emoji test * test: add remove emoji test * test: add create field tests * test: add create row and delete row integration tests * test: add create row from row menu * test: document in row detail page * test: delete, duplicate row in row detail page * test: check the row count displayed in grid page * test: rename existing field in grid page * test: update field type of exisiting field in grid page * test: delete field test * test: add duplicate field test * test: add hide field test * test: add edit text cell test * test: add insert text to text cell test * test: add edit number cell test * test: add edit multiple number cells * test: add edit checkbox cell test * feat: integrate editor into database row * test: add edit create time and last edit time cell test * test: add edit date cell by selecting a date test * chore: remove unused code * chore: update checklist bg color * test: add update database layout test --------- Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
@ -2,6 +2,7 @@ use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
use flowy_error::ErrorCode;
|
||||
|
||||
use crate::entities::parser::NotEmptyStr;
|
||||
use crate::entities::RowMetaPB;
|
||||
use crate::services::setting::{CalendarLayout, CalendarLayoutSetting};
|
||||
|
||||
use super::CellIdPB;
|
||||
@ -99,7 +100,7 @@ impl TryInto<CalendarEventRequestParams> for CalendarEventRequestPB {
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct CalendarEventPB {
|
||||
#[pb(index = 1)]
|
||||
pub row_id: String,
|
||||
pub row_meta: RowMetaPB,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub date_field_id: String,
|
||||
|
@ -6,7 +6,7 @@ use flowy_derive::ProtoBuf;
|
||||
use flowy_error::{ErrorCode, FlowyError};
|
||||
|
||||
use crate::entities::parser::NotEmptyStr;
|
||||
use crate::entities::{DatabaseLayoutPB, FieldIdPB, RowPB};
|
||||
use crate::entities::{DatabaseLayoutPB, FieldIdPB, RowMetaPB};
|
||||
use crate::services::database::CreateDatabaseViewParams;
|
||||
|
||||
/// [DatabasePB] describes how many fields and blocks the grid has
|
||||
@ -19,7 +19,7 @@ pub struct DatabasePB {
|
||||
pub fields: Vec<FieldIdPB>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub rows: Vec<RowPB>,
|
||||
pub rows: Vec<RowMetaPB>,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub layout_type: DatabaseLayoutPB,
|
||||
|
@ -4,7 +4,7 @@ use flowy_derive::ProtoBuf;
|
||||
use flowy_error::ErrorCode;
|
||||
|
||||
use crate::entities::parser::NotEmptyStr;
|
||||
use crate::entities::{FieldType, RowPB};
|
||||
use crate::entities::{FieldType, RowMetaPB};
|
||||
use crate::services::group::{GroupChangeset, GroupData, GroupSetting};
|
||||
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
@ -79,7 +79,7 @@ pub struct GroupPB {
|
||||
pub group_name: String,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub rows: Vec<RowPB>,
|
||||
pub rows: Vec<RowMetaPB>,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub is_default: bool,
|
||||
@ -94,7 +94,11 @@ impl std::convert::From<GroupData> for GroupPB {
|
||||
field_id: group_data.field_id,
|
||||
group_id: group_data.id,
|
||||
group_name: group_data.name,
|
||||
rows: group_data.rows.into_iter().map(RowPB::from).collect(),
|
||||
rows: group_data
|
||||
.rows
|
||||
.into_iter()
|
||||
.map(|row_detail| RowMetaPB::from(row_detail.meta))
|
||||
.collect(),
|
||||
is_default: group_data.is_default,
|
||||
is_visible: group_data.is_visible,
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use flowy_derive::ProtoBuf;
|
||||
use flowy_error::ErrorCode;
|
||||
|
||||
use crate::entities::parser::NotEmptyStr;
|
||||
use crate::entities::{GroupPB, InsertedRowPB, RowPB};
|
||||
use crate::entities::{GroupPB, InsertedRowPB, RowMetaPB};
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct GroupRowsNotificationPB {
|
||||
@ -21,7 +21,7 @@ pub struct GroupRowsNotificationPB {
|
||||
pub deleted_rows: Vec<String>,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub updated_rows: Vec<RowPB>,
|
||||
pub updated_rows: Vec<RowMetaPB>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GroupRowsNotificationPB {
|
||||
@ -29,7 +29,7 @@ impl std::fmt::Display for GroupRowsNotificationPB {
|
||||
for inserted_row in &self.inserted_rows {
|
||||
f.write_fmt(format_args!(
|
||||
"Insert: {} row at {:?}",
|
||||
inserted_row.row.id, inserted_row.index
|
||||
inserted_row.row_meta.id, inserted_row.index
|
||||
))?;
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ impl GroupRowsNotificationPB {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(group_id: String, updated_rows: Vec<RowPB>) -> Self {
|
||||
pub fn update(group_id: String, updated_rows: Vec<RowMetaPB>) -> Self {
|
||||
Self {
|
||||
group_id,
|
||||
updated_rows,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use collab_database::rows::{Row, RowId};
|
||||
use collab_database::rows::{Row, RowId, RowMeta};
|
||||
use collab_database::views::RowOrder;
|
||||
|
||||
use flowy_derive::ProtoBuf;
|
||||
@ -36,6 +36,7 @@ impl std::convert::From<Row> for RowPB {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RowOrder> for RowPB {
|
||||
fn from(data: RowOrder) -> Self {
|
||||
Self {
|
||||
@ -45,6 +46,153 @@ impl From<RowOrder> for RowPB {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct RowMetaPB {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub document_id: String,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub icon: Option<String>,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub cover: Option<String>,
|
||||
}
|
||||
|
||||
impl std::convert::From<&RowMeta> for RowMetaPB {
|
||||
fn from(row_meta: &RowMeta) -> Self {
|
||||
Self {
|
||||
id: row_meta.row_id.clone(),
|
||||
document_id: row_meta.document_id.clone(),
|
||||
icon: row_meta.icon_url.clone(),
|
||||
cover: row_meta.cover_url.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<RowMeta> for RowMetaPB {
|
||||
fn from(row_meta: RowMeta) -> Self {
|
||||
Self {
|
||||
id: row_meta.row_id,
|
||||
document_id: row_meta.document_id,
|
||||
icon: row_meta.icon_url,
|
||||
cover: row_meta.cover_url,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct UpdateRowMetaChangesetPB {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub view_id: String,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub icon_url: Option<String>,
|
||||
|
||||
#[pb(index = 4, one_of)]
|
||||
pub cover_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UpdateRowMetaParams {
|
||||
pub id: String,
|
||||
pub view_id: String,
|
||||
pub icon_url: Option<String>,
|
||||
pub cover_url: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<UpdateRowMetaParams> for UpdateRowMetaChangesetPB {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<UpdateRowMetaParams, Self::Error> {
|
||||
let row_id = NotEmptyStr::parse(self.id)
|
||||
.map_err(|_| ErrorCode::RowIdIsEmpty)?
|
||||
.0;
|
||||
|
||||
let view_id = NotEmptyStr::parse(self.view_id)
|
||||
.map_err(|_| ErrorCode::ViewIdIsInvalid)?
|
||||
.0;
|
||||
Ok(UpdateRowMetaParams {
|
||||
id: row_id,
|
||||
view_id,
|
||||
icon_url: self.icon_url,
|
||||
cover_url: self.cover_url,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct UpdateRowPayloadPB {
|
||||
#[pb(index = 1)]
|
||||
pub row_id: String,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub insert_document: Option<bool>,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub insert_comment: Option<RowCommentPayloadPB>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct UpdateRowParams {
|
||||
pub row_id: String,
|
||||
pub insert_comment: Option<RowCommentParams>,
|
||||
}
|
||||
|
||||
impl TryInto<UpdateRowParams> for UpdateRowPayloadPB {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<UpdateRowParams, Self::Error> {
|
||||
let row_id = NotEmptyStr::parse(self.row_id)
|
||||
.map_err(|_| ErrorCode::RowIdIsEmpty)?
|
||||
.0;
|
||||
let insert_comment = self
|
||||
.insert_comment
|
||||
.map(|comment| comment.try_into())
|
||||
.transpose()?;
|
||||
|
||||
Ok(UpdateRowParams {
|
||||
row_id,
|
||||
insert_comment,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct RowCommentPayloadPB {
|
||||
#[pb(index = 1)]
|
||||
pub uid: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub comment: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct RowCommentParams {
|
||||
pub uid: String,
|
||||
pub comment: String,
|
||||
}
|
||||
|
||||
impl TryInto<RowCommentParams> for RowCommentPayloadPB {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<RowCommentParams, Self::Error> {
|
||||
let uid = NotEmptyStr::parse(self.uid)
|
||||
.map_err(|_| ErrorCode::RowIdIsEmpty)?
|
||||
.0;
|
||||
let comment = NotEmptyStr::parse(self.comment)
|
||||
.map_err(|_| ErrorCode::RowIdIsEmpty)?
|
||||
.0;
|
||||
|
||||
Ok(RowCommentParams { uid, comment })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct OptionalRowPB {
|
||||
#[pb(index = 1, one_of)]
|
||||
@ -66,7 +214,7 @@ impl std::convert::From<Vec<RowPB>> for RepeatedRowPB {
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct InsertedRowPB {
|
||||
#[pb(index = 1)]
|
||||
pub row: RowPB,
|
||||
pub row_meta: RowMetaPB,
|
||||
|
||||
#[pb(index = 2, one_of)]
|
||||
pub index: Option<i32>,
|
||||
@ -76,9 +224,9 @@ pub struct InsertedRowPB {
|
||||
}
|
||||
|
||||
impl InsertedRowPB {
|
||||
pub fn new(row: RowPB) -> Self {
|
||||
pub fn new(row_meta: RowMetaPB) -> Self {
|
||||
Self {
|
||||
row,
|
||||
row_meta,
|
||||
index: None,
|
||||
is_new: false,
|
||||
}
|
||||
@ -90,26 +238,20 @@ impl InsertedRowPB {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<RowPB> for InsertedRowPB {
|
||||
fn from(row: RowPB) -> Self {
|
||||
impl std::convert::From<RowMetaPB> for InsertedRowPB {
|
||||
fn from(row_meta: RowMetaPB) -> Self {
|
||||
Self {
|
||||
row,
|
||||
row_meta,
|
||||
index: None,
|
||||
is_new: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&Row> for InsertedRowPB {
|
||||
fn from(row: &Row) -> Self {
|
||||
Self::from(RowPB::from(row))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InsertedRow> for InsertedRowPB {
|
||||
fn from(data: InsertedRow) -> Self {
|
||||
Self {
|
||||
row: data.row.into(),
|
||||
row_meta: data.row_meta.into(),
|
||||
index: data.index,
|
||||
is_new: data.is_new,
|
||||
}
|
||||
@ -119,18 +261,24 @@ impl From<InsertedRow> for InsertedRowPB {
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct UpdatedRowPB {
|
||||
#[pb(index = 1)]
|
||||
pub row: RowPB,
|
||||
pub row_id: String,
|
||||
|
||||
// Indicates the field ids of the cells that were updated in this row.
|
||||
#[pb(index = 2)]
|
||||
pub field_ids: Vec<String>,
|
||||
|
||||
/// The meta of row was updated if this is Some.
|
||||
#[pb(index = 3, one_of)]
|
||||
pub row_meta: Option<RowMetaPB>,
|
||||
}
|
||||
|
||||
impl From<UpdatedRow> for UpdatedRowPB {
|
||||
fn from(data: UpdatedRow) -> Self {
|
||||
let row_meta = data.row_meta.map(RowMetaPB::from);
|
||||
Self {
|
||||
row: data.row.into(),
|
||||
row_id: data.row_id,
|
||||
field_ids: data.field_ids,
|
||||
row_meta,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,6 +133,34 @@ pub(crate) async fn get_fields_handler(
|
||||
data_result_ok(fields)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn get_primary_field_handler(
|
||||
data: AFPluginData<DatabaseViewIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
) -> DataResult<FieldPB, FlowyError> {
|
||||
let view_id = data.into_inner().value;
|
||||
let database_editor = manager.get_database_with_view_id(&view_id).await?;
|
||||
let mut fields = database_editor
|
||||
.get_fields(&view_id, None)
|
||||
.into_iter()
|
||||
.filter(|field| field.is_primary)
|
||||
.map(FieldPB::from)
|
||||
.collect::<Vec<FieldPB>>();
|
||||
|
||||
if fields.is_empty() {
|
||||
// The primary field should not be empty. Because it is created when the database is created.
|
||||
// If it is empty, it must be a bug.
|
||||
Err(FlowyError::record_not_found())
|
||||
} else {
|
||||
if fields.len() > 1 {
|
||||
// The primary field should not be more than one. If it is more than one,
|
||||
// it must be a bug.
|
||||
tracing::error!("The primary field is more than one");
|
||||
}
|
||||
data_result_ok(fields.remove(0))
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
pub(crate) async fn update_field_handler(
|
||||
data: AFPluginData<FieldChangesetPB>,
|
||||
@ -300,6 +328,29 @@ pub(crate) async fn get_row_handler(
|
||||
data_result_ok(OptionalRowPB { row })
|
||||
}
|
||||
|
||||
pub(crate) async fn get_row_meta_handler(
|
||||
data: AFPluginData<RowIdPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
) -> DataResult<RowMetaPB, FlowyError> {
|
||||
let params: RowIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
match database_editor.get_row_meta(¶ms.view_id, ¶ms.row_id) {
|
||||
None => Err(FlowyError::record_not_found()),
|
||||
Some(row) => data_result_ok(row),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn update_row_meta_handler(
|
||||
data: AFPluginData<UpdateRowMetaChangesetPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
) -> FlowyResult<()> {
|
||||
let params: UpdateRowMetaParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let row_id = RowId::from(params.id.clone());
|
||||
database_editor.update_row_meta(&row_id, params).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn delete_row_handler(
|
||||
data: AFPluginData<RowIdPB>,
|
||||
@ -341,7 +392,7 @@ pub(crate) async fn move_row_handler(
|
||||
pub(crate) async fn create_row_handler(
|
||||
data: AFPluginData<CreateRowPayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager2>>,
|
||||
) -> DataResult<RowPB, FlowyError> {
|
||||
) -> DataResult<RowMetaPB, FlowyError> {
|
||||
let params: CreateRowParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let fields = database_editor.get_fields(¶ms.view_id, None);
|
||||
@ -362,7 +413,7 @@ pub(crate) async fn create_row_handler(
|
||||
.await?
|
||||
{
|
||||
None => Err(FlowyError::internal().context("Create row fail")),
|
||||
Some(row) => data_result_ok(RowPB::from(row)),
|
||||
Some(row) => data_result_ok(RowMetaPB::from(row.meta)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ pub fn init(database_manager: Arc<DatabaseManager2>) -> AFPlugin {
|
||||
.event(DatabaseEvent::DeleteAllSorts, delete_all_sorts_handler)
|
||||
// Field
|
||||
.event(DatabaseEvent::GetFields, get_fields_handler)
|
||||
.event(DatabaseEvent::GetPrimaryField, get_primary_field_handler)
|
||||
.event(DatabaseEvent::UpdateField, update_field_handler)
|
||||
.event(DatabaseEvent::UpdateFieldTypeOption, update_field_type_option_handler)
|
||||
.event(DatabaseEvent::DeleteField, delete_field_handler)
|
||||
@ -33,6 +34,8 @@ pub fn init(database_manager: Arc<DatabaseManager2>) -> AFPlugin {
|
||||
// Row
|
||||
.event(DatabaseEvent::CreateRow, create_row_handler)
|
||||
.event(DatabaseEvent::GetRow, get_row_handler)
|
||||
.event(DatabaseEvent::GetRowMeta, get_row_meta_handler)
|
||||
.event(DatabaseEvent::UpdateRowMeta, update_row_meta_handler)
|
||||
.event(DatabaseEvent::DeleteRow, delete_row_handler)
|
||||
.event(DatabaseEvent::DuplicateRow, duplicate_row_handler)
|
||||
.event(DatabaseEvent::MoveRow, move_row_handler)
|
||||
@ -172,6 +175,9 @@ pub enum DatabaseEvent {
|
||||
#[event(input = "CreateFieldPayloadPB", output = "TypeOptionPB")]
|
||||
CreateTypeOption = 24,
|
||||
|
||||
#[event(input = "DatabaseViewIdPB", output = "FieldPB")]
|
||||
GetPrimaryField = 25,
|
||||
|
||||
/// [CreateSelectOption] event is used to create a new select option. Returns a [SelectOptionPB] if
|
||||
/// there are no errors.
|
||||
#[event(input = "CreateSelectOptionPayloadPB", output = "SelectOptionPB")]
|
||||
@ -195,7 +201,7 @@ pub enum DatabaseEvent {
|
||||
#[event(input = "RepeatedSelectOptionPayload")]
|
||||
DeleteSelectOption = 33,
|
||||
|
||||
#[event(input = "CreateRowPayloadPB", output = "RowPB")]
|
||||
#[event(input = "CreateRowPayloadPB", output = "RowMetaPB")]
|
||||
CreateRow = 50,
|
||||
|
||||
/// [GetRow] event is used to get the row data,[RowPB]. [OptionalRowPB] is a wrapper that enables
|
||||
@ -212,6 +218,12 @@ pub enum DatabaseEvent {
|
||||
#[event(input = "MoveRowPayloadPB")]
|
||||
MoveRow = 54,
|
||||
|
||||
#[event(input = "RowIdPB", output = "RowMetaPB")]
|
||||
GetRowMeta = 55,
|
||||
|
||||
#[event(input = "UpdateRowMetaChangesetPB")]
|
||||
UpdateRowMeta = 56,
|
||||
|
||||
#[event(input = "CellIdPB", output = "CellPB")]
|
||||
GetCell = 70,
|
||||
|
||||
|
@ -31,6 +31,8 @@ pub enum DatabaseNotification {
|
||||
DidReorderRows = 65,
|
||||
/// Trigger after editing the row that hit the sort rule
|
||||
DidReorderSingleRow = 66,
|
||||
/// Trigger after updating the row meta
|
||||
DidUpdateRowMeta = 67,
|
||||
/// Trigger when the settings of the database are changed
|
||||
DidUpdateSettings = 70,
|
||||
// Trigger when the layout setting of the database is updated
|
||||
|
@ -14,19 +14,13 @@ use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_task::TaskDispatcher;
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
|
||||
use crate::entities::{
|
||||
CalendarEventPB, CellChangesetNotifyPB, CellPB, ChecklistCellDataPB, DatabaseFieldChangesetPB,
|
||||
DatabasePB, DatabaseViewSettingPB, DeleteFilterParams, DeleteGroupParams, DeleteSortParams,
|
||||
FieldChangesetParams, FieldIdPB, FieldPB, FieldType, GroupPB, IndexFieldPB, InsertedRowPB,
|
||||
LayoutSettingParams, NoDateCalendarEventPB, RepeatedFilterPB, RepeatedGroupPB, RepeatedSortPB,
|
||||
RowPB, RowsChangePB, SelectOptionCellDataPB, SelectOptionPB, UpdateFilterParams,
|
||||
UpdateSortParams, UpdatedRowPB,
|
||||
};
|
||||
use crate::entities::*;
|
||||
use crate::notification::{send_notification, DatabaseNotification};
|
||||
use crate::services::cell::{
|
||||
apply_cell_changeset, get_cell_protobuf, AnyTypeCache, CellCache, ToCellChangeset,
|
||||
};
|
||||
use crate::services::database::util::database_view_setting_pb_from_view;
|
||||
use crate::services::database::{RowDetail, UpdatedRow};
|
||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewData, DatabaseViews};
|
||||
use crate::services::field::checklist_type_option::{ChecklistCellChangeset, ChecklistCellData};
|
||||
use crate::services::field::{
|
||||
@ -376,8 +370,8 @@ impl DatabaseEditor {
|
||||
|
||||
pub async fn move_row(&self, view_id: &str, from: RowId, to: RowId) {
|
||||
let database = self.database.lock();
|
||||
if let (Some(row), Some(from_index), Some(to_index)) = (
|
||||
database.get_row(&from),
|
||||
if let (Some(row_meta), Some(from_index), Some(to_index)) = (
|
||||
database.get_row_meta(&from),
|
||||
database.index_of_row(view_id, &from),
|
||||
database.index_of_row(view_id, &to),
|
||||
) {
|
||||
@ -387,7 +381,7 @@ impl DatabaseEditor {
|
||||
drop(database);
|
||||
|
||||
let delete_row_id = from.into_inner();
|
||||
let insert_row = InsertedRowPB::from(&row).with_index(to_index as i32);
|
||||
let insert_row = InsertedRowPB::new(RowMetaPB::from(&row_meta)).with_index(to_index as i32);
|
||||
let changes =
|
||||
RowsChangePB::from_move(view_id.to_string(), vec![delete_row_id], vec![insert_row]);
|
||||
send_notification(view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
@ -401,7 +395,7 @@ impl DatabaseEditor {
|
||||
view_id: &str,
|
||||
group_id: Option<String>,
|
||||
mut params: CreateRowParams,
|
||||
) -> FlowyResult<Option<Row>> {
|
||||
) -> FlowyResult<Option<RowDetail>> {
|
||||
for view in self.database_views.editors().await {
|
||||
view.v_will_create_row(&mut params.cells, &group_id).await;
|
||||
}
|
||||
@ -409,11 +403,13 @@ impl DatabaseEditor {
|
||||
if let Some((index, row_order)) = result {
|
||||
tracing::trace!("create row: {:?} at {}", row_order, index);
|
||||
let row = self.database.lock().get_row(&row_order.id);
|
||||
if let Some(row) = row {
|
||||
let row_meta = self.database.lock().get_row_meta(&row_order.id);
|
||||
if let (Some(row), Some(meta)) = (row, row_meta) {
|
||||
let row_detail = RowDetail { row, meta };
|
||||
for view in self.database_views.editors().await {
|
||||
view.v_did_create_row(&row, &group_id, index).await;
|
||||
view.v_did_create_row(&row_detail, &group_id, index).await;
|
||||
}
|
||||
return Ok(Some(row));
|
||||
return Ok(Some(row_detail));
|
||||
}
|
||||
}
|
||||
|
||||
@ -491,16 +487,42 @@ impl DatabaseEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_rows(&self, view_id: &str) -> FlowyResult<Vec<Arc<Row>>> {
|
||||
pub async fn get_rows(&self, view_id: &str) -> FlowyResult<Vec<Arc<RowDetail>>> {
|
||||
let view_editor = self.database_views.get_view_editor(view_id).await?;
|
||||
Ok(view_editor.v_get_rows().await)
|
||||
}
|
||||
|
||||
pub fn get_row(&self, view_id: &str, row_id: &RowId) -> Option<Row> {
|
||||
if self.database.lock().views.is_row_exist(view_id, row_id) {
|
||||
return None;
|
||||
} else {
|
||||
self.database.lock().get_row(row_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_row_meta(&self, view_id: &str, row_id: &RowId) -> Option<RowMetaPB> {
|
||||
if self.database.lock().views.is_row_exist(view_id, row_id) {
|
||||
let row_meta = self.database.lock().get_row_meta(row_id)?;
|
||||
Some(RowMetaPB {
|
||||
id: row_id.clone().into_inner(),
|
||||
document_id: row_meta.document_id,
|
||||
icon: row_meta.icon_url,
|
||||
cover: row_meta.cover_url,
|
||||
})
|
||||
} else {
|
||||
tracing::warn!("the row:{} is exist in view:{}", row_id.as_str(), view_id);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_row_detail(&self, view_id: &str, row_id: &RowId) -> Option<RowDetail> {
|
||||
if self.database.lock().views.is_row_exist(view_id, row_id) {
|
||||
let meta = self.database.lock().get_row_meta(row_id)?;
|
||||
let row = self.database.lock().get_row(row_id)?;
|
||||
Some(RowDetail { row, meta })
|
||||
} else {
|
||||
tracing::warn!("the row:{} is exist in view:{}", row_id.as_str(), view_id);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,6 +536,28 @@ impl DatabaseEditor {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
pub async fn update_row_meta(&self, row_id: &RowId, changeset: UpdateRowMetaParams) {
|
||||
self.database.lock().update_row_meta(row_id, |meta_update| {
|
||||
meta_update
|
||||
.insert_cover_if_not_none(changeset.cover_url)
|
||||
.insert_icon_if_not_none(changeset.icon_url);
|
||||
});
|
||||
|
||||
// Use the temporary row meta to get rid of the lock that not implement the `Send` or 'Sync' trait.
|
||||
let row_meta = self.database.lock().get_row_meta(row_id);
|
||||
if let Some(row_meta) = row_meta {
|
||||
for view in self.database_views.editors().await {
|
||||
view.v_did_update_row_meta(row_id, &row_meta).await;
|
||||
}
|
||||
|
||||
// Notifies the client that the row meta has been updated.
|
||||
send_notification(row_id.as_str(), DatabaseNotification::DidUpdateRowMeta)
|
||||
.payload(RowMetaPB::from(&row_meta))
|
||||
.send();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_cell(&self, field_id: &str, row_id: &RowId) -> Option<Cell> {
|
||||
let database = self.database.lock();
|
||||
let field = database.fields.get_field(field_id)?;
|
||||
@ -630,7 +674,7 @@ impl DatabaseEditor {
|
||||
new_cell: Cell,
|
||||
) -> FlowyResult<()> {
|
||||
// Get the old row before updating the cell. It would be better to get the old cell
|
||||
let old_row = { self.database.lock().get_row(&row_id) };
|
||||
let old_row = { self.get_row_detail(view_id, &row_id) };
|
||||
|
||||
// Get all auto updated fields. It will be used to notify the frontend
|
||||
// that the fields have been updated.
|
||||
@ -642,19 +686,19 @@ impl DatabaseEditor {
|
||||
});
|
||||
});
|
||||
|
||||
let option_row = self.database.lock().get_row(&row_id);
|
||||
if let Some(new_row) = option_row {
|
||||
let updated_row = UpdatedRowPB {
|
||||
row: RowPB::from(&new_row),
|
||||
field_ids: vec![field_id.to_string()],
|
||||
};
|
||||
let changes = RowsChangePB::from_update(view_id.to_string(), updated_row);
|
||||
let option_row = self.get_row_detail(view_id, &row_id);
|
||||
if let Some(new_row_detail) = option_row {
|
||||
let updated_row =
|
||||
UpdatedRow::new(&new_row_detail.row.id).with_field_ids(vec![field_id.to_string()]);
|
||||
let changes = RowsChangePB::from_update(view_id.to_string(), updated_row.into());
|
||||
send_notification(view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changes)
|
||||
.send();
|
||||
|
||||
for view in self.database_views.editors().await {
|
||||
view.v_did_update_row(&old_row, &new_row, field_id).await;
|
||||
view
|
||||
.v_did_update_row(&old_row, &new_row_detail, field_id)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,23 +898,23 @@ impl DatabaseEditor {
|
||||
from_row: RowId,
|
||||
to_row: Option<RowId>,
|
||||
) -> FlowyResult<()> {
|
||||
let row = self.database.lock().get_row(&from_row);
|
||||
match row {
|
||||
let row_detail = self.get_row_detail(view_id, &from_row);
|
||||
match row_detail {
|
||||
None => {
|
||||
tracing::warn!(
|
||||
"Move row between group failed, can not find the row:{}",
|
||||
from_row
|
||||
)
|
||||
},
|
||||
Some(row) => {
|
||||
let mut row_changeset = RowChangeset::new(row.id.clone());
|
||||
Some(row_detail) => {
|
||||
let mut row_changeset = RowChangeset::new(row_detail.row.id.clone());
|
||||
let view = self.database_views.get_view_editor(view_id).await?;
|
||||
view
|
||||
.v_move_group_row(&row, &mut row_changeset, to_group, to_row)
|
||||
.v_move_group_row(&row_detail, &mut row_changeset, to_group, to_row)
|
||||
.await;
|
||||
|
||||
tracing::trace!("Row data changed: {:?}", row_changeset);
|
||||
self.database.lock().update_row(&row.id, |row| {
|
||||
self.database.lock().update_row(&row_detail.row.id, |row| {
|
||||
row.set_cells(Cells::from(row_changeset.cell_by_field_id.clone()));
|
||||
});
|
||||
|
||||
@ -1012,8 +1056,8 @@ impl DatabaseEditor {
|
||||
|
||||
let rows = rows
|
||||
.into_iter()
|
||||
.map(|row| RowPB::from(row.as_ref()))
|
||||
.collect::<Vec<RowPB>>();
|
||||
.map(|row_detail| RowMetaPB::from(&row_detail.meta))
|
||||
.collect::<Vec<RowMetaPB>>();
|
||||
Ok(DatabasePB {
|
||||
id: database_id,
|
||||
fields,
|
||||
@ -1150,20 +1194,37 @@ impl DatabaseViewData for DatabaseViewDataImpl {
|
||||
to_fut(async move { index })
|
||||
}
|
||||
|
||||
fn get_row(&self, view_id: &str, row_id: &RowId) -> Fut<Option<(usize, Arc<Row>)>> {
|
||||
fn get_row(&self, view_id: &str, row_id: &RowId) -> Fut<Option<(usize, Arc<RowDetail>)>> {
|
||||
let index = self.database.lock().index_of_row(view_id, row_id);
|
||||
let row = self.database.lock().get_row(row_id);
|
||||
let row_meta = self.database.lock().get_row_meta(row_id);
|
||||
to_fut(async move {
|
||||
match (index, row) {
|
||||
(Some(index), Some(row)) => Some((index, Arc::new(row))),
|
||||
match (index, row, row_meta) {
|
||||
(Some(index), Some(row), Some(row_meta)) => {
|
||||
let row_detail = RowDetail {
|
||||
row,
|
||||
meta: row_meta,
|
||||
};
|
||||
Some((index, Arc::new(row_detail)))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<Row>>> {
|
||||
let rows = self.database.lock().get_rows_for_view(view_id);
|
||||
to_fut(async move { rows.into_iter().map(Arc::new).collect() })
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<RowDetail>>> {
|
||||
let database = self.database.lock();
|
||||
let rows = database.get_rows_for_view(view_id);
|
||||
let row_details = rows
|
||||
.into_iter()
|
||||
.flat_map(|row| {
|
||||
database
|
||||
.get_row_meta(&row.id)
|
||||
.map(|meta| RowDetail { row, meta })
|
||||
})
|
||||
.collect::<Vec<RowDetail>>();
|
||||
|
||||
to_fut(async move { row_details.into_iter().map(Arc::new).collect() })
|
||||
}
|
||||
|
||||
fn get_cells_for_field(&self, view_id: &str, field_id: &str) -> Fut<Vec<Arc<RowCell>>> {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use collab_database::rows::RowId;
|
||||
use collab_database::views::{DatabaseLayout, RowOrder};
|
||||
use collab_database::rows::{Row, RowId, RowMeta};
|
||||
use collab_database::views::DatabaseLayout;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DatabaseRowEvent {
|
||||
@ -14,16 +14,48 @@ pub enum DatabaseRowEvent {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InsertedRow {
|
||||
pub row: RowOrder,
|
||||
pub row_meta: RowMeta,
|
||||
pub index: Option<i32>,
|
||||
pub is_new: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UpdatedRow {
|
||||
pub row: RowOrder,
|
||||
// represents as the cells that were updated in this row.
|
||||
pub row_id: String,
|
||||
|
||||
pub height: Option<i32>,
|
||||
|
||||
/// Indicates which cells were updated.
|
||||
pub field_ids: Vec<String>,
|
||||
|
||||
/// The meta of row was updated if this is Some.
|
||||
pub row_meta: Option<RowMeta>,
|
||||
}
|
||||
|
||||
impl UpdatedRow {
|
||||
pub fn new(row_id: &str) -> Self {
|
||||
Self {
|
||||
row_id: row_id.to_string(),
|
||||
height: None,
|
||||
field_ids: vec![],
|
||||
row_meta: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_field_ids(mut self, field_ids: Vec<String>) -> Self {
|
||||
self.field_ids = field_ids;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_height(mut self, height: i32) -> Self {
|
||||
self.height = Some(height);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_row_meta(mut self, row_meta: RowMeta) -> Self {
|
||||
self.row_meta = Some(row_meta);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -32,3 +64,9 @@ pub struct CreateDatabaseViewParams {
|
||||
pub view_id: String,
|
||||
pub layout_type: DatabaseLayout,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RowDetail {
|
||||
pub row: Row,
|
||||
pub meta: RowMeta,
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ use std::sync::Arc;
|
||||
|
||||
use collab_database::database::{gen_database_filter_id, gen_database_sort_id};
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{Cells, Row, RowCell, RowId};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting, RowOrder};
|
||||
use collab_database::rows::{Cells, Row, RowCell, RowId, RowMeta};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting};
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
@ -15,12 +15,14 @@ use lib_infra::future::Fut;
|
||||
use crate::entities::{
|
||||
CalendarEventPB, DatabaseLayoutMetaPB, DatabaseLayoutSettingPB, DeleteFilterParams,
|
||||
DeleteGroupParams, DeleteSortParams, FieldType, GroupChangesPB, GroupPB, GroupRowsNotificationPB,
|
||||
InsertedRowPB, LayoutSettingParams, RowPB, RowsChangePB, SortChangesetNotificationPB, SortPB,
|
||||
InsertedRowPB, LayoutSettingParams, RowMetaPB, RowsChangePB, SortChangesetNotificationPB, SortPB,
|
||||
UpdateFilterParams, UpdateSortParams,
|
||||
};
|
||||
use crate::notification::{send_notification, DatabaseNotification};
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::{database_view_setting_pb_from_view, DatabaseRowEvent, UpdatedRow};
|
||||
use crate::services::database::{
|
||||
database_view_setting_pb_from_view, DatabaseRowEvent, RowDetail, UpdatedRow,
|
||||
};
|
||||
use crate::services::database_view::view_filter::make_filter_controller;
|
||||
use crate::services::database_view::view_group::{
|
||||
get_cell_for_row, get_cells_for_field, new_group_controller, new_group_controller_with_field,
|
||||
@ -63,10 +65,10 @@ pub trait DatabaseViewData: Send + Sync + 'static {
|
||||
fn index_of_row(&self, view_id: &str, row_id: &RowId) -> Fut<Option<usize>>;
|
||||
|
||||
/// Returns the `index` and `RowRevision` with row_id
|
||||
fn get_row(&self, view_id: &str, row_id: &RowId) -> Fut<Option<(usize, Arc<Row>)>>;
|
||||
fn get_row(&self, view_id: &str, row_id: &RowId) -> Fut<Option<(usize, Arc<RowDetail>)>>;
|
||||
|
||||
/// Returns all the rows in the view
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<Row>>>;
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<RowDetail>>>;
|
||||
|
||||
fn get_cells_for_field(&self, view_id: &str, field_id: &str) -> Fut<Vec<Arc<RowCell>>>;
|
||||
|
||||
@ -198,11 +200,24 @@ impl DatabaseViewEditor {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn v_did_create_row(&self, row: &Row, group_id: &Option<String>, index: usize) {
|
||||
pub async fn v_did_update_row_meta(&self, row_id: &RowId, row_meta: &RowMeta) {
|
||||
let update_row = UpdatedRow::new(row_id.as_str()).with_row_meta(row_meta.clone());
|
||||
let changeset = RowsChangePB::from_update(self.view_id.clone(), update_row.into());
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changeset)
|
||||
.send();
|
||||
}
|
||||
|
||||
pub async fn v_did_create_row(
|
||||
&self,
|
||||
row_detail: &RowDetail,
|
||||
group_id: &Option<String>,
|
||||
index: usize,
|
||||
) {
|
||||
// Send the group notification if the current view has groups
|
||||
match group_id.as_ref() {
|
||||
None => {
|
||||
let row = InsertedRowPB::from(row).with_index(index as i32);
|
||||
let row = InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)).with_index(index as i32);
|
||||
let changes = RowsChangePB::from_insert(self.view_id.clone(), row);
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changes)
|
||||
@ -211,13 +226,13 @@ impl DatabaseViewEditor {
|
||||
Some(group_id) => {
|
||||
self
|
||||
.mut_group_controller(|group_controller, _| {
|
||||
group_controller.did_create_row(row, group_id);
|
||||
group_controller.did_create_row(row_detail, group_id);
|
||||
Ok(())
|
||||
})
|
||||
.await;
|
||||
|
||||
let inserted_row = InsertedRowPB {
|
||||
row: RowPB::from(row),
|
||||
row_meta: RowMetaPB::from(&row_detail.meta),
|
||||
index: Some(index as i32),
|
||||
is_new: true,
|
||||
};
|
||||
@ -251,10 +266,15 @@ impl DatabaseViewEditor {
|
||||
/// Notify the view that the row has been updated. If the view has groups,
|
||||
/// send the group notification with [GroupRowsNotificationPB]. Otherwise,
|
||||
/// send the view notification with [RowsChangePB]
|
||||
pub async fn v_did_update_row(&self, old_row: &Option<Row>, row: &Row, field_id: &str) {
|
||||
pub async fn v_did_update_row(
|
||||
&self,
|
||||
old_row: &Option<RowDetail>,
|
||||
row_detail: &RowDetail,
|
||||
field_id: &str,
|
||||
) {
|
||||
let result = self
|
||||
.mut_group_controller(|group_controller, field| {
|
||||
Ok(group_controller.did_update_group_row(old_row, row, &field))
|
||||
Ok(group_controller.did_update_group_row(old_row, row_detail, &field))
|
||||
})
|
||||
.await;
|
||||
|
||||
@ -283,10 +303,8 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let update_row = UpdatedRow {
|
||||
row: RowOrder::from(row),
|
||||
field_ids: vec![field_id.to_string()],
|
||||
};
|
||||
let update_row =
|
||||
UpdatedRow::new(&row_detail.row.id).with_field_ids(vec![field_id.to_string()]);
|
||||
let changeset = RowsChangePB::from_update(self.view_id.clone(), update_row.into());
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changeset)
|
||||
@ -295,7 +313,7 @@ impl DatabaseViewEditor {
|
||||
|
||||
// Each row update will trigger a filter and sort operation. We don't want
|
||||
// to block the main thread, so we spawn a new task to do the work.
|
||||
let row_id = row.id.clone();
|
||||
let row_id = row_detail.row.id.clone();
|
||||
let weak_filter_controller = Arc::downgrade(&self.filter_controller);
|
||||
let weak_sort_controller = Arc::downgrade(&self.sort_controller);
|
||||
tokio::spawn(async move {
|
||||
@ -314,15 +332,20 @@ impl DatabaseViewEditor {
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn v_filter_rows(&self, rows: &mut Vec<Arc<Row>>) {
|
||||
self.filter_controller.filter_rows(rows).await
|
||||
pub async fn v_filter_rows(&self, row_details: &mut Vec<Arc<RowDetail>>) {
|
||||
self.filter_controller.filter_rows(row_details).await
|
||||
}
|
||||
|
||||
pub async fn v_sort_rows(&self, rows: &mut Vec<Arc<Row>>) {
|
||||
self.sort_controller.write().await.sort_rows(rows).await
|
||||
pub async fn v_sort_rows(&self, row_details: &mut Vec<Arc<RowDetail>>) {
|
||||
self
|
||||
.sort_controller
|
||||
.write()
|
||||
.await
|
||||
.sort_rows(row_details)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn v_get_rows(&self) -> Vec<Arc<Row>> {
|
||||
pub async fn v_get_rows(&self) -> Vec<Arc<RowDetail>> {
|
||||
let mut rows = self.delegate.get_rows(&self.view_id).await;
|
||||
self.v_filter_rows(&mut rows).await;
|
||||
self.v_sort_rows(&mut rows).await;
|
||||
@ -331,7 +354,7 @@ impl DatabaseViewEditor {
|
||||
|
||||
pub async fn v_move_group_row(
|
||||
&self,
|
||||
row: &Row,
|
||||
row_detail: &RowDetail,
|
||||
row_changeset: &mut RowChangeset,
|
||||
to_group_id: &str,
|
||||
to_row_id: Option<RowId>,
|
||||
@ -339,7 +362,7 @@ impl DatabaseViewEditor {
|
||||
let result = self
|
||||
.mut_group_controller(|group_controller, field| {
|
||||
let move_row_context = MoveGroupRowContext {
|
||||
row,
|
||||
row_detail,
|
||||
row_changeset,
|
||||
field: field.as_ref(),
|
||||
to_group_id,
|
||||
@ -741,8 +764,9 @@ impl DatabaseViewEditor {
|
||||
.timestamp
|
||||
.unwrap_or_default();
|
||||
|
||||
let (_, row_detail) = self.delegate.get_row(&self.view_id, &row_id).await?;
|
||||
Some(CalendarEventPB {
|
||||
row_id: row_id.into_inner(),
|
||||
row_meta: RowMetaPB::from(&row_detail.meta),
|
||||
date_field_id: date_field.id.clone(),
|
||||
title,
|
||||
timestamp,
|
||||
@ -792,8 +816,9 @@ impl DatabaseViewEditor {
|
||||
.unwrap_or_default()
|
||||
.into();
|
||||
|
||||
let (_, row_detail) = self.delegate.get_row(&self.view_id, &row_id).await?;
|
||||
let event = CalendarEventPB {
|
||||
row_id: row_id.into_inner(),
|
||||
row_meta: RowMetaPB::from(&row_detail.meta),
|
||||
date_field_id: calendar_setting.field_id.clone(),
|
||||
title,
|
||||
timestamp,
|
||||
|
@ -1,12 +1,16 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::RowId;
|
||||
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::database_view::{
|
||||
gen_handler_id, DatabaseViewChangedNotifier, DatabaseViewData,
|
||||
};
|
||||
use crate::services::filter::{Filter, FilterController, FilterDelegate, FilterTaskHandler};
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Row, RowId};
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub async fn make_filter_controller(
|
||||
view_id: &str,
|
||||
@ -56,11 +60,11 @@ impl FilterDelegate for DatabaseViewFilterDelegateImpl {
|
||||
self.0.get_fields(view_id, field_ids)
|
||||
}
|
||||
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<Row>>> {
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<RowDetail>>> {
|
||||
self.0.get_rows(view_id)
|
||||
}
|
||||
|
||||
fn get_row(&self, view_id: &str, rows_id: &RowId) -> Fut<Option<(usize, Arc<Row>)>> {
|
||||
fn get_row(&self, view_id: &str, rows_id: &RowId) -> Fut<Option<(usize, Arc<RowDetail>)>> {
|
||||
self.0.get_row(view_id, rows_id)
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,17 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::database_view::{
|
||||
gen_handler_id, DatabaseViewChangedNotifier, DatabaseViewData,
|
||||
};
|
||||
use crate::services::filter::FilterController;
|
||||
use crate::services::sort::{Sort, SortController, SortDelegate, SortTaskHandler};
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::Row;
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub(crate) async fn make_sort_controller(
|
||||
view_id: &str,
|
||||
@ -56,14 +59,14 @@ impl SortDelegate for DatabaseViewSortDelegateImpl {
|
||||
to_fut(async move { sort })
|
||||
}
|
||||
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<Row>>> {
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<RowDetail>>> {
|
||||
let view_id = view_id.to_string();
|
||||
let delegate = self.delegate.clone();
|
||||
let filter_controller = self.filter_controller.clone();
|
||||
to_fut(async move {
|
||||
let mut rows = delegate.get_rows(&view_id).await;
|
||||
filter_controller.filter_rows(&mut rows).await;
|
||||
rows
|
||||
let mut row_details = delegate.get_rows(&view_id).await;
|
||||
filter_controller.filter_rows(&mut row_details).await;
|
||||
row_details
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Row, RowId};
|
||||
use collab_database::rows::RowId;
|
||||
use nanoid::nanoid;
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
@ -10,7 +10,7 @@ use flowy_error::FlowyResult;
|
||||
use lib_infra::future::Fut;
|
||||
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::{DatabaseRowEvent, MutexDatabase};
|
||||
use crate::services::database::{DatabaseRowEvent, MutexDatabase, RowDetail};
|
||||
use crate::services::database_view::{DatabaseViewData, DatabaseViewEditor};
|
||||
use crate::services::group::RowChangeset;
|
||||
|
||||
@ -58,15 +58,15 @@ impl DatabaseViews {
|
||||
pub async fn move_group_row(
|
||||
&self,
|
||||
view_id: &str,
|
||||
row: Arc<Row>,
|
||||
row_detail: Arc<RowDetail>,
|
||||
to_group_id: String,
|
||||
to_row_id: Option<RowId>,
|
||||
recv_row_changeset: impl FnOnce(RowChangeset) -> Fut<()>,
|
||||
) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
let mut row_changeset = RowChangeset::new(row.id.clone());
|
||||
let mut row_changeset = RowChangeset::new(row_detail.row.id.clone());
|
||||
view_editor
|
||||
.v_move_group_row(&row, &mut row_changeset, &to_group_id, to_row_id)
|
||||
.v_move_group_row(&row_detail, &mut row_changeset, &to_group_id, to_row_id)
|
||||
.await;
|
||||
|
||||
if !row_changeset.is_empty() {
|
||||
|
@ -13,8 +13,9 @@ use flowy_task::{QualityOfService, Task, TaskContent, TaskDispatcher};
|
||||
use lib_infra::future::Fut;
|
||||
|
||||
use crate::entities::filter_entities::*;
|
||||
use crate::entities::{FieldType, InsertedRowPB, RowPB};
|
||||
use crate::entities::{FieldType, InsertedRowPB, RowMetaPB};
|
||||
use crate::services::cell::{AnyTypeCache, CellCache, CellFilterCache};
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewChangedNotifier};
|
||||
use crate::services::field::*;
|
||||
use crate::services::filter::{Filter, FilterChangeset, FilterResult, FilterResultNotification};
|
||||
@ -23,8 +24,8 @@ pub trait FilterDelegate: Send + Sync + 'static {
|
||||
fn get_filter(&self, view_id: &str, filter_id: &str) -> Fut<Option<Arc<Filter>>>;
|
||||
fn get_field(&self, field_id: &str) -> Fut<Option<Arc<Field>>>;
|
||||
fn get_fields(&self, view_id: &str, field_ids: Option<Vec<String>>) -> Fut<Vec<Arc<Field>>>;
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<Row>>>;
|
||||
fn get_row(&self, view_id: &str, rows_id: &RowId) -> Fut<Option<(usize, Arc<Row>)>>;
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<RowDetail>>>;
|
||||
fn get_row(&self, view_id: &str, rows_id: &RowId) -> Fut<Option<(usize, Arc<RowDetail>)>>;
|
||||
}
|
||||
|
||||
pub trait FromFilterString {
|
||||
@ -98,14 +99,14 @@ impl FilterController {
|
||||
self.task_scheduler.write().await.add_task(task);
|
||||
}
|
||||
|
||||
pub async fn filter_rows(&self, rows: &mut Vec<Arc<Row>>) {
|
||||
pub async fn filter_rows(&self, rows: &mut Vec<Arc<RowDetail>>) {
|
||||
if self.cell_filter_cache.read().is_empty() {
|
||||
return;
|
||||
}
|
||||
let field_by_field_id = self.get_field_map().await;
|
||||
rows.iter().for_each(|row| {
|
||||
rows.iter().for_each(|row_detail| {
|
||||
let _ = filter_row(
|
||||
row,
|
||||
&row_detail.row,
|
||||
&self.result_by_row_id,
|
||||
&field_by_field_id,
|
||||
&self.cell_cache,
|
||||
@ -113,10 +114,10 @@ impl FilterController {
|
||||
);
|
||||
});
|
||||
|
||||
rows.retain(|row| {
|
||||
rows.retain(|row_detail| {
|
||||
self
|
||||
.result_by_row_id
|
||||
.get(&row.id)
|
||||
.get(&row_detail.row.id)
|
||||
.map(|result| result.is_visible())
|
||||
.unwrap_or(false)
|
||||
});
|
||||
@ -149,22 +150,21 @@ impl FilterController {
|
||||
}
|
||||
|
||||
async fn filter_row(&self, row_id: RowId) -> FlowyResult<()> {
|
||||
if let Some((_, row)) = self.delegate.get_row(&self.view_id, &row_id).await {
|
||||
if let Some((_, row_detail)) = self.delegate.get_row(&self.view_id, &row_id).await {
|
||||
let field_by_field_id = self.get_field_map().await;
|
||||
let mut notification = FilterResultNotification::new(self.view_id.clone());
|
||||
if let Some((row_id, is_visible)) = filter_row(
|
||||
&row,
|
||||
&row_detail.row,
|
||||
&self.result_by_row_id,
|
||||
&field_by_field_id,
|
||||
&self.cell_cache,
|
||||
&self.cell_filter_cache,
|
||||
) {
|
||||
if is_visible {
|
||||
if let Some((index, row)) = self.delegate.get_row(&self.view_id, &row_id).await {
|
||||
let row_pb = RowPB::from(row.as_ref());
|
||||
if let Some((index, _row)) = self.delegate.get_row(&self.view_id, &row_id).await {
|
||||
notification
|
||||
.visible_rows
|
||||
.push(InsertedRowPB::new(row_pb).with_index(index as i32))
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)).with_index(index as i32))
|
||||
}
|
||||
} else {
|
||||
notification.invisible_rows.push(row_id);
|
||||
@ -183,7 +183,7 @@ impl FilterController {
|
||||
let mut visible_rows = vec![];
|
||||
let mut invisible_rows = vec![];
|
||||
|
||||
for (index, row) in self
|
||||
for (index, row_detail) in self
|
||||
.delegate
|
||||
.get_rows(&self.view_id)
|
||||
.await
|
||||
@ -191,15 +191,15 @@ impl FilterController {
|
||||
.enumerate()
|
||||
{
|
||||
if let Some((row_id, is_visible)) = filter_row(
|
||||
&row,
|
||||
&row_detail.row,
|
||||
&self.result_by_row_id,
|
||||
&field_by_field_id,
|
||||
&self.cell_cache,
|
||||
&self.cell_filter_cache,
|
||||
) {
|
||||
if is_visible {
|
||||
let row_pb = RowPB::from(row.as_ref());
|
||||
visible_rows.push(InsertedRowPB::new(row_pb).with_index(index as i32))
|
||||
let row_meta = RowMetaPB::from(&row_detail.meta);
|
||||
visible_rows.push(InsertedRowPB::new(row_meta).with_index(index as i32))
|
||||
} else {
|
||||
invisible_rows.push(row_id);
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
use crate::entities::{GroupChangesPB, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
||||
use crate::services::cell::DecodedCellData;
|
||||
use crate::services::group::controller::MoveGroupRowContext;
|
||||
use crate::services::group::{GroupData, GroupSettingChangeset};
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Cell, Row};
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::{GroupChangesPB, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
||||
use crate::services::cell::DecodedCellData;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::group::controller::MoveGroupRowContext;
|
||||
use crate::services::group::{GroupData, GroupSettingChangeset};
|
||||
|
||||
/// Using polymorphism to provides the customs action for different group controller.
|
||||
///
|
||||
/// For example, the `CheckboxGroupController` implements this trait to provide custom behavior.
|
||||
@ -28,7 +30,7 @@ pub trait GroupCustomize: Send + Sync {
|
||||
|
||||
fn create_or_delete_group_when_cell_changed(
|
||||
&mut self,
|
||||
_row: &Row,
|
||||
_row_detail: &RowDetail,
|
||||
_old_cell_data: Option<&Self::CellData>,
|
||||
_cell_data: &Self::CellData,
|
||||
) -> FlowyResult<(Option<InsertedGroupPB>, Option<GroupPB>)> {
|
||||
@ -40,7 +42,7 @@ pub trait GroupCustomize: Send + Sync {
|
||||
///
|
||||
fn add_or_remove_row_when_cell_changed(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
row_detail: &RowDetail,
|
||||
cell_data: &Self::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB>;
|
||||
|
||||
@ -76,7 +78,7 @@ pub trait GroupControllerOperation: Send + Sync {
|
||||
fn get_group(&self, group_id: &str) -> Option<(usize, GroupData)>;
|
||||
|
||||
/// Separates the rows into different groups
|
||||
fn fill_groups(&mut self, rows: &[&Row], field: &Field) -> FlowyResult<()>;
|
||||
fn fill_groups(&mut self, rows: &[&RowDetail], field: &Field) -> FlowyResult<()>;
|
||||
|
||||
/// Remove the group with from_group_id and insert it to the index with to_group_id
|
||||
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()>;
|
||||
@ -84,8 +86,8 @@ pub trait GroupControllerOperation: Send + Sync {
|
||||
/// Insert/Remove the row to the group if the corresponding cell data is changed
|
||||
fn did_update_group_row(
|
||||
&mut self,
|
||||
old_row: &Option<Row>,
|
||||
row: &Row,
|
||||
old_row_detail: &Option<RowDetail>,
|
||||
row_detail: &RowDetail,
|
||||
field: &Field,
|
||||
) -> FlowyResult<DidUpdateGroupRowResult>;
|
||||
|
||||
|
@ -9,8 +9,11 @@ use serde::Serialize;
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::{FieldType, GroupChangesPB, GroupRowsNotificationPB, InsertedRowPB};
|
||||
use crate::entities::{
|
||||
FieldType, GroupChangesPB, GroupRowsNotificationPB, InsertedRowPB, RowMetaPB,
|
||||
};
|
||||
use crate::services::cell::{get_cell_protobuf, CellProtobufBlobParser, DecodedCellData};
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::group::action::{
|
||||
DidMoveGroupRowResult, DidUpdateGroupRowResult, GroupControllerOperation, GroupCustomize,
|
||||
};
|
||||
@ -36,7 +39,7 @@ pub trait GroupController: GroupControllerOperation + Send + Sync {
|
||||
fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str);
|
||||
|
||||
/// Called after the row was created.
|
||||
fn did_create_row(&mut self, row: &Row, group_id: &str);
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str);
|
||||
}
|
||||
|
||||
/// The [GroupsBuilder] trait is used to generate the groups for different [FieldType]
|
||||
@ -62,7 +65,7 @@ pub struct GeneratedGroupConfig {
|
||||
}
|
||||
|
||||
pub struct MoveGroupRowContext<'a> {
|
||||
pub row: &'a Row,
|
||||
pub row_detail: &'a RowDetail,
|
||||
pub row_changeset: &'a mut RowChangeset,
|
||||
pub field: &'a Field,
|
||||
pub to_group_id: &'a str,
|
||||
@ -134,7 +137,7 @@ where
|
||||
#[allow(clippy::needless_collect)]
|
||||
fn update_no_status_group(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
row_detail: &RowDetail,
|
||||
other_group_changesets: &[GroupRowsNotificationPB],
|
||||
) -> Option<GroupRowsNotificationPB> {
|
||||
let no_status_group = self.context.get_mut_no_status_group()?;
|
||||
@ -155,14 +158,16 @@ where
|
||||
// which means the row should not move to the default group.
|
||||
!other_group_inserted_row
|
||||
.iter()
|
||||
.any(|inserted_row| &inserted_row.row.id == row_id)
|
||||
.any(|inserted_row| &inserted_row.row_meta.id == row_id)
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let mut changeset = GroupRowsNotificationPB::new(no_status_group.id.clone());
|
||||
if !no_status_group_rows.is_empty() {
|
||||
changeset.inserted_rows.push(InsertedRowPB::new(row.into()));
|
||||
no_status_group.add_row(row.clone());
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
|
||||
no_status_group.add_row(row_detail.clone());
|
||||
}
|
||||
|
||||
// [other_group_delete_rows] contains all the deleted rows except the default group.
|
||||
@ -180,23 +185,23 @@ where
|
||||
// out from the default_group.
|
||||
!other_group_delete_rows
|
||||
.iter()
|
||||
.any(|row_id| &inserted_row.row.id == row_id)
|
||||
.any(|row_id| &inserted_row.row_meta.id == row_id)
|
||||
})
|
||||
.collect::<Vec<&InsertedRowPB>>();
|
||||
|
||||
let mut deleted_row_ids = vec![];
|
||||
for row in &no_status_group.rows {
|
||||
let row_id = row.id.clone().into_inner();
|
||||
for row_detail in &no_status_group.rows {
|
||||
let row_id = row_detail.meta.row_id.clone();
|
||||
if default_group_deleted_rows
|
||||
.iter()
|
||||
.any(|deleted_row| deleted_row.row.id == row_id)
|
||||
.any(|deleted_row| deleted_row.row_meta.id == row_id)
|
||||
{
|
||||
deleted_row_ids.push(row_id);
|
||||
}
|
||||
}
|
||||
no_status_group
|
||||
.rows
|
||||
.retain(|row| !deleted_row_ids.contains(&row.id));
|
||||
.retain(|row_detail| !deleted_row_ids.contains(&row_detail.meta.row_id));
|
||||
changeset.deleted_rows.extend(deleted_row_ids);
|
||||
Some(changeset)
|
||||
}
|
||||
@ -225,9 +230,9 @@ where
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, fields(row_count=%rows.len(), group_result))]
|
||||
fn fill_groups(&mut self, rows: &[&Row], field: &Field) -> FlowyResult<()> {
|
||||
for row in rows {
|
||||
let cell = match row.cells.get(&self.grouping_field_id) {
|
||||
fn fill_groups(&mut self, rows: &[&RowDetail], field: &Field) -> FlowyResult<()> {
|
||||
for row_detail in rows {
|
||||
let cell = match row_detail.row.cells.get(&self.grouping_field_id) {
|
||||
None => self.placeholder_cell(),
|
||||
Some(cell) => Some(cell.clone()),
|
||||
};
|
||||
@ -239,7 +244,7 @@ where
|
||||
for group in self.context.groups() {
|
||||
if self.can_group(&group.filter_content, &cell_data) {
|
||||
grouped_rows.push(GroupedRow {
|
||||
row: (*row).clone(),
|
||||
row_detail: (*row_detail).clone(),
|
||||
group_id: group.id.clone(),
|
||||
});
|
||||
}
|
||||
@ -248,7 +253,7 @@ where
|
||||
if !grouped_rows.is_empty() {
|
||||
for group_row in grouped_rows {
|
||||
if let Some(group) = self.context.get_mut_group(&group_row.group_id) {
|
||||
group.add_row(group_row.row);
|
||||
group.add_row(group_row.row_detail);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@ -257,7 +262,7 @@ where
|
||||
|
||||
match self.context.get_mut_no_status_group() {
|
||||
None => {},
|
||||
Some(no_status_group) => no_status_group.add_row((*row).clone()),
|
||||
Some(no_status_group) => no_status_group.add_row((*row_detail).clone()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,8 +276,8 @@ where
|
||||
|
||||
fn did_update_group_row(
|
||||
&mut self,
|
||||
old_row: &Option<Row>,
|
||||
row: &Row,
|
||||
old_row_detail: &Option<RowDetail>,
|
||||
row_detail: &RowDetail,
|
||||
field: &Field,
|
||||
) -> FlowyResult<DidUpdateGroupRowResult> {
|
||||
// let cell_data = row_rev.cells.get(&self.field_id).and_then(|cell_rev| {
|
||||
@ -285,18 +290,21 @@ where
|
||||
row_changesets: vec![],
|
||||
};
|
||||
|
||||
if let Some(cell_data) = get_cell_data_from_row::<P>(Some(row), field) {
|
||||
let old_row = old_row.as_ref();
|
||||
let old_cell_data = get_cell_data_from_row::<P>(old_row, field);
|
||||
if let Ok((insert, delete)) =
|
||||
self.create_or_delete_group_when_cell_changed(row, old_cell_data.as_ref(), &cell_data)
|
||||
{
|
||||
if let Some(cell_data) = get_cell_data_from_row::<P>(Some(&row_detail.row), field) {
|
||||
let _old_row = old_row_detail.as_ref();
|
||||
let old_cell_data =
|
||||
get_cell_data_from_row::<P>(old_row_detail.as_ref().map(|detail| &detail.row), field);
|
||||
if let Ok((insert, delete)) = self.create_or_delete_group_when_cell_changed(
|
||||
row_detail,
|
||||
old_cell_data.as_ref(),
|
||||
&cell_data,
|
||||
) {
|
||||
result.inserted_group = insert;
|
||||
result.deleted_group = delete;
|
||||
}
|
||||
|
||||
let mut changesets = self.add_or_remove_row_when_cell_changed(row, &cell_data);
|
||||
if let Some(changeset) = self.update_no_status_group(row, &changesets) {
|
||||
let mut changesets = self.add_or_remove_row_when_cell_changed(row_detail, &cell_data);
|
||||
if let Some(changeset) = self.update_no_status_group(row_detail, &changesets) {
|
||||
if !changeset.is_empty() {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
@ -350,7 +358,7 @@ where
|
||||
deleted_group: None,
|
||||
row_changesets: vec![],
|
||||
};
|
||||
let cell = match context.row.cells.get(&self.grouping_field_id) {
|
||||
let cell = match context.row_detail.row.cells.get(&self.grouping_field_id) {
|
||||
Some(cell) => Some(cell.clone()),
|
||||
None => self.placeholder_cell(),
|
||||
};
|
||||
@ -358,7 +366,7 @@ where
|
||||
if let Some(cell) = cell {
|
||||
let cell_bytes = get_cell_protobuf(&cell, context.field, None);
|
||||
let cell_data = cell_bytes.parser::<P>()?;
|
||||
result.deleted_group = self.delete_group_when_move_row(context.row, &cell_data);
|
||||
result.deleted_group = self.delete_group_when_move_row(&context.row_detail.row, &cell_data);
|
||||
result.row_changesets = self.move_row(&cell_data, context);
|
||||
} else {
|
||||
tracing::warn!("Unexpected moving group row, changes should not be empty");
|
||||
@ -381,7 +389,7 @@ where
|
||||
}
|
||||
|
||||
struct GroupedRow {
|
||||
row: Row,
|
||||
row_detail: RowDetail,
|
||||
group_id: String,
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB, InsertedRowPB, RowPB};
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB, InsertedRowPB, RowMetaPB};
|
||||
use crate::services::cell::insert_checkbox_cell;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{
|
||||
CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOption, CHECK, UNCHECK,
|
||||
};
|
||||
@ -49,25 +51,27 @@ impl GroupCustomize for CheckboxGroupController {
|
||||
|
||||
fn add_or_remove_row_when_cell_changed(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
row_detail: &RowDetail,
|
||||
cell_data: &Self::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
let mut changesets = vec![];
|
||||
self.context.iter_mut_status_groups(|group| {
|
||||
let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
|
||||
let is_not_contained = !group.contains_row(&row.id);
|
||||
let is_not_contained = !group.contains_row(&row_detail.row.id);
|
||||
if group.id == CHECK {
|
||||
if cell_data.is_uncheck() {
|
||||
// Remove the row if the group.id is CHECK but the cell_data is UNCHECK
|
||||
changeset.deleted_rows.push(row.id.clone().into_inner());
|
||||
group.remove_row(&row.id);
|
||||
changeset
|
||||
.deleted_rows
|
||||
.push(row_detail.row.id.clone().into_inner());
|
||||
group.remove_row(&row_detail.row.id);
|
||||
} else {
|
||||
// Add the row to the group if the group didn't contain the row
|
||||
if is_not_contained {
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowPB::from(row)));
|
||||
group.add_row(row.clone());
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
|
||||
group.add_row(row_detail.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,15 +79,17 @@ impl GroupCustomize for CheckboxGroupController {
|
||||
if group.id == UNCHECK {
|
||||
if cell_data.is_check() {
|
||||
// Remove the row if the group.id is UNCHECK but the cell_data is CHECK
|
||||
changeset.deleted_rows.push(row.id.clone().into_inner());
|
||||
group.remove_row(&row.id);
|
||||
changeset
|
||||
.deleted_rows
|
||||
.push(row_detail.row.id.clone().into_inner());
|
||||
group.remove_row(&row_detail.row.id);
|
||||
} else {
|
||||
// Add the row to the group if the group didn't contain the row
|
||||
if is_not_contained {
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowPB::from(row)));
|
||||
group.add_row(row.clone());
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
|
||||
group.add_row(row_detail.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,9 +148,9 @@ impl GroupController for CheckboxGroupController {
|
||||
}
|
||||
}
|
||||
|
||||
fn did_create_row(&mut self, row: &Row, group_id: &str) {
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str) {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row.clone())
|
||||
group.add_row(row_detail.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use collab_database::rows::{Cells, Row};
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::GroupChangesPB;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::group::action::{
|
||||
DidMoveGroupRowResult, DidUpdateGroupRowResult, GroupControllerOperation,
|
||||
};
|
||||
@ -52,7 +53,7 @@ impl GroupControllerOperation for DefaultGroupController {
|
||||
Some((0, self.group.clone()))
|
||||
}
|
||||
|
||||
fn fill_groups(&mut self, rows: &[&Row], _field: &Field) -> FlowyResult<()> {
|
||||
fn fill_groups(&mut self, rows: &[&RowDetail], _field: &Field) -> FlowyResult<()> {
|
||||
rows.iter().for_each(|row| {
|
||||
self.group.add_row((*row).clone());
|
||||
});
|
||||
@ -65,8 +66,8 @@ impl GroupControllerOperation for DefaultGroupController {
|
||||
|
||||
fn did_update_group_row(
|
||||
&mut self,
|
||||
_old_row: &Option<Row>,
|
||||
_row: &Row,
|
||||
_old_row_detail: &Option<RowDetail>,
|
||||
_row_detail: &RowDetail,
|
||||
_field: &Field,
|
||||
) -> FlowyResult<DidUpdateGroupRowResult> {
|
||||
Ok(DidUpdateGroupRowResult {
|
||||
@ -116,5 +117,5 @@ impl GroupController for DefaultGroupController {
|
||||
|
||||
fn will_create_row(&mut self, _cells: &mut Cells, _field: &Field, _group_id: &str) {}
|
||||
|
||||
fn did_create_row(&mut self, _row: &Row, _group_id: &str) {}
|
||||
fn did_create_row(&mut self, _row_detail: &RowDetail, _group_id: &str) {}
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB, SelectOptionCellDataPB};
|
||||
use crate::services::cell::insert_select_option_cell;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{MultiSelectTypeOption, SelectOptionCellDataParser};
|
||||
use crate::services::group::action::GroupCustomize;
|
||||
use crate::services::group::controller::{
|
||||
@ -9,11 +16,6 @@ use crate::services::group::{
|
||||
add_or_remove_select_option_row, generate_select_option_groups, make_no_status_group,
|
||||
move_group_row, remove_select_option_row, GeneratedGroups, GroupContext,
|
||||
};
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct MultiSelectGroupConfiguration {
|
||||
@ -49,12 +51,12 @@ impl GroupCustomize for MultiSelectGroupController {
|
||||
|
||||
fn add_or_remove_row_when_cell_changed(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
row_detail: &RowDetail,
|
||||
cell_data: &Self::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
let mut changesets = vec![];
|
||||
self.context.iter_mut_status_groups(|group| {
|
||||
if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row) {
|
||||
if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row_detail) {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
@ -99,9 +101,9 @@ impl GroupController for MultiSelectGroupController {
|
||||
}
|
||||
}
|
||||
|
||||
fn did_create_row(&mut self, row: &Row, group_id: &str) {
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str) {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row.clone())
|
||||
group.add_row(row_detail.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB, SelectOptionCellDataPB};
|
||||
use crate::services::cell::insert_select_option_cell;
|
||||
use crate::services::field::{SelectOptionCellDataParser, SingleSelectTypeOption};
|
||||
use crate::services::group::action::GroupCustomize;
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB, SelectOptionCellDataPB};
|
||||
use crate::services::cell::insert_select_option_cell;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{SelectOptionCellDataParser, SingleSelectTypeOption};
|
||||
use crate::services::group::action::GroupCustomize;
|
||||
use crate::services::group::controller::{
|
||||
BaseGroupController, GroupController, GroupsBuilder, MoveGroupRowContext,
|
||||
};
|
||||
@ -13,8 +16,6 @@ use crate::services::group::controller_impls::select_option_controller::util::*;
|
||||
use crate::services::group::entities::GroupData;
|
||||
use crate::services::group::{make_no_status_group, GeneratedGroups, GroupContext};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
pub struct SingleSelectGroupConfiguration {
|
||||
pub hide_empty: bool,
|
||||
@ -49,12 +50,12 @@ impl GroupCustomize for SingleSelectGroupController {
|
||||
|
||||
fn add_or_remove_row_when_cell_changed(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
row_detail: &RowDetail,
|
||||
cell_data: &Self::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
let mut changesets = vec![];
|
||||
self.context.iter_mut_status_groups(|group| {
|
||||
if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row) {
|
||||
if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row_detail) {
|
||||
changesets.push(changeset);
|
||||
}
|
||||
});
|
||||
@ -99,9 +100,9 @@ impl GroupController for SingleSelectGroupController {
|
||||
},
|
||||
}
|
||||
}
|
||||
fn did_create_row(&mut self, row: &Row, group_id: &str) {
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str) {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row.clone())
|
||||
group.add_row(row_detail.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ use collab_database::fields::Field;
|
||||
use collab_database::rows::{Cell, Row};
|
||||
|
||||
use crate::entities::{
|
||||
FieldType, GroupRowsNotificationPB, InsertedRowPB, RowPB, SelectOptionCellDataPB,
|
||||
FieldType, GroupRowsNotificationPB, InsertedRowPB, RowMetaPB, SelectOptionCellDataPB,
|
||||
};
|
||||
use crate::services::cell::{insert_checkbox_cell, insert_select_option_cell, insert_url_cell};
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{SelectOption, CHECK};
|
||||
use crate::services::group::controller::MoveGroupRowContext;
|
||||
use crate::services::group::{GeneratedGroupConfig, Group, GroupData};
|
||||
@ -12,26 +13,30 @@ use crate::services::group::{GeneratedGroupConfig, Group, GroupData};
|
||||
pub fn add_or_remove_select_option_row(
|
||||
group: &mut GroupData,
|
||||
cell_data: &SelectOptionCellDataPB,
|
||||
row: &Row,
|
||||
row_detail: &RowDetail,
|
||||
) -> Option<GroupRowsNotificationPB> {
|
||||
let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
|
||||
if cell_data.select_options.is_empty() {
|
||||
if group.contains_row(&row.id) {
|
||||
group.remove_row(&row.id);
|
||||
changeset.deleted_rows.push(row.id.clone().into_inner());
|
||||
if group.contains_row(&row_detail.row.id) {
|
||||
group.remove_row(&row_detail.row.id);
|
||||
changeset
|
||||
.deleted_rows
|
||||
.push(row_detail.row.id.clone().into_inner());
|
||||
}
|
||||
} else {
|
||||
cell_data.select_options.iter().for_each(|option| {
|
||||
if option.id == group.id {
|
||||
if !group.contains_row(&row.id) {
|
||||
if !group.contains_row(&row_detail.row.id) {
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowPB::from(row)));
|
||||
group.add_row(row.clone());
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
|
||||
group.add_row(row_detail.clone());
|
||||
}
|
||||
} else if group.contains_row(&row.id) {
|
||||
group.remove_row(&row.id);
|
||||
changeset.deleted_rows.push(row.id.clone().into_inner());
|
||||
} else if group.contains_row(&row_detail.row.id) {
|
||||
group.remove_row(&row_detail.row.id);
|
||||
changeset
|
||||
.deleted_rows
|
||||
.push(row_detail.row.id.clone().into_inner());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -69,14 +74,14 @@ pub fn move_group_row(
|
||||
) -> Option<GroupRowsNotificationPB> {
|
||||
let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
|
||||
let MoveGroupRowContext {
|
||||
row,
|
||||
row_detail,
|
||||
row_changeset,
|
||||
field,
|
||||
to_group_id,
|
||||
to_row_id,
|
||||
} = context;
|
||||
|
||||
let from_index = group.index_of_row(&row.id);
|
||||
let from_index = group.index_of_row(&row_detail.row.id);
|
||||
let to_index = match to_row_id {
|
||||
None => None,
|
||||
Some(to_row_id) => group.index_of_row(to_row_id),
|
||||
@ -84,28 +89,40 @@ pub fn move_group_row(
|
||||
|
||||
// Remove the row in which group contains it
|
||||
if let Some(from_index) = &from_index {
|
||||
changeset.deleted_rows.push(row.id.clone().into_inner());
|
||||
tracing::debug!("Group:{} remove {} at {}", group.id, row.id, from_index);
|
||||
group.remove_row(&row.id);
|
||||
changeset
|
||||
.deleted_rows
|
||||
.push(row_detail.row.id.clone().into_inner());
|
||||
tracing::debug!(
|
||||
"Group:{} remove {} at {}",
|
||||
group.id,
|
||||
row_detail.row.id,
|
||||
from_index
|
||||
);
|
||||
group.remove_row(&row_detail.row.id);
|
||||
}
|
||||
|
||||
if group.id == *to_group_id {
|
||||
let mut inserted_row = InsertedRowPB::new(RowPB::from(*row));
|
||||
let mut inserted_row = InsertedRowPB::new(RowMetaPB::from(&row_detail.meta));
|
||||
match to_index {
|
||||
None => {
|
||||
changeset.inserted_rows.push(inserted_row);
|
||||
tracing::debug!("Group:{} append row:{}", group.id, row.id);
|
||||
group.add_row(row.clone());
|
||||
tracing::debug!("Group:{} append row:{}", group.id, row_detail.row.id);
|
||||
group.add_row(row_detail.clone());
|
||||
},
|
||||
Some(to_index) => {
|
||||
if to_index < group.number_of_row() {
|
||||
tracing::debug!("Group:{} insert {} at {} ", group.id, row.id, to_index);
|
||||
tracing::debug!(
|
||||
"Group:{} insert {} at {} ",
|
||||
group.id,
|
||||
row_detail.row.id,
|
||||
to_index
|
||||
);
|
||||
inserted_row.index = Some(to_index as i32);
|
||||
group.insert_row(to_index, (*row).clone());
|
||||
group.insert_row(to_index, (*row_detail).clone());
|
||||
} else {
|
||||
tracing::warn!("Move to index: {} is out of bounds", to_index);
|
||||
tracing::debug!("Group:{} append row:{}", group.id, row.id);
|
||||
group.add_row((*row).clone());
|
||||
tracing::debug!("Group:{} append row:{}", group.id, row_detail.row.id);
|
||||
group.add_row((*row_detail).clone());
|
||||
}
|
||||
changeset.inserted_rows.push(inserted_row);
|
||||
},
|
||||
@ -119,7 +136,7 @@ pub fn move_group_row(
|
||||
if let Some(cell) = cell {
|
||||
tracing::debug!(
|
||||
"Update content of the cell in the row:{} to group:{}",
|
||||
row.id,
|
||||
row_detail.row.id,
|
||||
group.id
|
||||
);
|
||||
row_changeset
|
||||
|
@ -1,14 +1,17 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::{
|
||||
FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB, InsertedRowPB, RowPB, URLCellDataPB,
|
||||
FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB, InsertedRowPB, RowMetaPB,
|
||||
URLCellDataPB,
|
||||
};
|
||||
use crate::services::cell::insert_url_cell;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{URLCellData, URLCellDataParser, URLTypeOption};
|
||||
use crate::services::group::action::GroupCustomize;
|
||||
use crate::services::group::configuration::GroupContext;
|
||||
@ -46,7 +49,7 @@ impl GroupCustomize for URLGroupController {
|
||||
|
||||
fn create_or_delete_group_when_cell_changed(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
row_detail: &RowDetail,
|
||||
_old_cell_data: Option<&Self::CellData>,
|
||||
_cell_data: &Self::CellData,
|
||||
) -> FlowyResult<(Option<InsertedGroupPB>, Option<GroupPB>)> {
|
||||
@ -56,7 +59,7 @@ impl GroupCustomize for URLGroupController {
|
||||
let cell_data: URLCellData = _cell_data.clone().into();
|
||||
let group = make_group_from_url_cell(&cell_data);
|
||||
let mut new_group = self.context.add_new_group(group)?;
|
||||
new_group.group.rows.push(RowPB::from(row));
|
||||
new_group.group.rows.push(RowMetaPB::from(&row_detail.meta));
|
||||
inserted_group = Some(new_group);
|
||||
}
|
||||
|
||||
@ -87,22 +90,24 @@ impl GroupCustomize for URLGroupController {
|
||||
|
||||
fn add_or_remove_row_when_cell_changed(
|
||||
&mut self,
|
||||
row: &Row,
|
||||
row_detail: &RowDetail,
|
||||
cell_data: &Self::CellData,
|
||||
) -> Vec<GroupRowsNotificationPB> {
|
||||
let mut changesets = vec![];
|
||||
self.context.iter_mut_status_groups(|group| {
|
||||
let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
|
||||
if group.id == cell_data.content {
|
||||
if !group.contains_row(&row.id) {
|
||||
if !group.contains_row(&row_detail.row.id) {
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowPB::from(row)));
|
||||
group.add_row(row.clone());
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
|
||||
group.add_row(row_detail.clone());
|
||||
}
|
||||
} else if group.contains_row(&row.id) {
|
||||
group.remove_row(&row.id);
|
||||
changeset.deleted_rows.push(row.id.clone().into_inner());
|
||||
} else if group.contains_row(&row_detail.row.id) {
|
||||
group.remove_row(&row_detail.row.id);
|
||||
changeset
|
||||
.deleted_rows
|
||||
.push(row_detail.row.id.clone().into_inner());
|
||||
}
|
||||
|
||||
if !changeset.is_empty() {
|
||||
@ -175,9 +180,9 @@ impl GroupController for URLGroupController {
|
||||
}
|
||||
}
|
||||
|
||||
fn did_create_row(&mut self, row: &Row, group_id: &str) {
|
||||
fn did_create_row(&mut self, row_detail: &RowDetail, group_id: &str) {
|
||||
if let Some(group) = self.context.get_mut_group(group_id) {
|
||||
group.add_row(row.clone())
|
||||
group.add_row(row_detail.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
use anyhow::bail;
|
||||
use collab::core::any_map::AnyMapExtension;
|
||||
use collab_database::database::gen_database_group_id;
|
||||
use collab_database::rows::{Row, RowId};
|
||||
use collab_database::rows::RowId;
|
||||
use collab_database::views::{GroupMap, GroupMapBuilder, GroupSettingBuilder, GroupSettingMap};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::services::database::RowDetail;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct GroupSetting {
|
||||
pub id: String,
|
||||
@ -133,7 +135,7 @@ pub struct GroupData {
|
||||
pub name: String,
|
||||
pub is_default: bool,
|
||||
pub is_visible: bool,
|
||||
pub(crate) rows: Vec<Row>,
|
||||
pub(crate) rows: Vec<RowDetail>,
|
||||
|
||||
/// [filter_content] is used to determine which group the cell belongs to.
|
||||
pub filter_content: String,
|
||||
@ -154,11 +156,18 @@ impl GroupData {
|
||||
}
|
||||
|
||||
pub fn contains_row(&self, row_id: &RowId) -> bool {
|
||||
self.rows.iter().any(|row| &row.id == row_id)
|
||||
self
|
||||
.rows
|
||||
.iter()
|
||||
.any(|row_detail| &row_detail.row.id == row_id)
|
||||
}
|
||||
|
||||
pub fn remove_row(&mut self, row_id: &RowId) {
|
||||
match self.rows.iter().position(|row| &row.id == row_id) {
|
||||
match self
|
||||
.rows
|
||||
.iter()
|
||||
.position(|row_detail| &row_detail.row.id == row_id)
|
||||
{
|
||||
None => {},
|
||||
Some(pos) => {
|
||||
self.rows.remove(pos);
|
||||
@ -166,18 +175,18 @@ impl GroupData {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_row(&mut self, row: Row) {
|
||||
match self.rows.iter().find(|r| r.id == row.id) {
|
||||
pub fn add_row(&mut self, row_detail: RowDetail) {
|
||||
match self.rows.iter().find(|r| r.row.id == row_detail.row.id) {
|
||||
None => {
|
||||
self.rows.push(row);
|
||||
self.rows.push(row_detail);
|
||||
},
|
||||
Some(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_row(&mut self, index: usize, row: Row) {
|
||||
pub fn insert_row(&mut self, index: usize, row_detail: RowDetail) {
|
||||
if index < self.rows.len() {
|
||||
self.rows.insert(index, row);
|
||||
self.rows.insert(index, row_detail);
|
||||
} else {
|
||||
tracing::error!(
|
||||
"Insert row index:{} beyond the bounds:{},",
|
||||
@ -188,7 +197,10 @@ impl GroupData {
|
||||
}
|
||||
|
||||
pub fn index_of_row(&self, row_id: &RowId) -> Option<usize> {
|
||||
self.rows.iter().position(|row| &row.id == row_id)
|
||||
self
|
||||
.rows
|
||||
.iter()
|
||||
.position(|row_detail| &row_detail.row.id == row_id)
|
||||
}
|
||||
|
||||
pub fn number_of_row(&self) -> usize {
|
||||
|
@ -1,4 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::views::DatabaseLayout;
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::group::configuration::GroupSettingReader;
|
||||
use crate::services::group::controller::GroupController;
|
||||
use crate::services::group::{
|
||||
@ -6,12 +14,6 @@ use crate::services::group::{
|
||||
GroupSettingWriter, MultiSelectGroupController, MultiSelectOptionGroupContext,
|
||||
SingleSelectGroupController, SingleSelectOptionGroupContext, URLGroupContext, URLGroupController,
|
||||
};
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::Row;
|
||||
use collab_database::views::DatabaseLayout;
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Returns a group controller.
|
||||
///
|
||||
@ -33,7 +35,7 @@ use std::sync::Arc;
|
||||
pub async fn make_group_controller<R, W>(
|
||||
view_id: String,
|
||||
grouping_field: Arc<Field>,
|
||||
rows: Vec<Arc<Row>>,
|
||||
row_details: Vec<Arc<RowDetail>>,
|
||||
setting_reader: R,
|
||||
setting_writer: W,
|
||||
) -> FlowyResult<Box<dyn GroupController>>
|
||||
@ -99,7 +101,10 @@ where
|
||||
}
|
||||
|
||||
// Separates the rows into different groups
|
||||
let rows = rows.iter().map(|row| row.as_ref()).collect::<Vec<&Row>>();
|
||||
let rows = row_details
|
||||
.iter()
|
||||
.map(|row| row.as_ref())
|
||||
.collect::<Vec<&RowDetail>>();
|
||||
group_controller.fill_groups(rows.as_slice(), &grouping_field)?;
|
||||
Ok(group_controller)
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ use lib_infra::future::Fut;
|
||||
use crate::entities::FieldType;
|
||||
use crate::entities::SortChangesetNotificationPB;
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewChangedNotifier};
|
||||
use crate::services::field::{default_order, TypeOptionCellExt};
|
||||
use crate::services::sort::{
|
||||
@ -25,7 +26,7 @@ use crate::services::sort::{
|
||||
pub trait SortDelegate: Send + Sync {
|
||||
fn get_sort(&self, view_id: &str, sort_id: &str) -> Fut<Option<Arc<Sort>>>;
|
||||
/// Returns all the rows after applying grid's filter
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<Row>>>;
|
||||
fn get_rows(&self, view_id: &str) -> Fut<Vec<Arc<RowDetail>>>;
|
||||
fn get_field(&self, field_id: &str) -> Fut<Option<Arc<Field>>>;
|
||||
fn get_fields(&self, view_id: &str, field_ids: Option<Vec<String>>) -> Fut<Vec<Arc<Field>>>;
|
||||
}
|
||||
@ -90,13 +91,13 @@ impl SortController {
|
||||
// #[tracing::instrument(name = "process_sort_task", level = "trace", skip_all, err)]
|
||||
pub async fn process(&mut self, predicate: &str) -> FlowyResult<()> {
|
||||
let event_type = SortEvent::from_str(predicate).unwrap();
|
||||
let mut rows = self.delegate.get_rows(&self.view_id).await;
|
||||
let mut row_details = self.delegate.get_rows(&self.view_id).await;
|
||||
match event_type {
|
||||
SortEvent::SortDidChanged | SortEvent::DeleteAllSorts => {
|
||||
self.sort_rows(&mut rows).await;
|
||||
let row_orders = rows
|
||||
self.sort_rows(&mut row_details).await;
|
||||
let row_orders = row_details
|
||||
.iter()
|
||||
.map(|row| row.id.to_string())
|
||||
.map(|row_detail| row_detail.row.id.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let notification = ReorderAllRowsResult {
|
||||
@ -112,7 +113,7 @@ impl SortController {
|
||||
},
|
||||
SortEvent::RowDidChanged(row_id) => {
|
||||
let old_row_index = self.row_index_cache.get(&row_id).cloned();
|
||||
self.sort_rows(&mut rows).await;
|
||||
self.sort_rows(&mut row_details).await;
|
||||
let new_row_index = self.row_index_cache.get(&row_id).cloned();
|
||||
match (old_row_index, new_row_index) {
|
||||
(Some(old_row_index), Some(new_row_index)) => {
|
||||
@ -150,17 +151,20 @@ impl SortController {
|
||||
self.task_scheduler.write().await.add_task(task);
|
||||
}
|
||||
|
||||
pub async fn sort_rows(&mut self, rows: &mut Vec<Arc<Row>>) {
|
||||
pub async fn sort_rows(&mut self, rows: &mut Vec<Arc<RowDetail>>) {
|
||||
if self.sorts.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let field_revs = self.delegate.get_fields(&self.view_id, None).await;
|
||||
let fields = self.delegate.get_fields(&self.view_id, None).await;
|
||||
for sort in self.sorts.iter() {
|
||||
rows.par_sort_by(|left, right| cmp_row(left, right, sort, &field_revs, &self.cell_cache));
|
||||
rows
|
||||
.par_sort_by(|left, right| cmp_row(&left.row, &right.row, sort, &fields, &self.cell_cache));
|
||||
}
|
||||
rows.iter().enumerate().for_each(|(index, row)| {
|
||||
self.row_index_cache.insert(row.id.clone(), index);
|
||||
rows.iter().enumerate().for_each(|(index, row_detail)| {
|
||||
self
|
||||
.row_index_cache
|
||||
.insert(row_detail.row.id.clone(), index);
|
||||
});
|
||||
}
|
||||
|
||||
@ -231,10 +235,10 @@ impl SortController {
|
||||
}
|
||||
|
||||
fn cmp_row(
|
||||
left: &Arc<Row>,
|
||||
right: &Arc<Row>,
|
||||
left: &Row,
|
||||
right: &Row,
|
||||
sort: &Arc<Sort>,
|
||||
field_revs: &[Arc<Field>],
|
||||
fields: &[Arc<Field>],
|
||||
cell_data_cache: &CellCache,
|
||||
) -> Ordering {
|
||||
let order = match (
|
||||
@ -243,7 +247,7 @@ fn cmp_row(
|
||||
) {
|
||||
(Some(left_cell), Some(right_cell)) => {
|
||||
let field_type = sort.field_type.clone();
|
||||
match field_revs
|
||||
match fields
|
||||
.iter()
|
||||
.find(|field_rev| field_rev.id == sort.field_id)
|
||||
{
|
||||
|
Reference in New Issue
Block a user