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",
|
"textFieldName": "Text",
|
||||||
"checkboxFieldName": "Checkbox",
|
"checkboxFieldName": "Checkbox",
|
||||||
"dateFieldName": "Date",
|
"dateFieldName": "Date",
|
||||||
|
"updatedAtFieldName": "Updated At",
|
||||||
|
"createdAtFieldName": "Created At",
|
||||||
"numberFieldName": "Numbers",
|
"numberFieldName": "Numbers",
|
||||||
"singleSelectFieldName": "Select",
|
"singleSelectFieldName": "Select",
|
||||||
"multiSelectFieldName": "Multiselect",
|
"multiSelectFieldName": "Multiselect",
|
||||||
|
@ -40,6 +40,8 @@ class CellControllerBuilder {
|
|||||||
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
|
||||||
);
|
);
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
final cellDataLoader = CellDataLoader(
|
final cellDataLoader = CellDataLoader(
|
||||||
cellId: _cellId,
|
cellId: _cellId,
|
||||||
parser: DateCellDataParser(),
|
parser: DateCellDataParser(),
|
||||||
|
@ -353,7 +353,13 @@ class RowDataBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void insertDate(FieldInfo fieldInfo, DateTime date) {
|
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;
|
final timestamp = date.millisecondsSinceEpoch ~/ 1000;
|
||||||
_cellDataByFieldId[fieldInfo.field.id] = timestamp.toString();
|
_cellDataByFieldId[fieldInfo.field.id] = timestamp.toString();
|
||||||
}
|
}
|
||||||
|
@ -84,10 +84,19 @@ class FilterBackendService {
|
|||||||
required String fieldId,
|
required String fieldId,
|
||||||
String? filterId,
|
String? filterId,
|
||||||
required DateFilterConditionPB condition,
|
required DateFilterConditionPB condition,
|
||||||
|
required FieldType fieldType,
|
||||||
int? start,
|
int? start,
|
||||||
int? end,
|
int? end,
|
||||||
int? timestamp,
|
int? timestamp,
|
||||||
}) {
|
}) {
|
||||||
|
assert(
|
||||||
|
[
|
||||||
|
FieldType.DateTime,
|
||||||
|
FieldType.UpdatedAt,
|
||||||
|
FieldType.CreatedAt,
|
||||||
|
].contains(fieldType),
|
||||||
|
);
|
||||||
|
|
||||||
var filter = DateFilterPB();
|
var filter = DateFilterPB();
|
||||||
if (timestamp != null) {
|
if (timestamp != null) {
|
||||||
filter.timestamp = $fixnum.Int64(timestamp);
|
filter.timestamp = $fixnum.Int64(timestamp);
|
||||||
@ -105,7 +114,7 @@ class FilterBackendService {
|
|||||||
return insertFilter(
|
return insertFilter(
|
||||||
fieldId: fieldId,
|
fieldId: fieldId,
|
||||||
filterId: filterId,
|
filterId: filterId,
|
||||||
fieldType: FieldType.DateTime,
|
fieldType: fieldType,
|
||||||
data: filter.writeToBuffer(),
|
data: filter.writeToBuffer(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -362,6 +362,8 @@ Widget? _buildHeaderIcon(GroupData customData) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
break;
|
break;
|
||||||
case FieldType.MultiSelect:
|
case FieldType.MultiSelect:
|
||||||
break;
|
break;
|
||||||
|
@ -93,11 +93,14 @@ class GridCreateFilterBloc
|
|||||||
condition: CheckboxFilterConditionPB.IsChecked,
|
condition: CheckboxFilterConditionPB.IsChecked,
|
||||||
);
|
);
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||||
return _filterBackendSvc.insertDateFilter(
|
return _filterBackendSvc.insertDateFilter(
|
||||||
fieldId: fieldId,
|
fieldId: fieldId,
|
||||||
condition: DateFilterConditionPB.DateIs,
|
condition: DateFilterConditionPB.DateIs,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
|
fieldType: field.fieldType,
|
||||||
);
|
);
|
||||||
case FieldType.MultiSelect:
|
case FieldType.MultiSelect:
|
||||||
return _filterBackendSvc.insertSelectOptionFilter(
|
return _filterBackendSvc.insertSelectOptionFilter(
|
||||||
|
@ -23,7 +23,11 @@ class FilterInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DateFilterPB? dateFilter() {
|
DateFilterPB? dateFilter() {
|
||||||
if (filter.fieldType != FieldType.DateTime) {
|
if (![
|
||||||
|
FieldType.DateTime,
|
||||||
|
FieldType.UpdatedAt,
|
||||||
|
FieldType.CreatedAt,
|
||||||
|
].contains(filter.fieldType)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return DateFilterPB.fromBuffer(filter.data);
|
return DateFilterPB.fromBuffer(filter.data);
|
||||||
|
@ -25,6 +25,8 @@ Widget buildFilterChoicechip(FilterInfo filterInfo) {
|
|||||||
case FieldType.Checkbox:
|
case FieldType.Checkbox:
|
||||||
return CheckboxFilterChoicechip(filterInfo: filterInfo);
|
return CheckboxFilterChoicechip(filterInfo: filterInfo);
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
return DateFilterChoicechip(filterInfo: filterInfo);
|
return DateFilterChoicechip(filterInfo: filterInfo);
|
||||||
case FieldType.MultiSelect:
|
case FieldType.MultiSelect:
|
||||||
return SelectOptionFilterChoicechip(filterInfo: filterInfo);
|
return SelectOptionFilterChoicechip(filterInfo: filterInfo);
|
||||||
|
@ -8,6 +8,8 @@ extension FieldTypeListExtension on FieldType {
|
|||||||
case FieldType.Checkbox:
|
case FieldType.Checkbox:
|
||||||
return "grid/field/checkbox";
|
return "grid/field/checkbox";
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
return "grid/field/date";
|
return "grid/field/date";
|
||||||
case FieldType.MultiSelect:
|
case FieldType.MultiSelect:
|
||||||
return "grid/field/multi_select";
|
return "grid/field/multi_select";
|
||||||
@ -31,6 +33,10 @@ extension FieldTypeListExtension on FieldType {
|
|||||||
return LocaleKeys.grid_field_checkboxFieldName.tr();
|
return LocaleKeys.grid_field_checkboxFieldName.tr();
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
return LocaleKeys.grid_field_dateFieldName.tr();
|
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:
|
case FieldType.MultiSelect:
|
||||||
return LocaleKeys.grid_field_multiSelectFieldName.tr();
|
return LocaleKeys.grid_field_multiSelectFieldName.tr();
|
||||||
case FieldType.Number:
|
case FieldType.Number:
|
||||||
|
@ -73,6 +73,8 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
return DateTypeOptionWidgetBuilder(
|
return DateTypeOptionWidgetBuilder(
|
||||||
makeTypeOptionContextWithDataController<DateTypeOptionPB>(
|
makeTypeOptionContextWithDataController<DateTypeOptionPB>(
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
@ -202,6 +204,8 @@ TypeOptionContext<T>
|
|||||||
dataParser: CheckboxTypeOptionWidgetDataParser(),
|
dataParser: CheckboxTypeOptionWidgetDataParser(),
|
||||||
) as TypeOptionContext<T>;
|
) as TypeOptionContext<T>;
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
return DateTypeOptionContext(
|
return DateTypeOptionContext(
|
||||||
dataController: dataController,
|
dataController: dataController,
|
||||||
dataParser: DateTypeOptionDataParser(),
|
dataParser: DateTypeOptionDataParser(),
|
||||||
|
@ -39,6 +39,8 @@ class CardCellBuilder<CustomCardData> {
|
|||||||
key: key,
|
key: key,
|
||||||
);
|
);
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
return DateCardCell<CustomCardData>(
|
return DateCardCell<CustomCardData>(
|
||||||
renderHook: renderHook?.renderHook[FieldType.DateTime],
|
renderHook: renderHook?.renderHook[FieldType.DateTime],
|
||||||
cellControllerBuilder: cellControllerBuilder,
|
cellControllerBuilder: cellControllerBuilder,
|
||||||
|
@ -34,6 +34,8 @@ class GridCellBuilder {
|
|||||||
key: key,
|
key: key,
|
||||||
);
|
);
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
return GridDateCell(
|
return GridDateCell(
|
||||||
cellControllerBuilder: cellControllerBuilder,
|
cellControllerBuilder: cellControllerBuilder,
|
||||||
key: key,
|
key: key,
|
||||||
|
@ -335,6 +335,8 @@ GridCellStyle? _customCellStyle(FieldType fieldType) {
|
|||||||
case FieldType.Checkbox:
|
case FieldType.Checkbox:
|
||||||
return null;
|
return null;
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
return DateCellStyle(
|
return DateCellStyle(
|
||||||
alignment: Alignment.centerLeft,
|
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]]
|
[[package]]
|
||||||
name = "appflowy-integrate"
|
name = "appflowy-integrate"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
@ -1023,7 +1023,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab"
|
name = "collab"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1040,7 +1040,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-client-ws"
|
name = "collab-client-ws"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"collab-sync",
|
"collab-sync",
|
||||||
@ -1058,7 +1058,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-database"
|
name = "collab-database"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -1083,7 +1083,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-derive"
|
name = "collab-derive"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1095,7 +1095,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-document"
|
name = "collab-document"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
@ -1112,7 +1112,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-folder"
|
name = "collab-folder"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
@ -1130,7 +1130,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-persistence"
|
name = "collab-persistence"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -1150,7 +1150,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-plugins"
|
name = "collab-plugins"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -1180,7 +1180,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-sync"
|
name = "collab-sync"
|
||||||
version = "0.1.0"
|
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 = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"collab",
|
"collab",
|
||||||
|
@ -45,6 +45,8 @@ export class CellControllerBuilder {
|
|||||||
case FieldType.Number:
|
case FieldType.Number:
|
||||||
return this.makeNumberCellController();
|
return this.makeNumberCellController();
|
||||||
case FieldType.DateTime:
|
case FieldType.DateTime:
|
||||||
|
case FieldType.UpdatedAt:
|
||||||
|
case FieldType.CreatedAt:
|
||||||
return this.makeDateCellController();
|
return this.makeDateCellController();
|
||||||
case FieldType.URL:
|
case FieldType.URL:
|
||||||
return this.makeURLCellController();
|
return this.makeURLCellController();
|
||||||
|
@ -492,6 +492,8 @@ pub enum FieldType {
|
|||||||
Checkbox = 5,
|
Checkbox = 5,
|
||||||
URL = 6,
|
URL = 6,
|
||||||
Checklist = 7,
|
Checklist = 7,
|
||||||
|
UpdatedAt = 8,
|
||||||
|
CreatedAt = 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const RICH_TEXT_FIELD: FieldType = FieldType::RichText;
|
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 CHECKBOX_FIELD: FieldType = FieldType::Checkbox;
|
||||||
pub const URL_FIELD: FieldType = FieldType::URL;
|
pub const URL_FIELD: FieldType = FieldType::URL;
|
||||||
pub const CHECKLIST_FIELD: FieldType = FieldType::Checklist;
|
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 {
|
impl std::default::Default for FieldType {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -529,9 +533,13 @@ impl From<&FieldType> for FieldType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FieldType {
|
impl FieldType {
|
||||||
|
pub fn value(&self) -> i64 {
|
||||||
|
self.clone().into()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn default_cell_width(&self) -> i32 {
|
pub fn default_cell_width(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
FieldType::DateTime => 180,
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => 180,
|
||||||
_ => 150,
|
_ => 150,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -546,6 +554,8 @@ impl FieldType {
|
|||||||
FieldType::Checkbox => "Checkbox",
|
FieldType::Checkbox => "Checkbox",
|
||||||
FieldType::URL => "URL",
|
FieldType::URL => "URL",
|
||||||
FieldType::Checklist => "Checklist",
|
FieldType::Checklist => "Checklist",
|
||||||
|
FieldType::UpdatedAt => "Updated At",
|
||||||
|
FieldType::CreatedAt => "Created At",
|
||||||
};
|
};
|
||||||
s.to_string()
|
s.to_string()
|
||||||
}
|
}
|
||||||
@ -563,7 +573,7 @@ impl FieldType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_date(&self) -> bool {
|
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 {
|
pub fn is_single_select(&self) -> bool {
|
||||||
@ -605,6 +615,8 @@ impl From<FieldType> for i64 {
|
|||||||
FieldType::Checkbox => 5,
|
FieldType::Checkbox => 5,
|
||||||
FieldType::URL => 6,
|
FieldType::URL => 6,
|
||||||
FieldType::Checklist => 7,
|
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 {
|
let bytes: Bytes = match filter.field_type {
|
||||||
FieldType::RichText => TextFilterPB::from(filter).try_into().unwrap(),
|
FieldType::RichText => TextFilterPB::from(filter).try_into().unwrap(),
|
||||||
FieldType::Number => NumberFilterPB::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::SingleSelect => SelectOptionFilterPB::from(filter).try_into().unwrap(),
|
||||||
FieldType::MultiSelect => SelectOptionFilterPB::from(filter).try_into().unwrap(),
|
FieldType::MultiSelect => SelectOptionFilterPB::from(filter).try_into().unwrap(),
|
||||||
FieldType::Checklist => ChecklistFilterPB::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;
|
condition = filter.condition as u8;
|
||||||
content = filter.content;
|
content = filter.content;
|
||||||
},
|
},
|
||||||
FieldType::DateTime => {
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
|
||||||
let filter = DateFilterPB::try_from(bytes).map_err(|_| ErrorCode::ProtobufSerde)?;
|
let filter = DateFilterPB::try_from(bytes).map_err(|_| ErrorCode::ProtobufSerde)?;
|
||||||
condition = filter.condition as u8;
|
condition = filter.condition as u8;
|
||||||
content = DateFilterContentPB {
|
content = DateFilterContentPB {
|
||||||
|
@ -12,6 +12,8 @@ macro_rules! impl_into_field_type {
|
|||||||
5 => FieldType::Checkbox,
|
5 => FieldType::Checkbox,
|
||||||
6 => FieldType::URL,
|
6 => FieldType::URL,
|
||||||
7 => FieldType::Checklist,
|
7 => FieldType::Checklist,
|
||||||
|
8 => FieldType::UpdatedAt,
|
||||||
|
9 => FieldType::CreatedAt,
|
||||||
_ => {
|
_ => {
|
||||||
tracing::error!("Can't parser FieldType from value: {}", ty);
|
tracing::error!("Can't parser FieldType from value: {}", ty);
|
||||||
FieldType::RichText
|
FieldType::RichText
|
||||||
|
@ -4,7 +4,7 @@ use strum_macros::EnumIter;
|
|||||||
|
|
||||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||||
|
|
||||||
use crate::entities::CellIdPB;
|
use crate::entities::{CellIdPB, FieldType};
|
||||||
use crate::services::field::{DateFormat, DateTypeOption, TimeFormat};
|
use crate::services::field::{DateFormat, DateTypeOption, TimeFormat};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, ProtoBuf)]
|
#[derive(Clone, Debug, Default, ProtoBuf)]
|
||||||
@ -51,6 +51,9 @@ pub struct DateTypeOptionPB {
|
|||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
pub time_format: TimeFormatPB,
|
pub time_format: TimeFormatPB,
|
||||||
|
|
||||||
|
#[pb(index = 3)]
|
||||||
|
pub field_type: FieldType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DateTypeOption> for DateTypeOptionPB {
|
impl From<DateTypeOption> for DateTypeOptionPB {
|
||||||
@ -58,6 +61,7 @@ impl From<DateTypeOption> for DateTypeOptionPB {
|
|||||||
Self {
|
Self {
|
||||||
date_format: data.date_format.into(),
|
date_format: data.date_format.into(),
|
||||||
time_format: data.time_format.into(),
|
time_format: data.time_format.into(),
|
||||||
|
field_type: data.field_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,6 +71,7 @@ impl From<DateTypeOptionPB> for DateTypeOption {
|
|||||||
Self {
|
Self {
|
||||||
date_format: data.date_format.into(),
|
date_format: data.date_format.into(),
|
||||||
time_format: data.time_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::fields::Field;
|
||||||
use collab_database::rows::{get_field_type_from_cell, Cell, Cells};
|
use collab_database::rows::{get_field_type_from_cell, Cell, Cells};
|
||||||
|
use lib_infra::util::timestamp;
|
||||||
|
|
||||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
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()
|
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 {
|
let cell_data = serde_json::to_string(&DateCellChangeset {
|
||||||
date: Some(timestamp.to_string()),
|
date: Some(timestamp.to_string()),
|
||||||
time: None,
|
time: None,
|
||||||
include_time: Some(false),
|
include_time,
|
||||||
timezone_id: None,
|
timezone_id: None,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -299,6 +300,7 @@ pub struct CellBuilder<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> 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 {
|
pub fn with_cells(cell_by_field_id: HashMap<String, String>, fields: &'a [Field]) -> Self {
|
||||||
let field_maps = fields
|
let field_maps = fields
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -306,7 +308,7 @@ impl<'a> CellBuilder<'a> {
|
|||||||
.collect::<HashMap<String, &Field>>();
|
.collect::<HashMap<String, &Field>>();
|
||||||
|
|
||||||
let mut cells = Cells::new();
|
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) {
|
if let Some(field) = field_maps.get(&field_id) {
|
||||||
let field_type = FieldType::from(field.field_type);
|
let field_type = FieldType::from(field.field_type);
|
||||||
match field_type {
|
match field_type {
|
||||||
@ -318,9 +320,9 @@ impl<'a> CellBuilder<'a> {
|
|||||||
cells.insert(field_id, insert_number_cell(num, field));
|
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>() {
|
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 => {
|
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 }
|
CellBuilder { cells, field_maps }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,9 +415,10 @@ impl<'a> CellBuilder<'a> {
|
|||||||
match self.field_maps.get(&field_id.to_owned()) {
|
match self.field_maps.get(&field_id.to_owned()) {
|
||||||
None => tracing::warn!("Can't find the date field with id: {}", field_id),
|
None => tracing::warn!("Can't find the date field with id: {}", field_id),
|
||||||
Some(field) => {
|
Some(field) => {
|
||||||
self
|
self.cells.insert(
|
||||||
.cells
|
field_id.to_owned(),
|
||||||
.insert(field_id.to_owned(), insert_date_cell(timestamp, field));
|
insert_date_cell(timestamp, Some(false), field),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,8 @@ impl TypeCellData {
|
|||||||
|
|
||||||
pub fn is_date(&self) -> bool {
|
pub fn is_date(&self) -> bool {
|
||||||
self.field_type == FieldType::DateTime
|
self.field_type == FieldType::DateTime
|
||||||
|
|| self.field_type == FieldType::UpdatedAt
|
||||||
|
|| self.field_type == FieldType::CreatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_single_select(&self) -> bool {
|
pub fn is_single_select(&self) -> bool {
|
||||||
|
@ -23,15 +23,15 @@ use crate::entities::{
|
|||||||
};
|
};
|
||||||
use crate::notification::{send_notification, DatabaseNotification};
|
use crate::notification::{send_notification, DatabaseNotification};
|
||||||
use crate::services::cell::{
|
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::util::database_view_setting_pb_from_view;
|
||||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewData, DatabaseViews};
|
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewData, DatabaseViews};
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
default_type_option_data_for_type, default_type_option_data_from_type,
|
default_type_option_data_from_type, select_type_option_from_field, transform_type_option,
|
||||||
select_type_option_from_field, transform_type_option, type_option_data_from_pb_or_default,
|
type_option_data_from_pb_or_default, type_option_to_pb, SelectOptionCellChangeset,
|
||||||
type_option_to_pb, SelectOptionCellChangeset, SelectOptionIds, TypeOptionCellDataHandler,
|
SelectOptionIds, TypeOptionCellDataHandler, TypeOptionCellExt,
|
||||||
TypeOptionCellExt,
|
|
||||||
};
|
};
|
||||||
use crate::services::filter::Filter;
|
use crate::services::filter::Filter;
|
||||||
use crate::services::group::{default_group_setting, GroupSetting, RowChangeset};
|
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 old_type_option = field.get_any_type_option(old_field_type.clone());
|
||||||
let new_type_option = field
|
let new_type_option = field
|
||||||
.get_any_type_option(new_field_type)
|
.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(
|
let transformed_type_option = transform_type_option(
|
||||||
&new_type_option,
|
&new_type_option,
|
||||||
@ -352,7 +352,7 @@ impl DatabaseEditor {
|
|||||||
) -> (Field, Bytes) {
|
) -> (Field, Bytes) {
|
||||||
let name = field_type.default_name();
|
let name = field_type.default_name();
|
||||||
let type_option_data = match type_option_data {
|
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),
|
Some(type_option_data) => type_option_data_from_pb_or_default(type_option_data, field_type),
|
||||||
};
|
};
|
||||||
let (index, field) =
|
let (index, field) =
|
||||||
@ -492,9 +492,23 @@ impl DatabaseEditor {
|
|||||||
) -> FlowyResult<()> {
|
) -> FlowyResult<()> {
|
||||||
// Get the old row before updating the cell. It would be better to get the old cell
|
// Get the old row before updating the cell. It would be better to get the old cell
|
||||||
let old_row = { self.database.lock().get_row(&row_id) };
|
let old_row = { self.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| {
|
self.database.lock().update_row(&row_id, |row_update| {
|
||||||
row_update.update_cells(|cell_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 {
|
// Collect all the updated field's id. Notify the frontend that all of them have been updated.
|
||||||
view_id: view_id.to_string(),
|
let mut updated_field_ids = updated_at_fields
|
||||||
row_id: row_id.into_inner(),
|
.into_iter()
|
||||||
field_id: field_id.to_string(),
|
.map(|field| field.id)
|
||||||
}])
|
.collect::<Vec<String>>();
|
||||||
.await;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
mod field_builder;
|
mod field_builder;
|
||||||
mod field_operation;
|
mod field_operation;
|
||||||
mod type_option_builder;
|
|
||||||
mod type_options;
|
mod type_options;
|
||||||
|
|
||||||
pub use field_builder::*;
|
pub use field_builder::*;
|
||||||
pub use field_operation::*;
|
pub use field_operation::*;
|
||||||
pub use type_option_builder::*;
|
|
||||||
pub use type_options::*;
|
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]
|
#[test]
|
||||||
fn date_type_option_date_format_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();
|
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
||||||
for date_format in DateFormat::iter() {
|
for date_format in DateFormat::iter() {
|
||||||
type_option.date_format = date_format;
|
type_option.date_format = date_format;
|
||||||
@ -95,7 +95,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn date_type_option_different_time_format_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();
|
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
||||||
|
|
||||||
for time_format in TimeFormat::iter() {
|
for time_format in TimeFormat::iter() {
|
||||||
@ -183,8 +183,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn date_type_option_invalid_date_str_test() {
|
fn date_type_option_invalid_date_str_test() {
|
||||||
let type_option = DateTypeOption::default();
|
|
||||||
let field_type = FieldType::DateTime;
|
let field_type = FieldType::DateTime;
|
||||||
|
let type_option = DateTypeOption::new(field_type.clone());
|
||||||
let field = FieldBuilder::from_field_type(field_type).build();
|
let field = FieldBuilder::from_field_type(field_type).build();
|
||||||
assert_date(
|
assert_date(
|
||||||
&type_option,
|
&type_option,
|
||||||
@ -203,8 +203,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn date_type_option_invalid_include_time_str_test() {
|
fn date_type_option_invalid_include_time_str_test() {
|
||||||
let type_option = DateTypeOption::new();
|
let field_type = FieldType::DateTime;
|
||||||
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
let type_option = DateTypeOption::new(field_type.clone());
|
||||||
|
let field = FieldBuilder::from_field_type(field_type).build();
|
||||||
|
|
||||||
assert_date(
|
assert_date(
|
||||||
&type_option,
|
&type_option,
|
||||||
@ -223,8 +224,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn date_type_option_empty_include_time_str_test() {
|
fn date_type_option_empty_include_time_str_test() {
|
||||||
let type_option = DateTypeOption::new();
|
let field_type = FieldType::DateTime;
|
||||||
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
let type_option = DateTypeOption::new(field_type.clone());
|
||||||
|
let field = FieldBuilder::from_field_type(field_type).build();
|
||||||
|
|
||||||
assert_date(
|
assert_date(
|
||||||
&type_option,
|
&type_option,
|
||||||
@ -242,8 +244,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn date_type_midnight_include_time_str_test() {
|
fn date_type_midnight_include_time_str_test() {
|
||||||
let type_option = DateTypeOption::new();
|
|
||||||
let field_type = FieldType::DateTime;
|
let field_type = FieldType::DateTime;
|
||||||
|
let type_option = DateTypeOption::new(field_type.clone());
|
||||||
let field = FieldBuilder::from_field_type(field_type).build();
|
let field = FieldBuilder::from_field_type(field_type).build();
|
||||||
assert_date(
|
assert_date(
|
||||||
&type_option,
|
&type_option,
|
||||||
@ -264,7 +266,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn date_type_option_twelve_hours_include_time_str_in_twenty_four_hours_format() {
|
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();
|
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
||||||
assert_date(
|
assert_date(
|
||||||
&type_option,
|
&type_option,
|
||||||
@ -285,9 +287,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn date_type_option_twenty_four_hours_include_time_str_in_twelve_hours_format() {
|
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;
|
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(
|
assert_date(
|
||||||
&type_option,
|
&type_option,
|
||||||
@ -335,7 +338,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn update_date_keep_time() {
|
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 field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
||||||
|
|
||||||
let old_cell_data = initialize_date_cell(
|
let old_cell_data = initialize_date_cell(
|
||||||
@ -363,7 +366,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn update_time_keep_date() {
|
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 field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
||||||
|
|
||||||
let old_cell_data = initialize_date_cell(
|
let old_cell_data = initialize_date_cell(
|
||||||
@ -391,7 +394,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn timezone_no_daylight_saving_time() {
|
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();
|
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
||||||
|
|
||||||
assert_date(
|
assert_date(
|
||||||
@ -422,7 +425,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn timezone_with_daylight_saving_time() {
|
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();
|
let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
||||||
|
|
||||||
assert_date(
|
assert_date(
|
||||||
@ -453,7 +456,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn change_timezone() {
|
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 field = FieldBuilder::from_field_type(FieldType::DateTime).build();
|
||||||
|
|
||||||
let old_cell_data = initialize_date_cell(
|
let old_cell_data = initialize_date_cell(
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use crate::entities::{DateCellDataPB, DateFilterPB, FieldType};
|
use crate::entities::{DateCellDataPB, DateFilterPB, FieldType};
|
||||||
use crate::services::cell::{CellDataChangeset, CellDataDecoder};
|
use crate::services::cell::{CellDataChangeset, CellDataDecoder};
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
default_order, DateCellChangeset, DateCellData, DateFormat, TimeFormat, TypeOption,
|
default_order, DateCellChangeset, DateCellData, DateCellDataWrapper, DateFormat, TimeFormat,
|
||||||
TypeOptionCellData, TypeOptionCellDataCompare, TypeOptionCellDataFilter, TypeOptionTransform,
|
TypeOption, TypeOptionCellData, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
||||||
|
TypeOptionTransform,
|
||||||
};
|
};
|
||||||
use chrono::format::strftime::StrftimeItems;
|
use chrono::format::strftime::StrftimeItems;
|
||||||
use chrono::{DateTime, Local, NaiveDateTime, NaiveTime, Offset, TimeZone};
|
use chrono::{DateTime, Local, NaiveDateTime, NaiveTime, Offset, TimeZone};
|
||||||
@ -15,11 +16,14 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
// Date
|
/// The [DateTypeOption] is used by [FieldType::Date], [FieldType::UpdatedAt], and [FieldType::CreatedAt].
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
/// 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 struct DateTypeOption {
|
||||||
pub date_format: DateFormat,
|
pub date_format: DateFormat,
|
||||||
pub time_format: TimeFormat,
|
pub time_format: TimeFormat,
|
||||||
|
pub field_type: FieldType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeOption for DateTypeOption {
|
impl TypeOption for DateTypeOption {
|
||||||
@ -39,9 +43,14 @@ impl From<TypeOptionData> for DateTypeOption {
|
|||||||
.get_i64_value("time_format")
|
.get_i64_value("time_format")
|
||||||
.map(TimeFormat::from)
|
.map(TimeFormat::from)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
let field_type = data
|
||||||
|
.get_i64_value("field_type")
|
||||||
|
.map(FieldType::from)
|
||||||
|
.unwrap_or(FieldType::DateTime);
|
||||||
Self {
|
Self {
|
||||||
date_format,
|
date_format,
|
||||||
time_format,
|
time_format,
|
||||||
|
field_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,6 +60,7 @@ impl From<DateTypeOption> for TypeOptionData {
|
|||||||
TypeOptionDataBuilder::new()
|
TypeOptionDataBuilder::new()
|
||||||
.insert_i64_value("data_format", data.date_format.value())
|
.insert_i64_value("data_format", data.date_format.value())
|
||||||
.insert_i64_value("time_format", data.time_format.value())
|
.insert_i64_value("time_format", data.time_format.value())
|
||||||
|
.insert_i64_value("field_type", data.field_type.value())
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,9 +79,12 @@ impl TypeOptionCellData for DateTypeOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DateTypeOption {
|
impl DateTypeOption {
|
||||||
#[allow(dead_code)]
|
pub fn new(field_type: FieldType) -> Self {
|
||||||
pub fn new() -> Self {
|
Self {
|
||||||
Self::default()
|
date_format: Default::default(),
|
||||||
|
time_format: Default::default(),
|
||||||
|
field_type,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn today_desc_from_timestamp(&self, cell_data: DateCellData) -> DateCellDataPB {
|
fn today_desc_from_timestamp(&self, cell_data: DateCellData) -> DateCellDataPB {
|
||||||
@ -179,8 +192,8 @@ impl CellDataChangeset for DateTypeOption {
|
|||||||
// old date cell data
|
// old date cell data
|
||||||
let (previous_timestamp, include_time, timezone_id) = match cell {
|
let (previous_timestamp, include_time, timezone_id) = match cell {
|
||||||
None => (None, false, "".to_owned()),
|
None => (None, false, "".to_owned()),
|
||||||
Some(type_cell_data) => {
|
Some(cell) => {
|
||||||
let cell_data = DateCellData::from(&type_cell_data);
|
let cell_data = DateCellData::from(&cell);
|
||||||
(
|
(
|
||||||
cell_data.timestamp,
|
cell_data.timestamp,
|
||||||
cell_data.include_time,
|
cell_data.include_time,
|
||||||
@ -201,7 +214,6 @@ impl CellDataChangeset for DateTypeOption {
|
|||||||
// in the changeset without an accompanying time string, the old timestamp
|
// in the changeset without an accompanying time string, the old timestamp
|
||||||
// will simply be overwritten. Meaning, in order to change the day without
|
// 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.
|
// changing the time, the old time string should be passed in as well.
|
||||||
|
|
||||||
let changeset_timestamp = changeset.date_timestamp();
|
let changeset_timestamp = changeset.date_timestamp();
|
||||||
|
|
||||||
// parse the time string, which is in the timezone corresponding to
|
// parse the time string, which is in the timezone corresponding to
|
||||||
@ -241,12 +253,14 @@ impl CellDataChangeset for DateTypeOption {
|
|||||||
changeset_timestamp,
|
changeset_timestamp,
|
||||||
);
|
);
|
||||||
|
|
||||||
let date_cell_data = DateCellData {
|
let cell_data = DateCellData {
|
||||||
timestamp,
|
timestamp,
|
||||||
include_time,
|
include_time,
|
||||||
timezone_id,
|
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 {
|
/// Wrapper for DateCellData that also contains the field type.
|
||||||
fn from(data: DateCellData) -> Self {
|
/// 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 {
|
let timestamp_string = match data.timestamp {
|
||||||
Some(timestamp) => timestamp.to_string(),
|
Some(timestamp) => timestamp.to_string(),
|
||||||
None => "".to_owned(),
|
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_str_value(CELL_DATA, timestamp_string)
|
||||||
.insert_bool_value("include_time", data.include_time)
|
.insert_bool_value("include_time", data.include_time)
|
||||||
.insert_str_value("timezone_id", data.timezone_id)
|
.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 {
|
impl<'de> serde::Deserialize<'de> for DateCellData {
|
||||||
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
|
@ -146,7 +146,7 @@ pub fn type_option_data_from_pb_or_default<T: Into<Bytes>>(
|
|||||||
FieldType::Number => {
|
FieldType::Number => {
|
||||||
NumberTypeOptionPB::try_from(bytes).map(|pb| NumberTypeOption::from(pb).into())
|
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())
|
DateTypeOptionPB::try_from(bytes).map(|pb| DateTypeOption::from(pb).into())
|
||||||
},
|
},
|
||||||
FieldType::SingleSelect => {
|
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 {
|
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()
|
.try_into()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
FieldType::DateTime => {
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
|
||||||
let date_type_option: DateTypeOption = type_option.into();
|
let date_type_option: DateTypeOption = type_option.into();
|
||||||
DateTypeOptionPB::from(date_type_option).try_into().unwrap()
|
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 {
|
match field_type {
|
||||||
FieldType::RichText => RichTextTypeOption::default().into(),
|
FieldType::RichText => RichTextTypeOption::default().into(),
|
||||||
FieldType::Number => NumberTypeOption::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::SingleSelect => SingleSelectTypeOption::default().into(),
|
||||||
FieldType::MultiSelect => MultiSelectTypeOption::default().into(),
|
FieldType::MultiSelect => MultiSelectTypeOption::default().into(),
|
||||||
FieldType::Checkbox => CheckboxTypeOption::default().into(),
|
FieldType::Checkbox => CheckboxTypeOption::default().into(),
|
||||||
|
@ -350,7 +350,7 @@ impl<'a> TypeOptionCellExt<'a> {
|
|||||||
self.cell_data_cache.clone(),
|
self.cell_data_cache.clone(),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
FieldType::DateTime => self
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => self
|
||||||
.field
|
.field
|
||||||
.get_type_option::<DateTypeOption>(field_type)
|
.get_type_option::<DateTypeOption>(field_type)
|
||||||
.map(|type_option| {
|
.map(|type_option| {
|
||||||
@ -470,7 +470,7 @@ fn get_type_option_transform_handler(
|
|||||||
FieldType::Number => {
|
FieldType::Number => {
|
||||||
Box::new(NumberTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
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>
|
Box::new(DateTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
},
|
},
|
||||||
FieldType::SingleSelect => Box::new(SingleSelectTypeOption::from(type_option_data))
|
FieldType::SingleSelect => Box::new(SingleSelectTypeOption::from(type_option_data))
|
||||||
|
@ -323,7 +323,7 @@ impl FilterController {
|
|||||||
.write()
|
.write()
|
||||||
.insert(field_id, NumberFilterPB::from_filter(filter.as_ref()));
|
.insert(field_id, NumberFilterPB::from_filter(filter.as_ref()));
|
||||||
},
|
},
|
||||||
FieldType::DateTime => {
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
|
||||||
self
|
self
|
||||||
.cell_filter_cache
|
.cell_filter_cache
|
||||||
.write()
|
.write()
|
||||||
|
@ -139,17 +139,7 @@ pub fn find_new_grouping_field(
|
|||||||
///
|
///
|
||||||
pub fn default_group_setting(field: &Field) -> GroupSetting {
|
pub fn default_group_setting(field: &Field) -> GroupSetting {
|
||||||
let field_id = field.id.clone();
|
let field_id = field.id.clone();
|
||||||
let field_type = FieldType::from(field.field_type);
|
GroupSetting::new(field_id, field.field_type, "".to_owned())
|
||||||
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()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_no_status_group(field: &Field) -> Group {
|
pub fn make_no_status_group(field: &Field) -> Group {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::entities::FieldType;
|
use crate::entities::FieldType;
|
||||||
use crate::services::cell::CellBuilder;
|
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::database::{gen_database_id, gen_database_view_id, gen_field_id, gen_row_id};
|
||||||
use collab_database::fields::Field;
|
use collab_database::fields::Field;
|
||||||
use collab_database::rows::CreateRowParams;
|
use collab_database::rows::CreateRowParams;
|
||||||
@ -73,7 +73,7 @@ fn database_from_fields_and_rows(fields_and_rows: FieldsRows) -> CreateDatabaseP
|
|||||||
Ok(field) => field,
|
Ok(field) => field,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let field_type = FieldType::RichText;
|
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;
|
let is_primary = index == 0;
|
||||||
Field::new(
|
Field::new(
|
||||||
gen_field_id(),
|
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::entities::{CellChangesetPB, FieldType};
|
||||||
use flowy_database2::services::cell::ToCellChangeset;
|
use flowy_database2::services::cell::ToCellChangeset;
|
||||||
use flowy_database2::services::field::{
|
use flowy_database2::services::field::{
|
||||||
ChecklistTypeOption, MultiSelectTypeOption, SelectOptionCellChangeset, SingleSelectTypeOption,
|
ChecklistTypeOption, DateCellData, MultiSelectTypeOption, SelectOptionCellChangeset,
|
||||||
StrCellData, URLCellData,
|
SingleSelectTypeOption, StrCellData, URLCellData,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::database::cell_test::script::CellScript::UpdateCell;
|
use crate::database::cell_test::script::CellScript::UpdateCell;
|
||||||
@ -22,7 +22,9 @@ async fn grid_cell_update() {
|
|||||||
let cell_changeset = match field_type {
|
let cell_changeset = match field_type {
|
||||||
FieldType::RichText => "".to_string(),
|
FieldType::RichText => "".to_string(),
|
||||||
FieldType::Number => "123".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 => {
|
FieldType::SingleSelect => {
|
||||||
let type_option = field
|
let type_option = field
|
||||||
.get_type_option::<SingleSelectTypeOption>(field.field_type)
|
.get_type_option::<SingleSelectTypeOption>(field.field_type)
|
||||||
@ -64,7 +66,7 @@ async fn grid_cell_update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn text_cell_date_test() {
|
async fn text_cell_data_test() {
|
||||||
let test = DatabaseCellTest::new().await;
|
let test = DatabaseCellTest::new().await;
|
||||||
let text_field = test.get_first_field(FieldType::RichText);
|
let text_field = test.get_first_field(FieldType::RichText);
|
||||||
|
|
||||||
@ -88,7 +90,7 @@ async fn text_cell_date_test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn url_cell_date_test() {
|
async fn url_cell_data_test() {
|
||||||
let test = DatabaseCellTest::new().await;
|
let test = DatabaseCellTest::new().await;
|
||||||
let url_field = test.get_first_field(FieldType::URL);
|
let url_field = test.get_first_field(FieldType::URL);
|
||||||
let cells = test
|
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>,
|
time: Option<String>,
|
||||||
include_time: Option<bool>,
|
include_time: Option<bool>,
|
||||||
timezone_id: Option<String>,
|
timezone_id: Option<String>,
|
||||||
|
field_type: &FieldType,
|
||||||
) -> String {
|
) -> String {
|
||||||
let value = serde_json::to_string(&DateCellChangeset {
|
let value = serde_json::to_string(&DateCellChangeset {
|
||||||
date: Some(data.to_string()),
|
date: Some(data.to_string()),
|
||||||
@ -285,7 +286,7 @@ impl<'a> TestRowBuilder<'a> {
|
|||||||
timezone_id,
|
timezone_id,
|
||||||
})
|
})
|
||||||
.unwrap();
|
.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);
|
self.cell_build.insert_text_cell(&date_field.id, value);
|
||||||
date_field.id.clone()
|
date_field.id.clone()
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,16 @@ async fn grid_create_field() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
test.run_scripts(scripts).await;
|
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]
|
#[tokio::test]
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use collab_database::fields::Field;
|
use collab_database::fields::Field;
|
||||||
use flowy_database2::entities::{CreateFieldParams, FieldType};
|
use flowy_database2::entities::{CreateFieldParams, FieldType};
|
||||||
use flowy_database2::services::field::{
|
use flowy_database2::services::field::{
|
||||||
type_option_to_pb, DateCellChangeset, FieldBuilder, RichTextTypeOption, SelectOption,
|
type_option_to_pb, DateCellChangeset, DateFormat, DateTypeOption, FieldBuilder,
|
||||||
SingleSelectTypeOption,
|
RichTextTypeOption, SelectOption, SingleSelectTypeOption, TimeFormat,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn create_text_field(grid_id: &str) -> (CreateFieldParams, Field) {
|
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)
|
(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.
|
// 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 {
|
pub fn make_date_cell_string(s: &str) -> String {
|
||||||
|
@ -38,14 +38,21 @@ pub fn make_test_board() -> DatabaseData {
|
|||||||
.build();
|
.build();
|
||||||
fields.push(number_field);
|
fields.push(number_field);
|
||||||
},
|
},
|
||||||
FieldType::DateTime => {
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
|
||||||
// Date
|
// Date
|
||||||
let date_type_option = DateTypeOption {
|
let date_type_option = DateTypeOption {
|
||||||
date_format: DateFormat::US,
|
date_format: DateFormat::US,
|
||||||
time_format: TimeFormat::TwentyFourHour,
|
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)
|
let date_field = FieldBuilder::new(field_type.clone(), date_type_option)
|
||||||
.name("Time")
|
.name(name)
|
||||||
.visibility(true)
|
.visibility(true)
|
||||||
.build();
|
.build();
|
||||||
fields.push(date_field);
|
fields.push(date_field);
|
||||||
@ -119,12 +126,14 @@ pub fn make_test_board() -> DatabaseData {
|
|||||||
FieldType::RichText => row_builder.insert_text_cell("A"),
|
FieldType::RichText => row_builder.insert_text_cell("A"),
|
||||||
FieldType::Number => row_builder.insert_number_cell("1"),
|
FieldType::Number => row_builder.insert_number_cell("1"),
|
||||||
// 1647251762 => Mar 14,2022
|
// 1647251762 => Mar 14,2022
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1647251762",
|
.insert_date_cell(
|
||||||
None,
|
"1647251762",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
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::RichText => row_builder.insert_text_cell("B"),
|
||||||
FieldType::Number => row_builder.insert_number_cell("2"),
|
FieldType::Number => row_builder.insert_number_cell("2"),
|
||||||
// 1647251762 => Mar 14,2022
|
// 1647251762 => Mar 14,2022
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1647251762",
|
.insert_date_cell(
|
||||||
None,
|
"1647251762",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
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::RichText => row_builder.insert_text_cell("C"),
|
||||||
FieldType::Number => row_builder.insert_number_cell("3"),
|
FieldType::Number => row_builder.insert_number_cell("3"),
|
||||||
// 1647251762 => Mar 14,2022
|
// 1647251762 => Mar 14,2022
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1647251762",
|
.insert_date_cell(
|
||||||
None,
|
"1647251762",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
||||||
},
|
},
|
||||||
@ -189,12 +202,14 @@ pub fn make_test_board() -> DatabaseData {
|
|||||||
match field_type {
|
match field_type {
|
||||||
FieldType::RichText => row_builder.insert_text_cell("DA"),
|
FieldType::RichText => row_builder.insert_text_cell("DA"),
|
||||||
FieldType::Number => row_builder.insert_number_cell("4"),
|
FieldType::Number => row_builder.insert_number_cell("4"),
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1668704685",
|
.insert_date_cell(
|
||||||
None,
|
"1668704685",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
||||||
},
|
},
|
||||||
@ -209,12 +224,14 @@ pub fn make_test_board() -> DatabaseData {
|
|||||||
match field_type {
|
match field_type {
|
||||||
FieldType::RichText => row_builder.insert_text_cell("AE"),
|
FieldType::RichText => row_builder.insert_text_cell("AE"),
|
||||||
FieldType::Number => row_builder.insert_number_cell(""),
|
FieldType::Number => row_builder.insert_number_cell(""),
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1668359085",
|
.insert_date_cell(
|
||||||
None,
|
"1668359085",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
row_builder.insert_single_select_cell(|mut options| options.remove(2))
|
row_builder.insert_single_select_cell(|mut options| options.remove(2))
|
||||||
},
|
},
|
||||||
|
@ -51,6 +51,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
),
|
),
|
||||||
_ => "".to_owned(),
|
_ => "".to_owned(),
|
||||||
};
|
};
|
||||||
@ -65,6 +66,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
),
|
),
|
||||||
_ => "".to_owned(),
|
_ => "".to_owned(),
|
||||||
};
|
};
|
||||||
@ -79,6 +81,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
),
|
),
|
||||||
_ => "".to_owned(),
|
_ => "".to_owned(),
|
||||||
};
|
};
|
||||||
@ -93,6 +96,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
),
|
),
|
||||||
_ => "".to_owned(),
|
_ => "".to_owned(),
|
||||||
};
|
};
|
||||||
@ -107,6 +111,7 @@ pub fn make_test_calendar() -> DatabaseData {
|
|||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
),
|
),
|
||||||
_ => "".to_owned(),
|
_ => "".to_owned(),
|
||||||
};
|
};
|
||||||
|
@ -39,14 +39,21 @@ pub fn make_test_grid() -> DatabaseData {
|
|||||||
.build();
|
.build();
|
||||||
fields.push(number_field);
|
fields.push(number_field);
|
||||||
},
|
},
|
||||||
FieldType::DateTime => {
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => {
|
||||||
// Date
|
// Date
|
||||||
let date_type_option = DateTypeOption {
|
let date_type_option = DateTypeOption {
|
||||||
date_format: DateFormat::US,
|
date_format: DateFormat::US,
|
||||||
time_format: TimeFormat::TwentyFourHour,
|
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)
|
let date_field = FieldBuilder::new(field_type.clone(), date_type_option)
|
||||||
.name("Time")
|
.name(name)
|
||||||
.visibility(true)
|
.visibility(true)
|
||||||
.build();
|
.build();
|
||||||
fields.push(date_field);
|
fields.push(date_field);
|
||||||
@ -118,12 +125,14 @@ pub fn make_test_grid() -> DatabaseData {
|
|||||||
match field_type {
|
match field_type {
|
||||||
FieldType::RichText => row_builder.insert_text_cell("A"),
|
FieldType::RichText => row_builder.insert_text_cell("A"),
|
||||||
FieldType::Number => row_builder.insert_number_cell("1"),
|
FieldType::Number => row_builder.insert_number_cell("1"),
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1647251762",
|
.insert_date_cell(
|
||||||
None,
|
"1647251762",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::MultiSelect => row_builder
|
FieldType::MultiSelect => row_builder
|
||||||
.insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(0)]),
|
.insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(0)]),
|
||||||
FieldType::Checklist => row_builder.insert_checklist_cell(|options| options),
|
FieldType::Checklist => row_builder.insert_checklist_cell(|options| options),
|
||||||
@ -140,12 +149,14 @@ pub fn make_test_grid() -> DatabaseData {
|
|||||||
match field_type {
|
match field_type {
|
||||||
FieldType::RichText => row_builder.insert_text_cell(""),
|
FieldType::RichText => row_builder.insert_text_cell(""),
|
||||||
FieldType::Number => row_builder.insert_number_cell("2"),
|
FieldType::Number => row_builder.insert_number_cell("2"),
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1647251762",
|
.insert_date_cell(
|
||||||
None,
|
"1647251762",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::MultiSelect => row_builder
|
FieldType::MultiSelect => row_builder
|
||||||
.insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(1)]),
|
.insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(1)]),
|
||||||
FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
|
FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
|
||||||
@ -158,12 +169,14 @@ pub fn make_test_grid() -> DatabaseData {
|
|||||||
match field_type {
|
match field_type {
|
||||||
FieldType::RichText => row_builder.insert_text_cell("C"),
|
FieldType::RichText => row_builder.insert_text_cell("C"),
|
||||||
FieldType::Number => row_builder.insert_number_cell("3"),
|
FieldType::Number => row_builder.insert_number_cell("3"),
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1647251762",
|
.insert_date_cell(
|
||||||
None,
|
"1647251762",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
||||||
},
|
},
|
||||||
@ -180,12 +193,14 @@ pub fn make_test_grid() -> DatabaseData {
|
|||||||
match field_type {
|
match field_type {
|
||||||
FieldType::RichText => row_builder.insert_text_cell("DA"),
|
FieldType::RichText => row_builder.insert_text_cell("DA"),
|
||||||
FieldType::Number => row_builder.insert_number_cell("14"),
|
FieldType::Number => row_builder.insert_number_cell("14"),
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1668704685",
|
.insert_date_cell(
|
||||||
None,
|
"1668704685",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
row_builder.insert_single_select_cell(|mut options| options.remove(0))
|
||||||
},
|
},
|
||||||
@ -199,12 +214,14 @@ pub fn make_test_grid() -> DatabaseData {
|
|||||||
match field_type {
|
match field_type {
|
||||||
FieldType::RichText => row_builder.insert_text_cell("AE"),
|
FieldType::RichText => row_builder.insert_text_cell("AE"),
|
||||||
FieldType::Number => row_builder.insert_number_cell(""),
|
FieldType::Number => row_builder.insert_number_cell(""),
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1668359085",
|
.insert_date_cell(
|
||||||
None,
|
"1668359085",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
||||||
},
|
},
|
||||||
@ -219,12 +236,14 @@ pub fn make_test_grid() -> DatabaseData {
|
|||||||
match field_type {
|
match field_type {
|
||||||
FieldType::RichText => row_builder.insert_text_cell("AE"),
|
FieldType::RichText => row_builder.insert_text_cell("AE"),
|
||||||
FieldType::Number => row_builder.insert_number_cell("5"),
|
FieldType::Number => row_builder.insert_number_cell("5"),
|
||||||
FieldType::DateTime => row_builder.insert_date_cell(
|
FieldType::DateTime | FieldType::UpdatedAt | FieldType::CreatedAt => row_builder
|
||||||
"1671938394",
|
.insert_date_cell(
|
||||||
None,
|
"1671938394",
|
||||||
None,
|
None,
|
||||||
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
None,
|
||||||
),
|
Some(chrono_tz::Tz::Etc__GMTPlus8.to_string()),
|
||||||
|
&field_type,
|
||||||
|
),
|
||||||
FieldType::SingleSelect => {
|
FieldType::SingleSelect => {
|
||||||
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
row_builder.insert_single_select_cell(|mut options| options.remove(1))
|
||||||
},
|
},
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
mod block_test;
|
||||||
mod cell_test;
|
mod cell_test;
|
||||||
mod database_editor;
|
mod database_editor;
|
||||||
mod field_test;
|
mod field_test;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user