mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
parent
a85cc62a58
commit
9a213fa562
@ -280,6 +280,8 @@
|
||||
"textFieldName": "Text",
|
||||
"checkboxFieldName": "Checkbox",
|
||||
"dateFieldName": "Date",
|
||||
"updatedAtFieldName": "Updated At",
|
||||
"createdAtFieldName": "Created At",
|
||||
"numberFieldName": "Numbers",
|
||||
"singleSelectFieldName": "Select",
|
||||
"multiSelectFieldName": "Multiselect",
|
||||
|
@ -40,6 +40,8 @@ class CellControllerBuilder {
|
||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
final cellDataLoader = CellDataLoader(
|
||||
cellId: _cellId,
|
||||
parser: DateCellDataParser(),
|
||||
|
@ -353,7 +353,13 @@ class RowDataBuilder {
|
||||
}
|
||||
|
||||
void insertDate(FieldInfo fieldInfo, DateTime date) {
|
||||
assert(fieldInfo.fieldType == FieldType.DateTime);
|
||||
assert(
|
||||
[
|
||||
FieldType.DateTime,
|
||||
FieldType.UpdatedAt,
|
||||
FieldType.CreatedAt,
|
||||
].contains(fieldInfo.fieldType),
|
||||
);
|
||||
final timestamp = date.millisecondsSinceEpoch ~/ 1000;
|
||||
_cellDataByFieldId[fieldInfo.field.id] = timestamp.toString();
|
||||
}
|
||||
|
@ -84,10 +84,19 @@ class FilterBackendService {
|
||||
required String fieldId,
|
||||
String? filterId,
|
||||
required DateFilterConditionPB condition,
|
||||
required FieldType fieldType,
|
||||
int? start,
|
||||
int? end,
|
||||
int? timestamp,
|
||||
}) {
|
||||
assert(
|
||||
[
|
||||
FieldType.DateTime,
|
||||
FieldType.UpdatedAt,
|
||||
FieldType.CreatedAt,
|
||||
].contains(fieldType),
|
||||
);
|
||||
|
||||
var filter = DateFilterPB();
|
||||
if (timestamp != null) {
|
||||
filter.timestamp = $fixnum.Int64(timestamp);
|
||||
@ -105,7 +114,7 @@ class FilterBackendService {
|
||||
return insertFilter(
|
||||
fieldId: fieldId,
|
||||
filterId: filterId,
|
||||
fieldType: FieldType.DateTime,
|
||||
fieldType: fieldType,
|
||||
data: filter.writeToBuffer(),
|
||||
);
|
||||
}
|
||||
|
@ -362,6 +362,8 @@ Widget? _buildHeaderIcon(GroupData customData) {
|
||||
}
|
||||
break;
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
break;
|
||||
case FieldType.MultiSelect:
|
||||
break;
|
||||
|
@ -93,11 +93,14 @@ class GridCreateFilterBloc
|
||||
condition: CheckboxFilterConditionPB.IsChecked,
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
return _filterBackendSvc.insertDateFilter(
|
||||
fieldId: fieldId,
|
||||
condition: DateFilterConditionPB.DateIs,
|
||||
timestamp: timestamp,
|
||||
fieldType: field.fieldType,
|
||||
);
|
||||
case FieldType.MultiSelect:
|
||||
return _filterBackendSvc.insertSelectOptionFilter(
|
||||
|
@ -23,7 +23,11 @@ class FilterInfo {
|
||||
}
|
||||
|
||||
DateFilterPB? dateFilter() {
|
||||
if (filter.fieldType != FieldType.DateTime) {
|
||||
if (![
|
||||
FieldType.DateTime,
|
||||
FieldType.UpdatedAt,
|
||||
FieldType.CreatedAt,
|
||||
].contains(filter.fieldType)) {
|
||||
return null;
|
||||
}
|
||||
return DateFilterPB.fromBuffer(filter.data);
|
||||
|
@ -25,6 +25,8 @@ Widget buildFilterChoicechip(FilterInfo filterInfo) {
|
||||
case FieldType.Checkbox:
|
||||
return CheckboxFilterChoicechip(filterInfo: filterInfo);
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
return DateFilterChoicechip(filterInfo: filterInfo);
|
||||
case FieldType.MultiSelect:
|
||||
return SelectOptionFilterChoicechip(filterInfo: filterInfo);
|
||||
|
@ -8,6 +8,8 @@ extension FieldTypeListExtension on FieldType {
|
||||
case FieldType.Checkbox:
|
||||
return "grid/field/checkbox";
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
return "grid/field/date";
|
||||
case FieldType.MultiSelect:
|
||||
return "grid/field/multi_select";
|
||||
@ -31,6 +33,10 @@ extension FieldTypeListExtension on FieldType {
|
||||
return LocaleKeys.grid_field_checkboxFieldName.tr();
|
||||
case FieldType.DateTime:
|
||||
return LocaleKeys.grid_field_dateFieldName.tr();
|
||||
case FieldType.UpdatedAt:
|
||||
return LocaleKeys.grid_field_updatedAtFieldName.tr();
|
||||
case FieldType.CreatedAt:
|
||||
return LocaleKeys.grid_field_createdAtFieldName.tr();
|
||||
case FieldType.MultiSelect:
|
||||
return LocaleKeys.grid_field_multiSelectFieldName.tr();
|
||||
case FieldType.Number:
|
||||
|
@ -73,6 +73,8 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
|
||||
),
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
return DateTypeOptionWidgetBuilder(
|
||||
makeTypeOptionContextWithDataController<DateTypeOptionPB>(
|
||||
viewId: viewId,
|
||||
@ -202,6 +204,8 @@ TypeOptionContext<T>
|
||||
dataParser: CheckboxTypeOptionWidgetDataParser(),
|
||||
) as TypeOptionContext<T>;
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
return DateTypeOptionContext(
|
||||
dataController: dataController,
|
||||
dataParser: DateTypeOptionDataParser(),
|
||||
|
@ -39,6 +39,8 @@ class CardCellBuilder<CustomCardData> {
|
||||
key: key,
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
return DateCardCell<CustomCardData>(
|
||||
renderHook: renderHook?.renderHook[FieldType.DateTime],
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
|
@ -34,6 +34,8 @@ class GridCellBuilder {
|
||||
key: key,
|
||||
);
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
return GridDateCell(
|
||||
cellControllerBuilder: cellControllerBuilder,
|
||||
key: key,
|
||||
|
@ -335,6 +335,8 @@ GridCellStyle? _customCellStyle(FieldType fieldType) {
|
||||
case FieldType.Checkbox:
|
||||
return null;
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
return DateCellStyle(
|
||||
alignment: Alignment.centerLeft,
|
||||
);
|
||||
|
20
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
20
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -99,7 +99,7 @@ checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
[[package]]
|
||||
name = "appflowy-integrate"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1023,7 +1023,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -1040,7 +1040,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-client-ws"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab-sync",
|
||||
@ -1058,7 +1058,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1083,7 +1083,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1095,7 +1095,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1112,7 +1112,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
@ -1130,7 +1130,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-persistence"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
@ -1150,7 +1150,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1180,7 +1180,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-sync"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=6052d5#6052d509982f705c6d43a859c937a722a8c3358b"
|
||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d6af3a#d6af3a7662a57202e4e5b0a297c28757a18f3372"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"collab",
|
||||
|
@ -45,6 +45,8 @@ export class CellControllerBuilder {
|
||||
case FieldType.Number:
|
||||
return this.makeNumberCellController();
|
||||
case FieldType.DateTime:
|
||||
case FieldType.UpdatedAt:
|
||||
case FieldType.CreatedAt:
|
||||
return this.makeDateCellController();
|
||||
case FieldType.URL:
|
||||
return this.makeURLCellController();
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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::*;
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
@ -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(
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
|
@ -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))
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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(),
|
||||
|
@ -0,0 +1,2 @@
|
||||
mod row_test;
|
||||
mod script;
|
@ -0,0 +1,53 @@
|
||||
use crate::database::block_test::script::DatabaseRowTest;
|
||||
use crate::database::block_test::script::RowScript::*;
|
||||
use flowy_database2::entities::FieldType;
|
||||
use flowy_database2::services::field::DateCellData;
|
||||
|
||||
#[tokio::test]
|
||||
async fn set_created_at_field_on_create_row() {
|
||||
let mut test = DatabaseRowTest::new().await;
|
||||
let row_count = test.rows.len();
|
||||
|
||||
let before_create_timestamp = chrono::offset::Utc::now().timestamp();
|
||||
test
|
||||
.run_scripts(vec![CreateEmptyRow, AssertRowCount(row_count + 1)])
|
||||
.await;
|
||||
let after_create_timestamp = chrono::offset::Utc::now().timestamp();
|
||||
|
||||
let mut rows = test.rows.clone();
|
||||
rows.sort_by(|r1, r2| r1.created_at.cmp(&r2.created_at));
|
||||
let row = rows.last().unwrap();
|
||||
|
||||
let fields = test.fields.clone();
|
||||
let created_at_field = fields
|
||||
.iter()
|
||||
.find(|&f| FieldType::from(f.field_type) == FieldType::CreatedAt)
|
||||
.unwrap();
|
||||
let cell = row.cells.cell_for_field_id(&created_at_field.id).unwrap();
|
||||
let created_at_timestamp = DateCellData::from(cell).timestamp.unwrap();
|
||||
|
||||
assert!(
|
||||
created_at_timestamp >= before_create_timestamp
|
||||
&& created_at_timestamp <= after_create_timestamp,
|
||||
"timestamp: {}, before: {}, after: {}",
|
||||
created_at_timestamp,
|
||||
before_create_timestamp,
|
||||
after_create_timestamp
|
||||
);
|
||||
|
||||
let updated_at_field = fields
|
||||
.iter()
|
||||
.find(|&f| FieldType::from(f.field_type) == FieldType::UpdatedAt)
|
||||
.unwrap();
|
||||
let cell = row.cells.cell_for_field_id(&updated_at_field.id).unwrap();
|
||||
let updated_at_timestamp = DateCellData::from(cell).timestamp.unwrap();
|
||||
|
||||
assert!(
|
||||
updated_at_timestamp >= before_create_timestamp
|
||||
&& updated_at_timestamp <= after_create_timestamp,
|
||||
"timestamp: {}, before: {}, after: {}",
|
||||
updated_at_timestamp,
|
||||
before_create_timestamp,
|
||||
after_create_timestamp
|
||||
);
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
use crate::database::database_editor::DatabaseEditorTest;
|
||||
use flowy_database2::entities::CreateRowParams;
|
||||
|
||||
pub enum RowScript {
|
||||
CreateEmptyRow,
|
||||
AssertRowCount(usize),
|
||||
}
|
||||
|
||||
pub struct DatabaseRowTest {
|
||||
inner: DatabaseEditorTest,
|
||||
}
|
||||
|
||||
impl DatabaseRowTest {
|
||||
pub async fn new() -> Self {
|
||||
let editor_test = DatabaseEditorTest::new_grid().await;
|
||||
Self { inner: editor_test }
|
||||
}
|
||||
|
||||
pub async fn run_scripts(&mut self, scripts: Vec<RowScript>) {
|
||||
for script in scripts {
|
||||
self.run_script(script).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run_script(&mut self, script: RowScript) {
|
||||
match script {
|
||||
RowScript::CreateEmptyRow => {
|
||||
let params = CreateRowParams {
|
||||
view_id: self.view_id.clone(),
|
||||
start_row_id: None,
|
||||
group_id: None,
|
||||
cell_data_by_field_id: None,
|
||||
};
|
||||
let row_order = self.editor.create_row(params).await.unwrap().unwrap();
|
||||
self
|
||||
.row_by_row_id
|
||||
.insert(row_order.id.to_string(), row_order.into());
|
||||
self.rows = self.get_rows().await;
|
||||
},
|
||||
RowScript::AssertRowCount(expected_row_count) => {
|
||||
assert_eq!(expected_row_count, self.rows.len());
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for DatabaseRowTest {
|
||||
type Target = DatabaseEditorTest;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for DatabaseRowTest {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
use flowy_database2::entities::{CellChangesetPB, FieldType};
|
||||
use flowy_database2::services::cell::ToCellChangeset;
|
||||
use flowy_database2::services::field::{
|
||||
ChecklistTypeOption, MultiSelectTypeOption, SelectOptionCellChangeset, SingleSelectTypeOption,
|
||||
StrCellData, URLCellData,
|
||||
ChecklistTypeOption, DateCellData, MultiSelectTypeOption, SelectOptionCellChangeset,
|
||||
SingleSelectTypeOption, StrCellData, URLCellData,
|
||||
};
|
||||
|
||||
use crate::database::cell_test::script::CellScript::UpdateCell;
|
||||
@ -22,7 +22,9 @@ async fn grid_cell_update() {
|
||||
let cell_changeset = match field_type {
|
||||
FieldType::RichText => "".to_string(),
|
||||
FieldType::Number => "123".to_string(),
|
||||
FieldType::DateTime => make_date_cell_string("123"),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
|
||||
make_date_cell_string("123")
|
||||
},
|
||||
FieldType::SingleSelect => {
|
||||
let type_option = field
|
||||
.get_type_option::<SingleSelectTypeOption>(field.field_type)
|
||||
@ -64,7 +66,7 @@ async fn grid_cell_update() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn text_cell_date_test() {
|
||||
async fn text_cell_data_test() {
|
||||
let test = DatabaseCellTest::new().await;
|
||||
let text_field = test.get_first_field(FieldType::RichText);
|
||||
|
||||
@ -88,7 +90,7 @@ async fn text_cell_date_test() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn url_cell_date_test() {
|
||||
async fn url_cell_data_test() {
|
||||
let test = DatabaseCellTest::new().await;
|
||||
let url_field = test.get_first_field(FieldType::URL);
|
||||
let cells = test
|
||||
@ -103,3 +105,83 @@ async fn url_cell_date_test() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_updated_at_field_on_other_cell_update() {
|
||||
let mut test = DatabaseCellTest::new().await;
|
||||
let updated_at_field = test.get_first_field(FieldType::UpdatedAt);
|
||||
|
||||
let text_field = test
|
||||
.fields
|
||||
.iter()
|
||||
.find(|&f| FieldType::from(f.field_type) == FieldType::RichText)
|
||||
.unwrap();
|
||||
|
||||
let before_update_timestamp = chrono::offset::Utc::now().timestamp();
|
||||
test
|
||||
.run_script(UpdateCell {
|
||||
changeset: CellChangesetPB {
|
||||
view_id: test.view_id.clone(),
|
||||
row_id: test.rows[0].id.to_string(),
|
||||
field_id: text_field.id.clone(),
|
||||
cell_changeset: "change".to_string(),
|
||||
},
|
||||
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;
|
||||
assert!(cells.len() > 0);
|
||||
for (i, cell) in cells.into_iter().enumerate() {
|
||||
let timestamp = DateCellData::from(cell.as_ref()).timestamp.unwrap();
|
||||
println!(
|
||||
"{}, bf: {}, af: {}",
|
||||
timestamp, before_update_timestamp, after_update_timestamp
|
||||
);
|
||||
match i {
|
||||
0 => assert!(
|
||||
timestamp >= before_update_timestamp && timestamp <= after_update_timestamp,
|
||||
"{} >= {} && {} <= {}",
|
||||
timestamp,
|
||||
before_update_timestamp,
|
||||
timestamp,
|
||||
after_update_timestamp
|
||||
),
|
||||
1 => assert!(
|
||||
timestamp <= before_update_timestamp,
|
||||
"{} <= {}",
|
||||
timestamp,
|
||||
before_update_timestamp
|
||||
),
|
||||
2 => assert!(
|
||||
timestamp <= before_update_timestamp,
|
||||
"{} <= {}",
|
||||
timestamp,
|
||||
before_update_timestamp
|
||||
),
|
||||
3 => assert!(
|
||||
timestamp <= before_update_timestamp,
|
||||
"{} <= {}",
|
||||
timestamp,
|
||||
before_update_timestamp
|
||||
),
|
||||
4 => assert!(
|
||||
timestamp <= before_update_timestamp,
|
||||
"{} <= {}",
|
||||
timestamp,
|
||||
before_update_timestamp
|
||||
),
|
||||
5 => assert!(
|
||||
timestamp <= before_update_timestamp,
|
||||
"{} <= {}",
|
||||
timestamp,
|
||||
before_update_timestamp
|
||||
),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -277,6 +277,7 @@ impl<'a> TestRowBuilder<'a> {
|
||||
time: Option<String>,
|
||||
include_time: Option<bool>,
|
||||
timezone_id: Option<String>,
|
||||
field_type: &FieldType,
|
||||
) -> String {
|
||||
let value = serde_json::to_string(&DateCellChangeset {
|
||||
date: Some(data.to_string()),
|
||||
@ -285,7 +286,7 @@ impl<'a> TestRowBuilder<'a> {
|
||||
timezone_id,
|
||||
})
|
||||
.unwrap();
|
||||
let date_field = self.field_with_type(&FieldType::DateTime);
|
||||
let date_field = self.field_with_type(field_type);
|
||||
self.cell_build.insert_text_cell(&date_field.id, value);
|
||||
date_field.id.clone()
|
||||
}
|
||||
|
@ -30,6 +30,16 @@ async fn grid_create_field() {
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
|
||||
let (params, field) = create_date_field(&test.view_id(), FieldType::CreatedAt);
|
||||
let scripts = vec![
|
||||
CreateField { params },
|
||||
AssertFieldTypeOptionEqual {
|
||||
field_index: test.field_count(),
|
||||
expected_type_option_data: field.get_any_type_option(field.field_type).unwrap(),
|
||||
},
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -1,8 +1,8 @@
|
||||
use collab_database::fields::Field;
|
||||
use flowy_database2::entities::{CreateFieldParams, FieldType};
|
||||
use flowy_database2::services::field::{
|
||||
type_option_to_pb, DateCellChangeset, FieldBuilder, RichTextTypeOption, SelectOption,
|
||||
SingleSelectTypeOption,
|
||||
type_option_to_pb, DateCellChangeset, DateFormat, DateTypeOption, FieldBuilder,
|
||||
RichTextTypeOption, SelectOption, SingleSelectTypeOption, TimeFormat,
|
||||
};
|
||||
|
||||
pub fn create_text_field(grid_id: &str) -> (CreateFieldParams, Field) {
|
||||
@ -42,6 +42,39 @@ pub fn create_single_select_field(grid_id: &str) -> (CreateFieldParams, Field) {
|
||||
(params, single_select_field)
|
||||
}
|
||||
|
||||
pub fn create_date_field(grid_id: &str, field_type: FieldType) -> (CreateFieldParams, Field) {
|
||||
let date_type_option = DateTypeOption {
|
||||
date_format: DateFormat::US,
|
||||
time_format: TimeFormat::TwentyFourHour,
|
||||
field_type: field_type.clone(),
|
||||
};
|
||||
|
||||
let field: Field = match field_type {
|
||||
FieldType::DateTime => FieldBuilder::new(field_type.clone(), date_type_option.clone())
|
||||
.name("Date")
|
||||
.visibility(true)
|
||||
.build(),
|
||||
FieldType::UpdatedAt => FieldBuilder::new(field_type.clone(), date_type_option.clone())
|
||||
.name("Updated At")
|
||||
.visibility(true)
|
||||
.build(),
|
||||
FieldType::CreatedAt => FieldBuilder::new(field_type.clone(), date_type_option.clone())
|
||||
.name("Created At")
|
||||
.visibility(true)
|
||||
.build(),
|
||||
_ => panic!("Unsupported group field type"),
|
||||
};
|
||||
|
||||
let type_option_data = type_option_to_pb(date_type_option.into(), &field_type).to_vec();
|
||||
|
||||
let params = CreateFieldParams {
|
||||
view_id: grid_id.to_owned(),
|
||||
field_type,
|
||||
type_option_data: Some(type_option_data),
|
||||
};
|
||||
(params, field)
|
||||
}
|
||||
|
||||
// The grid will contains all existing field types and there are three empty rows in this grid.
|
||||
|
||||
pub fn make_date_cell_string(s: &str) -> String {
|
||||
|
@ -38,14 +38,21 @@ pub fn make_test_board() -> DatabaseData {
|
||||
.build();
|
||||
fields.push(number_field);
|
||||
},
|
||||
FieldType::DateTime => {
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
|
||||
// Date
|
||||
let date_type_option = DateTypeOption {
|
||||
date_format: DateFormat::US,
|
||||
time_format: TimeFormat::TwentyFourHour,
|
||||
field_type: field_type.clone(),
|
||||
};
|
||||
let name = match field_type {
|
||||
FieldType::DateTime => "Time",
|
||||
FieldType::UpdatedAt => "Updated At",
|
||||
FieldType::CreatedAt => "Created At",
|
||||
_ => "",
|
||||
};
|
||||
let date_field = FieldBuilder::new(field_type.clone(), date_type_option)
|
||||
.name("Time")
|
||||
.name(name)
|
||||
.visibility(true)
|
||||
.build();
|
||||
fields.push(date_field);
|
||||
@ -119,12 +126,14 @@ pub fn make_test_board() -> DatabaseData {
|
||||
FieldType::RichText => row_builder.insert_text_cell("A"),
|
||||
FieldType::Number => row_builder.insert_number_cell("1"),
|
||||
// 1647251762 => Mar 14,2022
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::SingleSelect => {
|
||||
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
||||
},
|
||||
@ -142,12 +151,14 @@ pub fn make_test_board() -> DatabaseData {
|
||||
FieldType::RichText => row_builder.insert_text_cell("B"),
|
||||
FieldType::Number => row_builder.insert_number_cell("2"),
|
||||
// 1647251762 => Mar 14,2022
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::SingleSelect => {
|
||||
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
||||
},
|
||||
@ -164,12 +175,14 @@ pub fn make_test_board() -> DatabaseData {
|
||||
FieldType::RichText => row_builder.insert_text_cell("C"),
|
||||
FieldType::Number => row_builder.insert_number_cell("3"),
|
||||
// 1647251762 => Mar 14,2022
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::SingleSelect => {
|
||||
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
||||
},
|
||||
@ -189,12 +202,14 @@ pub fn make_test_board() -> DatabaseData {
|
||||
match field_type {
|
||||
FieldType::RichText => row_builder.insert_text_cell("DA"),
|
||||
FieldType::Number => row_builder.insert_number_cell("4"),
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1668704685",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1668704685",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::SingleSelect => {
|
||||
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
||||
},
|
||||
@ -209,12 +224,14 @@ pub fn make_test_board() -> DatabaseData {
|
||||
match field_type {
|
||||
FieldType::RichText => row_builder.insert_text_cell("AE"),
|
||||
FieldType::Number => row_builder.insert_number_cell(""),
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1668359085",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1668359085",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::SingleSelect => {
|
||||
row_builder.insert_single_select_cell(|mut options| options.remove(2))
|
||||
},
|
||||
|
@ -51,6 +51,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
_ => "".to_owned(),
|
||||
};
|
||||
@ -65,6 +66,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
_ => "".to_owned(),
|
||||
};
|
||||
@ -79,6 +81,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
_ => "".to_owned(),
|
||||
};
|
||||
@ -93,6 +96,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
_ => "".to_owned(),
|
||||
};
|
||||
@ -107,6 +111,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
_ => "".to_owned(),
|
||||
};
|
||||
|
@ -39,14 +39,21 @@ pub fn make_test_grid() -> DatabaseData {
|
||||
.build();
|
||||
fields.push(number_field);
|
||||
},
|
||||
FieldType::DateTime => {
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
|
||||
// Date
|
||||
let date_type_option = DateTypeOption {
|
||||
date_format: DateFormat::US,
|
||||
time_format: TimeFormat::TwentyFourHour,
|
||||
field_type: field_type.clone(),
|
||||
};
|
||||
let name = match field_type {
|
||||
FieldType::DateTime => "Time",
|
||||
FieldType::UpdatedAt => "Updated At",
|
||||
FieldType::CreatedAt => "Created At",
|
||||
_ => "",
|
||||
};
|
||||
let date_field = FieldBuilder::new(field_type.clone(), date_type_option)
|
||||
.name("Time")
|
||||
.name(name)
|
||||
.visibility(true)
|
||||
.build();
|
||||
fields.push(date_field);
|
||||
@ -118,12 +125,14 @@ pub fn make_test_grid() -> DatabaseData {
|
||||
match field_type {
|
||||
FieldType::RichText => row_builder.insert_text_cell("A"),
|
||||
FieldType::Number => row_builder.insert_number_cell("1"),
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::MultiSelect => row_builder
|
||||
.insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(0)]),
|
||||
FieldType::Checklist => row_builder.insert_checklist_cell(|options| options),
|
||||
@ -140,12 +149,14 @@ pub fn make_test_grid() -> DatabaseData {
|
||||
match field_type {
|
||||
FieldType::RichText => row_builder.insert_text_cell(""),
|
||||
FieldType::Number => row_builder.insert_number_cell("2"),
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::MultiSelect => row_builder
|
||||
.insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(1)]),
|
||||
FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
|
||||
@ -158,12 +169,14 @@ pub fn make_test_grid() -> DatabaseData {
|
||||
match field_type {
|
||||
FieldType::RichText => row_builder.insert_text_cell("C"),
|
||||
FieldType::Number => row_builder.insert_number_cell("3"),
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1647251762",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::SingleSelect => {
|
||||
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
||||
},
|
||||
@ -180,12 +193,14 @@ pub fn make_test_grid() -> DatabaseData {
|
||||
match field_type {
|
||||
FieldType::RichText => row_builder.insert_text_cell("DA"),
|
||||
FieldType::Number => row_builder.insert_number_cell("14"),
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1668704685",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1668704685",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::SingleSelect => {
|
||||
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
||||
},
|
||||
@ -199,12 +214,14 @@ pub fn make_test_grid() -> DatabaseData {
|
||||
match field_type {
|
||||
FieldType::RichText => row_builder.insert_text_cell("AE"),
|
||||
FieldType::Number => row_builder.insert_number_cell(""),
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1668359085",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1668359085",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::SingleSelect => {
|
||||
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
||||
},
|
||||
@ -219,12 +236,14 @@ pub fn make_test_grid() -> DatabaseData {
|
||||
match field_type {
|
||||
FieldType::RichText => row_builder.insert_text_cell("AE"),
|
||||
FieldType::Number => row_builder.insert_number_cell("5"),
|
||||
FieldType::DateTime => row_builder.insert_date_cell(
|
||||
"1671938394",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
),
|
||||
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||
.insert_date_cell(
|
||||
"1671938394",
|
||||
None,
|
||||
None,
|
||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||
&field_type,
|
||||
),
|
||||
FieldType::SingleSelect => {
|
||||
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
||||
},
|
||||
|
@ -1,3 +1,4 @@
|
||||
mod block_test;
|
||||
mod cell_test;
|
||||
mod database_editor;
|
||||
mod field_test;
|
||||
|
Loading…
Reference in New Issue
Block a user