feat: created at and updated at field type (#2572)

* feat: created at and updated at field type

* style: context for rust asserts, change checks in flutter

* fix: mistake in if condition

* style: add comma end of array

* feat: created at and updated at field type

* fix: typo in const variable

* style: cargo fmt

* refactor: opti cell insert

* chore: remove redundant clone

* refactor: date type option

* fix: tauri build

---------

Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
Mohammad Zolfaghari
2023-05-26 14:04:17 +03:30
committed by GitHub
parent a85cc62a58
commit 9a213fa562
43 changed files with 598 additions and 188 deletions

View File

@ -492,6 +492,8 @@ pub enum FieldType {
Checkbox = 5,
URL = 6,
Checklist = 7,
UpdatedAt = 8,
CreatedAt = 9,
}
pub const RICH_TEXT_FIELD: FieldType = FieldType::RichText;
@ -502,6 +504,8 @@ 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::UpdatedAt;
pub const CREATED_AT_FIELD: FieldType = FieldType::CreatedAt;
impl std::default::Default for FieldType {
fn default() -> Self {
@ -529,9 +533,13 @@ impl From<&FieldType> for FieldType {
}
impl FieldType {
pub fn value(&self) -> i64 {
self.clone().into()
}
pub fn default_cell_width(&self) -> i32 {
match self {
FieldType::DateTime => 180,
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => 180,
_ => 150,
}
}
@ -546,6 +554,8 @@ impl FieldType {
FieldType::Checkbox => "Checkbox",
FieldType::URL => "URL",
FieldType::Checklist => "Checklist",
FieldType::UpdatedAt => "Updated At",
FieldType::CreatedAt => "Created At",
};
s.to_string()
}
@ -563,7 +573,7 @@ impl FieldType {
}
pub fn is_date(&self) -> bool {
self == &DATE_FIELD
self == &DATE_FIELD || self == &UPDATED_AT_FIELD || self == &CREATED_AT_FIELD
}
pub fn is_single_select(&self) -> bool {
@ -605,6 +615,8 @@ impl From<FieldType> for i64 {
FieldType::Checkbox => 5,
FieldType::URL => 6,
FieldType::Checklist => 7,
FieldType::UpdatedAt => 8,
FieldType::CreatedAt => 9,
}
}
}

View File

@ -35,7 +35,9 @@ impl std::convert::From<&Filter> for FilterPB {
let bytes: Bytes = match filter.field_type {
FieldType::RichText => TextFilterPB::from(filter).try_into().unwrap(),
FieldType::Number => NumberFilterPB::from(filter).try_into().unwrap(),
FieldType::DateTime => DateFilterPB::from(filter).try_into().unwrap(),
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
DateFilterPB::from(filter).try_into().unwrap()
},
FieldType::SingleSelect => SelectOptionFilterPB::from(filter).try_into().unwrap(),
FieldType::MultiSelect => SelectOptionFilterPB::from(filter).try_into().unwrap(),
FieldType::Checklist => ChecklistFilterPB::from(filter).try_into().unwrap(),
@ -198,7 +200,7 @@ impl TryInto<AlterFilterParams> for AlterFilterPayloadPB {
condition = filter.condition as u8;
content = filter.content;
},
FieldType::DateTime => {
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
let filter = DateFilterPB::try_from(bytes).map_err(|_| ErrorCode::ProtobufSerde)?;
condition = filter.condition as u8;
content = DateFilterContentPB {

View File

@ -12,6 +12,8 @@ macro_rules! impl_into_field_type {
5 => FieldType::Checkbox,
6 => FieldType::URL,
7 => FieldType::Checklist,
8 => FieldType::UpdatedAt,
9 => FieldType::CreatedAt,
_ => {
tracing::error!("Can't parser FieldType from value: {}", ty);
FieldType::RichText

View File

@ -4,7 +4,7 @@ use strum_macros::EnumIter;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use crate::entities::CellIdPB;
use crate::entities::{CellIdPB, FieldType};
use crate::services::field::{DateFormat, DateTypeOption, TimeFormat};
#[derive(Clone, Debug, Default, ProtoBuf)]
@ -51,6 +51,9 @@ pub struct DateTypeOptionPB {
#[pb(index = 2)]
pub time_format: TimeFormatPB,
#[pb(index = 3)]
pub field_type: FieldType,
}
impl From<DateTypeOption> for DateTypeOptionPB {
@ -58,6 +61,7 @@ impl From<DateTypeOption> for DateTypeOptionPB {
Self {
date_format: data.date_format.into(),
time_format: data.time_format.into(),
field_type: data.field_type,
}
}
}
@ -67,6 +71,7 @@ impl From<DateTypeOptionPB> for DateTypeOption {
Self {
date_format: data.date_format.into(),
time_format: data.time_format.into(),
field_type: data.field_type,
}
}
}

View File

@ -3,6 +3,7 @@ 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};
@ -205,11 +206,11 @@ pub fn insert_checkbox_cell(is_check: bool, field: &Field) -> Cell {
apply_cell_changeset(s, None, field, None).unwrap()
}
pub fn insert_date_cell(timestamp: i64, field: &Field) -> Cell {
pub fn insert_date_cell(timestamp: i64, include_time: Option<bool>, field: &Field) -> Cell {
let cell_data = serde_json::to_string(&DateCellChangeset {
date: Some(timestamp.to_string()),
time: None,
include_time: Some(false),
include_time,
timezone_id: None,
})
.unwrap();
@ -299,6 +300,7 @@ pub struct CellBuilder<'a> {
}
impl<'a> CellBuilder<'a> {
/// Build list of Cells from HashMap of cell string by field id.
pub fn with_cells(cell_by_field_id: HashMap<String, String>, fields: &'a [Field]) -> Self {
let field_maps = fields
.into_iter()
@ -306,7 +308,7 @@ impl<'a> CellBuilder<'a> {
.collect::<HashMap<String, &Field>>();
let mut cells = Cells::new();
for (field_id, cell_str) in cell_by_field_id {
for (field_id, cell_str) in cell_by_field_id.clone() {
if let Some(field) = field_maps.get(&field_id) {
let field_type = FieldType::from(field.field_type);
match field_type {
@ -318,9 +320,9 @@ impl<'a> CellBuilder<'a> {
cells.insert(field_id, insert_number_cell(num, field));
}
},
FieldType::DateTime => {
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
if let Ok(timestamp) = cell_str.parse::<i64>() {
cells.insert(field_id, insert_date_cell(timestamp, field));
cells.insert(field_id, insert_date_cell(timestamp, Some(false), field));
}
},
FieldType::SingleSelect | FieldType::MultiSelect => {
@ -345,6 +347,19 @@ 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::UpdatedAt || field_type == FieldType::CreatedAt {
cells.insert(
field.id.clone(),
insert_date_cell(timestamp(), Some(true), field),
);
}
}
}
CellBuilder { cells, field_maps }
}
@ -400,9 +415,10 @@ impl<'a> CellBuilder<'a> {
match self.field_maps.get(&field_id.to_owned()) {
None => tracing::warn!("Can't find the date field with id: {}", field_id),
Some(field) => {
self
.cells
.insert(field_id.to_owned(), insert_date_cell(timestamp, field));
self.cells.insert(
field_id.to_owned(),
insert_date_cell(timestamp, Some(false), field),
);
},
}
}

View File

@ -82,6 +82,8 @@ impl TypeCellData {
pub fn is_date(&self) -> bool {
self.field_type == FieldType::DateTime
|| self.field_type == FieldType::UpdatedAt
|| self.field_type == FieldType::CreatedAt
}
pub fn is_single_select(&self) -> bool {

View File

@ -23,15 +23,15 @@ use crate::entities::{
};
use crate::notification::{send_notification, DatabaseNotification};
use crate::services::cell::{
apply_cell_changeset, get_cell_protobuf, AnyTypeCache, CellBuilder, CellCache, ToCellChangeset,
apply_cell_changeset, get_cell_protobuf, insert_date_cell, AnyTypeCache, CellBuilder, 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::{
default_type_option_data_for_type, 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, SelectOptionIds, TypeOptionCellDataHandler,
TypeOptionCellExt,
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,
SelectOptionIds, TypeOptionCellDataHandler, TypeOptionCellExt,
};
use crate::services::filter::Filter;
use crate::services::group::{default_group_setting, GroupSetting, RowChangeset};
@ -237,7 +237,7 @@ impl DatabaseEditor {
let old_type_option = field.get_any_type_option(old_field_type.clone());
let new_type_option = field
.get_any_type_option(new_field_type)
.unwrap_or_else(|| default_type_option_data_for_type(new_field_type));
.unwrap_or_else(|| default_type_option_data_from_type(new_field_type));
let transformed_type_option = transform_type_option(
&new_type_option,
@ -352,7 +352,7 @@ impl DatabaseEditor {
) -> (Field, Bytes) {
let name = field_type.default_name();
let type_option_data = match type_option_data {
None => default_type_option_data_for_type(field_type),
None => default_type_option_data_from_type(field_type),
Some(type_option_data) => type_option_data_from_pb_or_default(type_option_data, field_type),
};
let (index, field) =
@ -492,9 +492,23 @@ impl DatabaseEditor {
) -> 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) };
// 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::UpdatedAt)
.collect::<Vec<Field>>();
self.database.lock().update_row(&row_id, |row_update| {
row_update.update_cells(|cell_update| {
cell_update.insert(field_id, new_cell);
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));
}
});
});
@ -505,12 +519,22 @@ impl DatabaseEditor {
}
}
notify_did_update_cell(vec![CellChangesetNotifyPB {
view_id: view_id.to_string(),
row_id: row_id.into_inner(),
field_id: field_id.to_string(),
}])
.await;
// 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
.into_iter()
.map(|field| field.id)
.collect::<Vec<String>>();
updated_field_ids.push(field_id.to_string());
let changeset = updated_field_ids
.into_iter()
.map(|field_id| CellChangesetNotifyPB {
view_id: view_id.to_string(),
row_id: row_id.clone().into_inner(),
field_id,
})
.collect();
notify_did_update_cell(changeset).await;
Ok(())
}

View File

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

View File

@ -1,16 +0,0 @@
use crate::entities::FieldType;
use crate::services::field::type_options::*;
use collab_database::fields::TypeOptionData;
pub fn default_type_option_data_from_type(field_type: &FieldType) -> TypeOptionData {
match field_type {
FieldType::RichText => RichTextTypeOption::default().into(),
FieldType::Number => NumberTypeOption::default().into(),
FieldType::DateTime => DateTypeOption::default().into(),
FieldType::SingleSelect => SingleSelectTypeOption::default().into(),
FieldType::MultiSelect => MultiSelectTypeOption::default().into(),
FieldType::Checkbox => CheckboxTypeOption::default().into(),
FieldType::URL => URLTypeOption::default().into(),
FieldType::Checklist => ChecklistTypeOption::default().into(),
}
}

View File

@ -14,7 +14,7 @@ mod tests {
#[test]
fn date_type_option_date_format_test() {
let mut type_option = DateTypeOption::default();
let mut type_option = DateTypeOption::new(FieldType::DateTime);
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
for date_format in DateFormat::iter() {
type_option.date_format = date_format;
@ -95,7 +95,7 @@ mod tests {
#[test]
fn date_type_option_different_time_format_test() {
let mut type_option = DateTypeOption::default();
let mut type_option = DateTypeOption::new(FieldType::DateTime);
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
for time_format in TimeFormat::iter() {
@ -183,8 +183,8 @@ mod tests {
#[test]
fn date_type_option_invalid_date_str_test() {
let type_option = DateTypeOption::default();
let field_type = FieldType::DateTime;
let type_option = DateTypeOption::new(field_type.clone());
let field = FieldBuilder::from_field_type(field_type).build();
assert_date(
&type_option,
@ -203,8 +203,9 @@ mod tests {
#[test]
#[should_panic]
fn date_type_option_invalid_include_time_str_test() {
let type_option = DateTypeOption::new();
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
let field_type = FieldType::DateTime;
let type_option = DateTypeOption::new(field_type.clone());
let field = FieldBuilder::from_field_type(field_type).build();
assert_date(
&type_option,
@ -223,8 +224,9 @@ mod tests {
#[test]
#[should_panic]
fn date_type_option_empty_include_time_str_test() {
let type_option = DateTypeOption::new();
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
let field_type = FieldType::DateTime;
let type_option = DateTypeOption::new(field_type.clone());
let field = FieldBuilder::from_field_type(field_type).build();
assert_date(
&type_option,
@ -242,8 +244,8 @@ mod tests {
#[test]
fn date_type_midnight_include_time_str_test() {
let type_option = DateTypeOption::new();
let field_type = FieldType::DateTime;
let type_option = DateTypeOption::new(field_type.clone());
let field = FieldBuilder::from_field_type(field_type).build();
assert_date(
&type_option,
@ -264,7 +266,7 @@ mod tests {
#[test]
#[should_panic]
fn date_type_option_twelve_hours_include_time_str_in_twenty_four_hours_format() {
let type_option = DateTypeOption::new();
let type_option = DateTypeOption::new(FieldType::DateTime);
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
assert_date(
&type_option,
@ -285,9 +287,10 @@ mod tests {
#[test]
#[should_panic]
fn date_type_option_twenty_four_hours_include_time_str_in_twelve_hours_format() {
let mut type_option = DateTypeOption::new();
let field_type = FieldType::DateTime;
let mut type_option = DateTypeOption::new(field_type.clone());
type_option.time_format = TimeFormat::TwelveHour;
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
let field = FieldBuilder::from_field_type(field_type).build();
assert_date(
&type_option,
@ -335,7 +338,7 @@ mod tests {
#[test]
#[should_panic]
fn update_date_keep_time() {
let type_option = DateTypeOption::new();
let type_option = DateTypeOption::new(FieldType::DateTime);
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
let old_cell_data = initialize_date_cell(
@ -363,7 +366,7 @@ mod tests {
#[test]
fn update_time_keep_date() {
let type_option = DateTypeOption::new();
let type_option = DateTypeOption::new(FieldType::DateTime);
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
let old_cell_data = initialize_date_cell(
@ -391,7 +394,7 @@ mod tests {
#[test]
fn timezone_no_daylight_saving_time() {
let type_option = DateTypeOption::new();
let type_option = DateTypeOption::new(FieldType::DateTime);
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
assert_date(
@ -422,7 +425,7 @@ mod tests {
#[test]
fn timezone_with_daylight_saving_time() {
let type_option = DateTypeOption::new();
let type_option = DateTypeOption::new(FieldType::DateTime);
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
assert_date(
@ -453,7 +456,7 @@ mod tests {
#[test]
fn change_timezone() {
let type_option = DateTypeOption::new();
let type_option = DateTypeOption::new(FieldType::DateTime);
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
let old_cell_data = initialize_date_cell(

View File

@ -1,8 +1,9 @@
use crate::entities::{DateCellDataPB, DateFilterPB, FieldType};
use crate::services::cell::{CellDataChangeset, CellDataDecoder};
use crate::services::field::{
default_order, DateCellChangeset, DateCellData, DateFormat, TimeFormat, TypeOption,
TypeOptionCellData, TypeOptionCellDataCompare, TypeOptionCellDataFilter, TypeOptionTransform,
default_order, DateCellChangeset, DateCellData, DateCellDataWrapper, DateFormat, TimeFormat,
TypeOption, TypeOptionCellData, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
TypeOptionTransform,
};
use chrono::format::strftime::StrftimeItems;
use chrono::{DateTime, Local, NaiveDateTime, NaiveTime, Offset, TimeZone};
@ -15,11 +16,14 @@ use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::str::FromStr;
// Date
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
/// The [DateTypeOption] is used by [FieldType::Date], [FieldType::UpdatedAt], and [FieldType::CreatedAt].
/// So, storing the field type is necessary to distinguish the field type.
/// Most of the cases, each [FieldType] has its own [TypeOption] implementation.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DateTypeOption {
pub date_format: DateFormat,
pub time_format: TimeFormat,
pub field_type: FieldType,
}
impl TypeOption for DateTypeOption {
@ -39,9 +43,14 @@ impl From<TypeOptionData> for DateTypeOption {
.get_i64_value("time_format")
.map(TimeFormat::from)
.unwrap_or_default();
let field_type = data
.get_i64_value("field_type")
.map(FieldType::from)
.unwrap_or(FieldType::DateTime);
Self {
date_format,
time_format,
field_type,
}
}
}
@ -51,6 +60,7 @@ impl From<DateTypeOption> for TypeOptionData {
TypeOptionDataBuilder::new()
.insert_i64_value("data_format", data.date_format.value())
.insert_i64_value("time_format", data.time_format.value())
.insert_i64_value("field_type", data.field_type.value())
.build()
}
}
@ -69,9 +79,12 @@ impl TypeOptionCellData for DateTypeOption {
}
impl DateTypeOption {
#[allow(dead_code)]
pub fn new() -> Self {
Self::default()
pub fn new(field_type: FieldType) -> Self {
Self {
date_format: Default::default(),
time_format: Default::default(),
field_type,
}
}
fn today_desc_from_timestamp(&self, cell_data: DateCellData) -> DateCellDataPB {
@ -179,8 +192,8 @@ impl CellDataChangeset for DateTypeOption {
// old date cell data
let (previous_timestamp, include_time, timezone_id) = match cell {
None => (None, false, "".to_owned()),
Some(type_cell_data) => {
let cell_data = DateCellData::from(&type_cell_data);
Some(cell) => {
let cell_data = DateCellData::from(&cell);
(
cell_data.timestamp,
cell_data.include_time,
@ -201,7 +214,6 @@ impl CellDataChangeset for DateTypeOption {
// in the changeset without an accompanying time string, the old timestamp
// will simply be overwritten. Meaning, in order to change the day without
// changing the time, the old time string should be passed in as well.
let changeset_timestamp = changeset.date_timestamp();
// parse the time string, which is in the timezone corresponding to
@ -241,12 +253,14 @@ impl CellDataChangeset for DateTypeOption {
changeset_timestamp,
);
let date_cell_data = DateCellData {
let cell_data = DateCellData {
timestamp,
include_time,
timezone_id,
};
Ok((Cell::from(date_cell_data.clone()), date_cell_data))
let cell_wrapper: DateCellDataWrapper = (self.field_type.clone(), cell_data.clone()).into();
Ok((Cell::from(cell_wrapper), cell_data))
}
}

View File

@ -70,13 +70,29 @@ impl From<&Cell> for DateCellData {
}
}
impl From<DateCellData> for Cell {
fn from(data: DateCellData) -> Self {
/// Wrapper for DateCellData that also contains the field type.
/// Handy struct to use when you need to convert a DateCellData to a Cell.
pub struct DateCellDataWrapper {
data: DateCellData,
field_type: FieldType,
}
impl From<(FieldType, DateCellData)> for DateCellDataWrapper {
fn from((field_type, data): (FieldType, DateCellData)) -> Self {
Self { data, field_type }
}
}
impl From<DateCellDataWrapper> for Cell {
fn from(wrapper: DateCellDataWrapper) -> Self {
let (field_type, data) = (wrapper.field_type, wrapper.data);
let timestamp_string = match data.timestamp {
Some(timestamp) => timestamp.to_string(),
None => "".to_owned(),
};
new_cell_builder(FieldType::DateTime)
// Most of the case, don't use these keys in other places. Otherwise, we should define
// constants for them.
new_cell_builder(field_type)
.insert_str_value(CELL_DATA, timestamp_string)
.insert_bool_value("include_time", data.include_time)
.insert_str_value("timezone_id", data.timezone_id)
@ -84,6 +100,13 @@ impl From<DateCellData> for Cell {
}
}
impl From<DateCellData> for Cell {
fn from(data: DateCellData) -> Self {
let data: DateCellDataWrapper = (FieldType::DateTime, data).into();
Cell::from(data)
}
}
impl<'de> serde::Deserialize<'de> for DateCellData {
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where

View File

@ -146,7 +146,7 @@ pub fn type_option_data_from_pb_or_default<T: Into<Bytes>>(
FieldType::Number => {
NumberTypeOptionPB::try_from(bytes).map(|pb| NumberTypeOption::from(pb).into())
},
FieldType::DateTime => {
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
DateTypeOptionPB::try_from(bytes).map(|pb| DateTypeOption::from(pb).into())
},
FieldType::SingleSelect => {
@ -164,7 +164,7 @@ pub fn type_option_data_from_pb_or_default<T: Into<Bytes>>(
},
};
result.unwrap_or_else(|_| default_type_option_data_for_type(field_type))
result.unwrap_or_else(|_| default_type_option_data_from_type(field_type))
}
pub fn type_option_to_pb(type_option: TypeOptionData, field_type: &FieldType) -> Bytes {
@ -181,7 +181,7 @@ pub fn type_option_to_pb(type_option: TypeOptionData, field_type: &FieldType) ->
.try_into()
.unwrap()
},
FieldType::DateTime => {
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
let date_type_option: DateTypeOption = type_option.into();
DateTypeOptionPB::from(date_type_option).try_into().unwrap()
},
@ -216,11 +216,16 @@ pub fn type_option_to_pb(type_option: TypeOptionData, field_type: &FieldType) ->
}
}
pub fn default_type_option_data_for_type(field_type: &FieldType) -> TypeOptionData {
pub fn default_type_option_data_from_type(field_type: &FieldType) -> TypeOptionData {
match field_type {
FieldType::RichText => RichTextTypeOption::default().into(),
FieldType::Number => NumberTypeOption::default().into(),
FieldType::DateTime => DateTypeOption::default().into(),
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => DateTypeOption {
date_format: Default::default(),
time_format: Default::default(),
field_type: field_type.clone(),
}
.into(),
FieldType::SingleSelect => SingleSelectTypeOption::default().into(),
FieldType::MultiSelect => MultiSelectTypeOption::default().into(),
FieldType::Checkbox => CheckboxTypeOption::default().into(),

View File

@ -350,7 +350,7 @@ impl<'a> TypeOptionCellExt<'a> {
self.cell_data_cache.clone(),
)
}),
FieldType::DateTime => self
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => self
.field
.get_type_option::<DateTypeOption>(field_type)
.map(|type_option| {
@ -470,7 +470,7 @@ fn get_type_option_transform_handler(
FieldType::Number => {
Box::new(NumberTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
},
FieldType::DateTime => {
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
Box::new(DateTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
},
FieldType::SingleSelect => Box::new(SingleSelectTypeOption::from(type_option_data))

View File

@ -323,7 +323,7 @@ impl FilterController {
.write()
.insert(field_id, NumberFilterPB::from_filter(filter.as_ref()));
},
FieldType::DateTime => {
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
self
.cell_filter_cache
.write()

View File

@ -139,17 +139,7 @@ pub fn find_new_grouping_field(
///
pub fn default_group_setting(field: &Field) -> GroupSetting {
let field_id = field.id.clone();
let field_type = FieldType::from(field.field_type);
match field_type {
FieldType::RichText => GroupSetting::new(field_id, field.field_type, "".to_owned()),
FieldType::Number => GroupSetting::new(field_id, field.field_type, "".to_owned()),
FieldType::DateTime => GroupSetting::new(field_id, field.field_type, "".to_owned()),
FieldType::SingleSelect => GroupSetting::new(field_id, field.field_type, "".to_owned()),
FieldType::MultiSelect => GroupSetting::new(field_id, field.field_type, "".to_owned()),
FieldType::Checklist => GroupSetting::new(field_id, field.field_type, "".to_owned()),
FieldType::Checkbox => GroupSetting::new(field_id, field.field_type, "".to_owned()),
FieldType::URL => GroupSetting::new(field_id, field.field_type, "".to_owned()),
}
GroupSetting::new(field_id, field.field_type, "".to_owned())
}
pub fn make_no_status_group(field: &Field) -> Group {

View File

@ -1,6 +1,6 @@
use crate::entities::FieldType;
use crate::services::cell::CellBuilder;
use crate::services::field::default_type_option_data_for_type;
use crate::services::field::default_type_option_data_from_type;
use collab_database::database::{gen_database_id, gen_database_view_id, gen_field_id, gen_row_id};
use collab_database::fields::Field;
use collab_database::rows::CreateRowParams;
@ -73,7 +73,7 @@ fn database_from_fields_and_rows(fields_and_rows: FieldsRows) -> CreateDatabaseP
Ok(field) => field,
Err(_) => {
let field_type = FieldType::RichText;
let type_option_data = default_type_option_data_for_type(&field_type);
let type_option_data = default_type_option_data_from_type(&field_type);
let is_primary = index == 0;
Field::new(
gen_field_id(),