mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
refactor: updated at and created at (#2692)
* refactor: updated at and created at * chore: update patch ref * ci: fix tests
This commit is contained in:
parent
561d0f0808
commit
edd58ede45
@ -34,12 +34,12 @@ default = ["custom-protocol"]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
||||
[patch.crates-io]
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
|
||||
#collab = { path = "../../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../../AppFlowy-Collab/collab-folder" }
|
||||
|
20
frontend/rust-lib/Cargo.lock
generated
20
frontend/rust-lib/Cargo.lock
generated
@ -85,7 +85,7 @@ checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
|
||||
[[package]]
|
||||
name = "appflowy-integrate"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -887,7 +887,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -905,7 +905,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-client-ws"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab-sync",
|
||||
@ -923,7 +923,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -949,7 +949,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -961,7 +961,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -978,7 +978,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -997,7 +997,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -1017,7 +1017,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1047,7 +1047,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-sync"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=12e373#12e373f972d893d5f34b18794e77d3b49783ddcf"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=13b178#13b17802de31e75255b4303914042bdbb04361b2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab",
|
||||
|
@ -33,11 +33,11 @@ opt-level = 3
|
||||
incremental = false
|
||||
|
||||
[patch.crates-io]
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "12e373" }
|
||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "13b178" }
|
||||
|
||||
#collab = { path = "../AppFlowy-Collab/collab" }
|
||||
#collab-folder = { path = "../AppFlowy-Collab/collab-folder" }
|
||||
|
@ -496,17 +496,6 @@ pub enum FieldType {
|
||||
CreatedTime = 9,
|
||||
}
|
||||
|
||||
pub const RICH_TEXT_FIELD: FieldType = FieldType::RichText;
|
||||
pub const NUMBER_FIELD: FieldType = FieldType::Number;
|
||||
pub const DATE_FIELD: FieldType = FieldType::DateTime;
|
||||
pub const SINGLE_SELECT_FIELD: FieldType = FieldType::SingleSelect;
|
||||
pub const MULTI_SELECT_FIELD: FieldType = FieldType::MultiSelect;
|
||||
pub const CHECKBOX_FIELD: FieldType = FieldType::Checkbox;
|
||||
pub const URL_FIELD: FieldType = FieldType::URL;
|
||||
pub const CHECKLIST_FIELD: FieldType = FieldType::Checklist;
|
||||
pub const UPDATED_AT_FIELD: FieldType = FieldType::LastEditedTime;
|
||||
pub const CREATED_AT_FIELD: FieldType = FieldType::CreatedTime;
|
||||
|
||||
impl std::default::Default for FieldType {
|
||||
fn default() -> Self {
|
||||
FieldType::RichText
|
||||
@ -561,44 +550,58 @@ impl FieldType {
|
||||
}
|
||||
|
||||
pub fn is_number(&self) -> bool {
|
||||
self == &NUMBER_FIELD
|
||||
matches!(self, FieldType::Number)
|
||||
}
|
||||
|
||||
pub fn is_text(&self) -> bool {
|
||||
self == &RICH_TEXT_FIELD
|
||||
matches!(self, FieldType::RichText)
|
||||
}
|
||||
|
||||
pub fn is_checkbox(&self) -> bool {
|
||||
self == &CHECKBOX_FIELD
|
||||
matches!(self, FieldType::Checkbox)
|
||||
}
|
||||
|
||||
pub fn is_date(&self) -> bool {
|
||||
self == &DATE_FIELD || self == &UPDATED_AT_FIELD || self == &CREATED_AT_FIELD
|
||||
matches!(self, FieldType::DateTime)
|
||||
|| matches!(self, FieldType::LastEditedTime)
|
||||
|| matches!(self, FieldType::CreatedTime)
|
||||
}
|
||||
|
||||
pub fn is_single_select(&self) -> bool {
|
||||
self == &SINGLE_SELECT_FIELD
|
||||
matches!(self, FieldType::SingleSelect)
|
||||
}
|
||||
|
||||
pub fn is_multi_select(&self) -> bool {
|
||||
self == &MULTI_SELECT_FIELD
|
||||
matches!(self, FieldType::MultiSelect)
|
||||
}
|
||||
|
||||
pub fn is_last_edited_time(&self) -> bool {
|
||||
matches!(self, FieldType::LastEditedTime)
|
||||
}
|
||||
|
||||
pub fn is_created_time(&self) -> bool {
|
||||
matches!(self, FieldType::CreatedTime)
|
||||
}
|
||||
|
||||
pub fn is_url(&self) -> bool {
|
||||
self == &URL_FIELD
|
||||
matches!(self, FieldType::URL)
|
||||
}
|
||||
|
||||
pub fn is_select_option(&self) -> bool {
|
||||
self == &MULTI_SELECT_FIELD || self == &SINGLE_SELECT_FIELD
|
||||
self.is_single_select() || self.is_multi_select()
|
||||
}
|
||||
|
||||
pub fn is_checklist(&self) -> bool {
|
||||
self == &CHECKLIST_FIELD
|
||||
matches!(self, FieldType::Checklist)
|
||||
}
|
||||
|
||||
pub fn can_be_group(&self) -> bool {
|
||||
self.is_select_option() || self.is_checkbox() || self.is_url()
|
||||
}
|
||||
|
||||
pub fn is_auto_update(&self) -> bool {
|
||||
self.is_last_edited_time()
|
||||
}
|
||||
}
|
||||
|
||||
impl_into_field_type!(i64);
|
||||
|
@ -1,16 +1,15 @@
|
||||
use collab_database::database::gen_row_id;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::database::gen_row_id;
|
||||
use collab_database::rows::RowId;
|
||||
use lib_infra::util::timestamp;
|
||||
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult};
|
||||
use lib_infra::util::timestamp;
|
||||
|
||||
use crate::entities::*;
|
||||
use crate::manager::DatabaseManager2;
|
||||
use crate::services::cell::CellBuilder;
|
||||
|
||||
use crate::services::field::checklist_type_option::ChecklistCellChangeset;
|
||||
use crate::services::field::{
|
||||
type_option_data_from_pb_or_default, DateCellChangeset, SelectOptionCellChangeset,
|
||||
@ -373,8 +372,9 @@ pub(crate) async fn get_cell_handler(
|
||||
let params: CellIdParams = data.into_inner().try_into()?;
|
||||
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||
let cell = database_editor
|
||||
.get_cell(¶ms.field_id, params.row_id)
|
||||
.await;
|
||||
.get_cell_pb(¶ms.field_id, ¶ms.row_id)
|
||||
.await
|
||||
.unwrap_or_else(|| CellPB::empty(¶ms.field_id, params.row_id.into_inner()));
|
||||
data_result_ok(cell)
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ use std::fmt::Debug;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{get_field_type_from_cell, Cell, Cells};
|
||||
use lib_infra::util::timestamp;
|
||||
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
|
||||
@ -298,11 +297,6 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl std::convert::From<String> for AnyCellChangeset<String> {
|
||||
// fn from(s: String) -> Self {
|
||||
// AnyCellChangeset(Some(s))
|
||||
// }
|
||||
// }
|
||||
|
||||
pub struct CellBuilder<'a> {
|
||||
cells: Cells,
|
||||
@ -330,11 +324,14 @@ impl<'a> CellBuilder<'a> {
|
||||
cells.insert(field_id, insert_number_cell(num, field));
|
||||
}
|
||||
},
|
||||
FieldType::DateTime | FieldType::LastEditedTime | FieldType::CreatedTime => {
|
||||
FieldType::DateTime => {
|
||||
if let Ok(timestamp) = cell_str.parse::<i64>() {
|
||||
cells.insert(field_id, insert_date_cell(timestamp, Some(false), field));
|
||||
}
|
||||
},
|
||||
FieldType::LastEditedTime | FieldType::CreatedTime => {
|
||||
tracing::warn!("Shouldn't insert cell data to cell whose field type is LastEditedTime or CreatedTime");
|
||||
},
|
||||
FieldType::SingleSelect | FieldType::MultiSelect => {
|
||||
if let Ok(ids) = SelectOptionIds::from_cell_str(&cell_str) {
|
||||
cells.insert(field_id, insert_select_option_cell(ids.into_inner(), field));
|
||||
@ -357,19 +354,6 @@ impl<'a> CellBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto insert the cell data if the field is not in the cell_by_field_id.
|
||||
// Currently, the auto fill field type is `UpdatedAt` or `CreatedAt`.
|
||||
for field in fields {
|
||||
if !cell_by_field_id.contains_key(&field.id) {
|
||||
let field_type = FieldType::from(field.field_type);
|
||||
if field_type == FieldType::LastEditedTime || field_type == FieldType::CreatedTime {
|
||||
cells.insert(
|
||||
field.id.clone(),
|
||||
insert_date_cell(timestamp(), Some(true), field),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
CellBuilder { cells, field_maps }
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytes::Bytes;
|
||||
use collab_database::database::{timestamp, Database as InnerDatabase};
|
||||
use collab_database::database::Database as InnerDatabase;
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{Cell, Cells, CreateRowParams, Row, RowCell, RowId};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting};
|
||||
@ -24,22 +24,20 @@ use crate::entities::{
|
||||
};
|
||||
use crate::notification::{send_notification, DatabaseNotification};
|
||||
use crate::services::cell::{
|
||||
apply_cell_changeset, get_cell_protobuf, insert_date_cell, AnyTypeCache, CellCache,
|
||||
ToCellChangeset,
|
||||
apply_cell_changeset, get_cell_protobuf, AnyTypeCache, CellCache, ToCellChangeset,
|
||||
};
|
||||
use crate::services::database::util::database_view_setting_pb_from_view;
|
||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewData, DatabaseViews};
|
||||
use crate::services::field::checklist_type_option::{ChecklistCellChangeset, ChecklistCellData};
|
||||
use crate::services::field::{
|
||||
default_type_option_data_from_type, select_type_option_from_field, transform_type_option,
|
||||
type_option_data_from_pb_or_default, type_option_to_pb, SelectOptionCellChangeset,
|
||||
type_option_data_from_pb_or_default, type_option_to_pb, DateCellData, SelectOptionCellChangeset,
|
||||
SelectOptionIds, TypeOptionCellDataHandler, TypeOptionCellExt,
|
||||
};
|
||||
use crate::services::filter::Filter;
|
||||
use crate::services::group::{
|
||||
default_group_setting, GroupSetting, GroupSettingChangeset, RowChangeset,
|
||||
};
|
||||
|
||||
use crate::services::share::csv::{CSVExport, CSVFormat};
|
||||
use crate::services::sort::Sort;
|
||||
|
||||
@ -451,31 +449,84 @@ impl DatabaseEditor {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_cell(&self, field_id: &str, row_id: RowId) -> CellPB {
|
||||
let (field, cell) = {
|
||||
let database = self.database.lock();
|
||||
let field = database.fields.get_field(field_id);
|
||||
let cell = database.get_cell(field_id, &row_id).cell;
|
||||
(field, cell)
|
||||
};
|
||||
|
||||
match (field, cell) {
|
||||
(Some(field), Some(cell)) => {
|
||||
let field_type = FieldType::from(field.field_type);
|
||||
let cell_bytes = get_cell_protobuf(&cell, &field, Some(self.cell_cache.clone()));
|
||||
CellPB {
|
||||
field_id: field_id.to_string(),
|
||||
row_id: row_id.into(),
|
||||
data: cell_bytes.to_vec(),
|
||||
field_type: Some(field_type),
|
||||
}
|
||||
},
|
||||
_ => CellPB::empty(field_id, row_id.into_inner()),
|
||||
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)?;
|
||||
let field_type = FieldType::from(field.field_type);
|
||||
// If the cell data is referenced, return the reference data. Otherwise, return an empty cell.
|
||||
match field_type {
|
||||
FieldType::LastEditedTime | FieldType::CreatedTime => database
|
||||
.get_row(row_id)
|
||||
.map(|row| {
|
||||
if field_type.is_created_time() {
|
||||
DateCellData::new(row.created_at, true)
|
||||
} else {
|
||||
DateCellData::new(row.modified_at, true)
|
||||
}
|
||||
})
|
||||
.map(Cell::from),
|
||||
_ => database.get_cell(field_id, row_id).cell,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_cell_pb(&self, field_id: &str, row_id: &RowId) -> Option<CellPB> {
|
||||
let (field, cell) = {
|
||||
let database = self.database.lock();
|
||||
let field = database.fields.get_field(field_id)?;
|
||||
let field_type = FieldType::from(field.field_type);
|
||||
// If the cell data is referenced, return the reference data. Otherwise, return an empty cell.
|
||||
let cell = match field_type {
|
||||
FieldType::LastEditedTime | FieldType::CreatedTime => database
|
||||
.get_row(row_id)
|
||||
.map(|row| {
|
||||
if field_type.is_created_time() {
|
||||
DateCellData::new(row.created_at, true)
|
||||
} else {
|
||||
DateCellData::new(row.modified_at, true)
|
||||
}
|
||||
})
|
||||
.map(Cell::from),
|
||||
_ => database.get_cell(field_id, row_id).cell,
|
||||
}?;
|
||||
|
||||
(field, cell)
|
||||
};
|
||||
|
||||
let field_type = FieldType::from(field.field_type);
|
||||
let cell_bytes = get_cell_protobuf(&cell, &field, Some(self.cell_cache.clone()));
|
||||
Some(CellPB {
|
||||
field_id: field_id.to_string(),
|
||||
row_id: row_id.clone().into(),
|
||||
data: cell_bytes.to_vec(),
|
||||
field_type: Some(field_type),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_cells_for_field(&self, view_id: &str, field_id: &str) -> Vec<RowCell> {
|
||||
self.database.lock().get_cells_for_field(view_id, field_id)
|
||||
let database = self.database.lock();
|
||||
if let Some(field) = database.fields.get_field(field_id) {
|
||||
let field_type = FieldType::from(field.field_type);
|
||||
match field_type {
|
||||
FieldType::LastEditedTime | FieldType::CreatedTime => database
|
||||
.get_rows_for_view(view_id)
|
||||
.into_iter()
|
||||
.map(|row| {
|
||||
let data = if field_type.is_created_time() {
|
||||
DateCellData::new(row.created_at, true)
|
||||
} else {
|
||||
DateCellData::new(row.modified_at, true)
|
||||
};
|
||||
RowCell {
|
||||
row_id: row.id,
|
||||
cell: Some(Cell::from(data)),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
_ => database.get_cells_for_field(view_id, field_id),
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_cell_with_changeset<T>(
|
||||
@ -516,22 +567,13 @@ impl DatabaseEditor {
|
||||
// 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) };
|
||||
|
||||
// Get all the updated_at fields. We will update all of them.
|
||||
let updated_at_fields = self
|
||||
.database
|
||||
.lock()
|
||||
.get_fields(view_id, None)
|
||||
.into_iter()
|
||||
.filter(|f| FieldType::from(f.field_type) == FieldType::LastEditedTime)
|
||||
.collect::<Vec<Field>>();
|
||||
// Get all auto updated fields. It will be used to notify the frontend
|
||||
// that the fields have been updated.
|
||||
let auto_updated_fields = self.get_auto_updated_fields(view_id);
|
||||
|
||||
self.database.lock().update_row(&row_id, |row_update| {
|
||||
row_update.update_cells(|cell_update| {
|
||||
let mut cells_update = cell_update.insert(field_id, new_cell);
|
||||
for field in &updated_at_fields {
|
||||
cells_update =
|
||||
cells_update.insert(&field.id, insert_date_cell(timestamp(), Some(true), field));
|
||||
}
|
||||
cell_update.insert(field_id, new_cell);
|
||||
});
|
||||
});
|
||||
|
||||
@ -552,12 +594,12 @@ impl DatabaseEditor {
|
||||
}
|
||||
|
||||
// Collect all the updated field's id. Notify the frontend that all of them have been updated.
|
||||
let mut updated_field_ids = updated_at_fields
|
||||
let mut auto_updated_field_ids = auto_updated_fields
|
||||
.into_iter()
|
||||
.map(|field| field.id)
|
||||
.collect::<Vec<String>>();
|
||||
updated_field_ids.push(field_id.to_string());
|
||||
let changeset = updated_field_ids
|
||||
auto_updated_field_ids.push(field_id.to_string());
|
||||
let changeset = auto_updated_field_ids
|
||||
.into_iter()
|
||||
.map(|field_id| CellChangesetNotifyPB {
|
||||
view_id: view_id.to_string(),
|
||||
@ -884,7 +926,7 @@ impl DatabaseEditor {
|
||||
let view = database_view
|
||||
.get_view()
|
||||
.await
|
||||
.ok_or(FlowyError::record_not_found())?;
|
||||
.ok_or_else(|| FlowyError::record_not_found())?;
|
||||
let rows = database_view.v_get_rows().await;
|
||||
let (database_id, fields) = {
|
||||
let database = self.database.lock();
|
||||
@ -921,6 +963,16 @@ impl DatabaseEditor {
|
||||
.map_err(internal_error)??;
|
||||
Ok(csv)
|
||||
}
|
||||
|
||||
fn get_auto_updated_fields(&self, view_id: &str) -> Vec<Field> {
|
||||
self
|
||||
.database
|
||||
.lock()
|
||||
.get_fields(view_id, None)
|
||||
.into_iter()
|
||||
.filter(|f| FieldType::from(f.field_type).is_auto_update())
|
||||
.collect::<Vec<Field>>()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn notify_did_update_cell(changesets: Vec<CellChangesetNotifyPB>) {
|
||||
|
@ -1,3 +1,5 @@
|
||||
use collab_database::views::DatabaseView;
|
||||
|
||||
use crate::entities::{
|
||||
CalendarLayoutSettingPB, DatabaseLayoutPB, DatabaseLayoutSettingPB, DatabaseViewSettingPB,
|
||||
FilterPB, GroupSettingPB, SortPB,
|
||||
@ -6,10 +8,9 @@ use crate::services::filter::Filter;
|
||||
use crate::services::group::GroupSetting;
|
||||
use crate::services::setting::CalendarLayoutSetting;
|
||||
use crate::services::sort::Sort;
|
||||
use collab_database::views::DatabaseView;
|
||||
|
||||
pub(crate) fn database_view_setting_pb_from_view(view: DatabaseView) -> DatabaseViewSettingPB {
|
||||
let layout_type: DatabaseLayoutPB = view.layout.clone().into();
|
||||
let layout_type: DatabaseLayoutPB = view.layout.into();
|
||||
let layout_setting = if let Some(layout_setting) = view.layout_settings.get(&view.layout) {
|
||||
let calendar_setting =
|
||||
CalendarLayoutSettingPB::from(CalendarLayoutSetting::from(layout_setting.clone()));
|
||||
|
@ -52,6 +52,15 @@ pub struct DateCellData {
|
||||
pub include_time: bool,
|
||||
}
|
||||
|
||||
impl DateCellData {
|
||||
pub fn new(timestamp: i64, include_time: bool) -> Self {
|
||||
Self {
|
||||
timestamp: Some(timestamp),
|
||||
include_time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Cell> for DateCellData {
|
||||
fn from(cell: &Cell) -> Self {
|
||||
let timestamp = cell
|
||||
|
@ -16,8 +16,8 @@ use crate::entities::{
|
||||
use crate::services::cell::{CellDataDecoder, FromCellChangeset, ToCellChangeset};
|
||||
use crate::services::field::checklist_type_option::ChecklistTypeOption;
|
||||
use crate::services::field::{
|
||||
CheckboxTypeOption, DateTypeOption, MultiSelectTypeOption, NumberTypeOption, RichTextTypeOption,
|
||||
SingleSelectTypeOption, URLTypeOption,
|
||||
CheckboxTypeOption, DateFormat, DateTypeOption, MultiSelectTypeOption, NumberTypeOption,
|
||||
RichTextTypeOption, SingleSelectTypeOption, TimeFormat, URLTypeOption,
|
||||
};
|
||||
use crate::services::filter::FromFilterString;
|
||||
|
||||
@ -220,11 +220,18 @@ pub fn default_type_option_data_from_type(field_type: &FieldType) -> TypeOptionD
|
||||
match field_type {
|
||||
FieldType::RichText => RichTextTypeOption::default().into(),
|
||||
FieldType::Number => NumberTypeOption::default().into(),
|
||||
FieldType::DateTime | FieldType::LastEditedTime | FieldType::CreatedTime => DateTypeOption {
|
||||
FieldType::DateTime => DateTypeOption {
|
||||
field_type: field_type.clone(),
|
||||
..Default::default()
|
||||
}
|
||||
.into(),
|
||||
FieldType::LastEditedTime | FieldType::CreatedTime => DateTypeOption {
|
||||
field_type: field_type.clone(),
|
||||
date_format: DateFormat::Friendly,
|
||||
time_format: TimeFormat::TwelveHour,
|
||||
..Default::default()
|
||||
}
|
||||
.into(),
|
||||
FieldType::SingleSelect => SingleSelectTypeOption::default().into(),
|
||||
FieldType::MultiSelect => MultiSelectTypeOption::default().into(),
|
||||
FieldType::Checkbox => CheckboxTypeOption::default().into(),
|
||||
|
@ -1,9 +1,12 @@
|
||||
use crate::database::block_test::script::DatabaseRowTest;
|
||||
use crate::database::block_test::script::RowScript::*;
|
||||
use std::time::Duration;
|
||||
|
||||
use flowy_database2::entities::FieldType;
|
||||
use flowy_database2::services::field::DateCellData;
|
||||
use lib_infra::util::timestamp;
|
||||
|
||||
use crate::database::block_test::script::DatabaseRowTest;
|
||||
use crate::database::block_test::script::RowScript::*;
|
||||
|
||||
// Create a new row at the end of the grid and check the create time is valid.
|
||||
#[tokio::test]
|
||||
async fn created_at_field_test() {
|
||||
@ -16,11 +19,15 @@ async fn created_at_field_test() {
|
||||
// Get created time of the new row.
|
||||
let row = test.get_rows().await.last().cloned().unwrap();
|
||||
let updated_at_field = test.get_first_field(FieldType::CreatedTime);
|
||||
let cell = row.cells.cell_for_field_id(&updated_at_field.id).unwrap();
|
||||
let created_at_timestamp = DateCellData::from(cell).timestamp.unwrap();
|
||||
let cell = test
|
||||
.editor
|
||||
.get_cell(&updated_at_field.id, &row.id)
|
||||
.await
|
||||
.unwrap();
|
||||
let created_at_timestamp = DateCellData::from(&cell).timestamp.unwrap();
|
||||
|
||||
assert!(created_at_timestamp > 0);
|
||||
assert!(created_at_timestamp < timestamp());
|
||||
assert!(created_at_timestamp <= timestamp());
|
||||
}
|
||||
|
||||
// Update row and check the update time is valid.
|
||||
@ -28,10 +35,15 @@ async fn created_at_field_test() {
|
||||
async fn update_at_field_test() {
|
||||
let mut test = DatabaseRowTest::new().await;
|
||||
let row = test.get_rows().await.remove(0);
|
||||
let updated_at_field = test.get_first_field(FieldType::LastEditedTime);
|
||||
let cell = row.cells.cell_for_field_id(&updated_at_field.id).unwrap();
|
||||
let old_updated_at = DateCellData::from(cell).timestamp.unwrap();
|
||||
let last_edit_field = test.get_first_field(FieldType::LastEditedTime);
|
||||
let cell = test
|
||||
.editor
|
||||
.get_cell(&last_edit_field.id, &row.id)
|
||||
.await
|
||||
.unwrap();
|
||||
let old_updated_at = DateCellData::from(&cell).timestamp.unwrap();
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
test
|
||||
.run_script(UpdateTextCell {
|
||||
row_id: row.id.clone(),
|
||||
@ -41,9 +53,12 @@ async fn update_at_field_test() {
|
||||
|
||||
// Get the updated time of the row.
|
||||
let row = test.get_rows().await.remove(0);
|
||||
let updated_at_field = test.get_first_field(FieldType::LastEditedTime);
|
||||
let cell = row.cells.cell_for_field_id(&updated_at_field.id).unwrap();
|
||||
let new_updated_at = DateCellData::from(cell).timestamp.unwrap();
|
||||
|
||||
let last_edit_field = test.get_first_field(FieldType::LastEditedTime);
|
||||
let cell = test
|
||||
.editor
|
||||
.get_cell(&last_edit_field.id, &row.id)
|
||||
.await
|
||||
.unwrap();
|
||||
let new_updated_at = DateCellData::from(&cell).timestamp.unwrap();
|
||||
assert!(old_updated_at < new_updated_at);
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use flowy_database2::entities::{CellChangesetPB, FieldType};
|
||||
use flowy_database2::services::cell::ToCellChangeset;
|
||||
use flowy_database2::services::field::checklist_type_option::ChecklistCellChangeset;
|
||||
@ -130,12 +132,14 @@ async fn update_updated_at_field_on_other_cell_update() {
|
||||
is_err: false,
|
||||
})
|
||||
.await;
|
||||
let after_update_timestamp = chrono::offset::Utc::now().timestamp();
|
||||
|
||||
let cells = test
|
||||
.editor
|
||||
.get_cells_for_field(&test.view_id, &updated_at_field.id)
|
||||
.await;
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
let after_update_timestamp = chrono::offset::Utc::now().timestamp();
|
||||
assert!(!cells.is_empty());
|
||||
for (i, row_cell) in cells.into_iter().enumerate() {
|
||||
let timestamp = DateCellData::from(row_cell.cell.as_ref().unwrap())
|
||||
|
@ -1,7 +1,7 @@
|
||||
use collab_database::database::gen_database_view_id;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::database::{gen_database_view_id, timestamp};
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{CreateRowParams, Row, RowId};
|
||||
use strum::EnumCount;
|
||||
@ -418,7 +418,7 @@ impl<'a> TestRowBuilder<'a> {
|
||||
height: 60,
|
||||
visibility: true,
|
||||
prev_row_id: None,
|
||||
timestamp: 0,
|
||||
timestamp: timestamp(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use std::{collections::HashMap, vec};
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
use indexmap::IndexMap;
|
||||
use nanoid::nanoid;
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::{BlockPB, ChildrenPB, DocumentDataPB, MetaPB};
|
||||
|
||||
use super::block::Block;
|
||||
@ -69,12 +70,12 @@ impl JsonToDocumentParser {
|
||||
}
|
||||
|
||||
fn block_to_block_pb(block: &Block, id: Option<String>, parent_id: String) -> BlockPB {
|
||||
let id = id.unwrap_or(nanoid!(10));
|
||||
let id = id.unwrap_or_else(|| nanoid!(10));
|
||||
BlockPB {
|
||||
id: id.clone(),
|
||||
id,
|
||||
ty: block.ty.clone(),
|
||||
data: serde_json::to_string(&block.data).unwrap(),
|
||||
parent_id: parent_id.clone(),
|
||||
parent_id,
|
||||
children_id: nanoid!(10),
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
use collab_folder::core::{FolderData, RepeatedView, ViewIdentifier, Workspace};
|
||||
use lib_infra::util::timestamp;
|
||||
use nanoid::nanoid;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_folder::core::{FolderData, RepeatedView, ViewIdentifier, Workspace};
|
||||
use nanoid::nanoid;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use lib_infra::util::timestamp;
|
||||
|
||||
use crate::entities::{view_pb_with_child_views, ViewPB, WorkspacePB};
|
||||
use crate::view_operation::{
|
||||
FlattedViews, FolderOperationHandlers, ParentChildViews, WorkspaceViewBuilder,
|
||||
@ -49,10 +51,7 @@ impl DefaultFolderBuilder {
|
||||
created_at: timestamp(),
|
||||
};
|
||||
|
||||
let first_level_view_pbs = views
|
||||
.iter()
|
||||
.map(|value| ViewPB::from(value))
|
||||
.collect::<Vec<_>>();
|
||||
let first_level_view_pbs = views.iter().map(ViewPB::from).collect::<Vec<_>>();
|
||||
|
||||
let workspace_pb = WorkspacePB {
|
||||
id: workspace.id.clone(),
|
||||
|
Loading…
Reference in New Issue
Block a user