Bläddra i källkod

feat: clear date value (#2700)

* chore: Add _ClearDateFieldButton

* chore: Add new DateCellCalendarEvent to clear date

* chore: Add grid_field_clearDate translation token

* refactor: _ClearDateFieldButton -> _ClearDateButton

* fix: Fix dart(unused_element) in _ClearDateButton

* feat: Handle clearDate

* Revert "feat: Handle clearDate"

This reverts commit fd145ef8e9589f3b4aa1a16e5d72c15b6d0b53c4.

* feat: Handle clearDate

* feat: Add clear_flag field

* feat: check clear_flag to clear date

* chore: update exisitng tests

* fix: add mssing import

* refactor: remove check for timeFormatError

* fix: fix margin on _ClearDateButton

* refactor: _ClearDateButton -> ClearDateButton

* test: add clear date backend unit test

* test: add clear date integration test

* test: add clear date to edit time cell test

* chore: mark ClearDateButton visible for testing

* feat: close date editor popover on clear date

* style: make AppFlowyPopover taller

* fix: trim dateStr in _dateStrFromCellData

* fix: don't dismiss CellEditor after clearDate
dejvizelo 1 år sedan
förälder
incheckning
f28c5d849c
17 ändrade filer med 187 tillägg och 30 borttagningar
  1. 12 0
      frontend/appflowy_flutter/integration_test/database_cell_test.dart
  2. 26 17
      frontend/appflowy_flutter/integration_test/util/database_test_op.dart
  3. 4 0
      frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_data_persistence.dart
  4. 34 5
      frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_cal_bloc.dart
  5. 2 2
      frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_cell.dart
  6. 4 2
      frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_cell_bloc.dart
  7. 33 4
      frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_editor.dart
  8. 1 0
      frontend/resources/translations/en.json
  9. 3 0
      frontend/rust-lib/flowy-database2/src/entities/type_option_entities/date_entities.rs
  10. 1 0
      frontend/rust-lib/flowy-database2/src/event_handler.rs
  11. 1 0
      frontend/rust-lib/flowy-database2/src/services/cell/cell_operation.rs
  12. 49 0
      frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_tests.rs
  13. 12 0
      frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_type_option.rs
  14. 1 0
      frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_type_option_entities.rs
  15. 1 0
      frontend/rust-lib/flowy-database2/tests/database/database_editor.rs
  16. 1 0
      frontend/rust-lib/flowy-database2/tests/database/field_test/util.rs
  17. 2 0
      frontend/rust-lib/flowy-test/tests/database/local_test/test.rs

+ 12 - 0
frontend/appflowy_flutter/integration_test/database_cell_test.dart

@@ -268,6 +268,18 @@ void main() {
         content: DateFormat('dd/MM/y hh:mm a').format(now),
       );
 
+      await tester.tapCellInGrid(rowIndex: 0, fieldType: fieldType);
+      await tester.findDateEditor(findsOneWidget);
+
+      // Clear the date and time
+      await tester.clearDate();
+
+      await tester.assertDateCellInGrid(
+        rowIndex: 0,
+        fieldType: fieldType,
+        content: '',
+      );
+
       await tester.pumpAndSettle();
     });
 

+ 26 - 17
frontend/appflowy_flutter/integration_test/util/database_test_op.dart

@@ -6,6 +6,7 @@ import 'package:appflowy/plugins/database_view/calendar/application/calendar_blo
 import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_day.dart';
 import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
 import 'package:appflowy/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart';
+import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checkbox.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/checklist/checklist.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/choicechip/select_option/option_list.dart';
@@ -14,31 +15,42 @@ import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/create_filter_list.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/disclosure_button.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/filter_menu_item.dart';
+import 'package:appflowy/plugins/database_view/grid/presentation/widgets/footer/grid_footer.dart';
+import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_cell.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_cell_action_sheet.dart';
+import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_editor.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_extension.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_list.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_option_editor.dart';
+import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart';
+import 'package:appflowy/plugins/database_view/grid/presentation/widgets/row/row.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/create_sort_list.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/order_panel.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/sort_editor.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/sort/sort_menu.dart';
-import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/type_option/date.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/filter_button.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/grid_layout.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/toolbar/sort_button.dart';
 import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_view.dart';
 import 'package:appflowy/plugins/database_view/tar_bar/tar_bar_add_button.dart';
 import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart';
+import 'package:appflowy/plugins/database_view/widgets/row/accessory/cell_accessory.dart';
+import 'package:appflowy/plugins/database_view/widgets/row/cells/cells.dart';
+import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_progress_bar.dart';
+import 'package:appflowy/plugins/database_view/widgets/row/cells/date_cell/date_editor.dart';
 import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
 import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/select_option_editor.dart';
 import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/text_field.dart';
-import 'package:appflowy/plugins/database_view/widgets/row/cells/checklist_cell/checklist_progress_bar.dart';
+import 'package:appflowy/plugins/database_view/widgets/row/row_action.dart';
+import 'package:appflowy/plugins/database_view/widgets/row/row_banner.dart';
+import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
 import 'package:appflowy/plugins/database_view/widgets/row/row_document.dart';
-import 'package:appflowy/plugins/database_view/widgets/row/cells/date_cell/date_editor.dart';
 import 'package:appflowy/plugins/database_view/widgets/setting/database_setting.dart';
 import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart';
+import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_picker/emoji_menu_item.dart';
 import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
 import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
+import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
 import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart';
 import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
 import 'package:calendar_view/calendar_view.dart';
@@ -50,25 +62,12 @@ import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
-import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
-import 'package:appflowy/plugins/database_view/grid/presentation/widgets/footer/grid_footer.dart';
-import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_cell.dart';
-import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_editor.dart';
-import 'package:appflowy/plugins/database_view/grid/presentation/widgets/row/row.dart';
-import 'package:appflowy/plugins/database_view/widgets/row/accessory/cell_accessory.dart';
-import 'package:appflowy/plugins/database_view/widgets/row/cells/cells.dart';
-import 'package:appflowy/plugins/database_view/widgets/row/row_action.dart';
-import 'package:appflowy/plugins/database_view/widgets/row/row_banner.dart';
-import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
-import 'package:appflowy/plugins/document/presentation/editor_plugins/emoji_picker/emoji_menu_item.dart';
-import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
+import 'package:path/path.dart' as p;
 import 'package:table_calendar/table_calendar.dart';
 
 import 'base.dart';
 import 'common_operations.dart';
 import 'expectation.dart';
-import 'package:path/path.dart' as p;
-
 import 'mock/mock_file_picker.dart';
 
 extension AppFlowyDatabaseTest on WidgetTester {
@@ -358,6 +357,16 @@ extension AppFlowyDatabaseTest on WidgetTester {
     await tapButton(findNewDateFormat);
   }
 
+  Future<void> clearDate() async {
+    final findDateEditor = find.byType(DateCellEditor);
+    final findClearButton = find.byType(ClearDateButton);
+    final finder = find.descendant(
+      of: findDateEditor,
+      matching: findClearButton,
+    );
+    await tapButton(finder);
+  }
+
   Future<void> tapSelectOptionCellInGrid({
     required int rowIndex,
     required FieldType fieldType,

+ 4 - 0
frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_data_persistence.dart

@@ -35,6 +35,7 @@ class DateCellData with _$DateCellData {
     DateTime? dateTime,
     String? time,
     required bool includeTime,
+    bool? clearFlag,
   }) = _DateCellData;
 }
 
@@ -55,6 +56,9 @@ class DateCellDataPersistence implements CellDataPersistence<DateCellData> {
     if (data.time != null) {
       payload.time = data.time!;
     }
+    if (data.clearFlag != null) {
+      payload.clearFlag = data.clearFlag!;
+    }
     payload.includeTime = data.includeTime;
 
     return DatabaseEventUpdateDateCell(payload).send().then((result) {

+ 34 - 5
frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_cal_bloc.dart

@@ -1,18 +1,19 @@
+import 'dart:async';
+
 import 'package:appflowy/generated/locale_keys.g.dart';
 import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
-import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
-import 'package:easy_localization/easy_localization.dart'
-    show StringTranslateExtension;
 import 'package:appflowy_backend/log.dart';
+import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
 import 'package:appflowy_backend/protobuf/flowy-error/code.pb.dart';
 import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
+import 'package:easy_localization/easy_localization.dart'
+    show StringTranslateExtension;
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
-import 'package:table_calendar/table_calendar.dart';
-import 'dart:async';
 import 'package:protobuf/protobuf.dart';
+import 'package:table_calendar/table_calendar.dart';
 
 part 'date_cal_bloc.freezed.dart';
 
@@ -64,6 +65,9 @@ class DateCellCalendarBloc
           setFocusedDay: (focusedDay) {
             emit(state.copyWith(focusedDay: focusedDay));
           },
+          clearDate: () async {
+            await _clearDate(emit);
+          },
         );
       },
     );
@@ -121,6 +125,29 @@ class DateCellCalendarBloc
     );
   }
 
+  Future<void> _clearDate(Emitter<DateCellCalendarState> emit) async {
+    final DateCellData newDateData = DateCellData(
+      dateTime: null,
+      time: null,
+      includeTime: state.includeTime,
+      clearFlag: true,
+    );
+
+    cellController.saveCellData(
+      newDateData,
+      onFinish: (result) {
+        result.fold(
+          () {
+            if (!isClosed) {
+              add(const DateCellCalendarEvent.didReceiveTimeFormatError(null));
+            }
+          },
+          (err) => Log.error(err),
+        );
+      },
+    );
+  }
+
   DateTime? _utcToLocalAddTime(DateTime? date) {
     if (date == null) {
       return null;
@@ -237,6 +264,8 @@ class DateCellCalendarEvent with _$DateCellCalendarEvent {
       _TimeFormat;
   const factory DateCellCalendarEvent.setDateFormat(DateFormatPB dateFormat) =
       _DateFormat;
+
+  const factory DateCellCalendarEvent.clearDate() = _ClearDate;
 }
 
 @freezed

+ 2 - 2
frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_cell.dart

@@ -1,9 +1,9 @@
 import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
+import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:appflowy_popover/appflowy_popover.dart';
 
 import '../../../../grid/presentation/layout/sizes.dart';
 import '../../cell_builder.dart';
@@ -83,7 +83,7 @@ class _DateCellState extends GridCellState<GridDateCell> {
               controller: _popover,
               triggerActions: PopoverTriggerFlags.none,
               direction: PopoverDirection.bottomWithLeftAligned,
-              constraints: BoxConstraints.loose(const Size(260, 500)),
+              constraints: BoxConstraints.loose(const Size(260, 520)),
               margin: EdgeInsets.zero,
               child: dateTextWidget,
               popupBuilder: (BuildContext popoverContent) {

+ 4 - 2
frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_cell_bloc.dart

@@ -1,9 +1,11 @@
+import 'dart:async';
+
 import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
 import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
-import 'dart:async';
+
 part 'date_cell_bloc.freezed.dart';
 
 class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
@@ -85,5 +87,5 @@ String _dateStrFromCellData(DateCellDataPB? cellData) {
       dateStr = cellData.date;
     }
   }
-  return dateStr;
+  return dateStr.trim();
 }

+ 33 - 4
frontend/appflowy_flutter/lib/plugins/database_view/widgets/row/cells/date_cell/date_editor.dart

@@ -3,20 +3,21 @@ import 'package:appflowy/plugins/database_view/application/cell/cell_controller_
 import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
 import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
 import 'package:appflowy/workspace/presentation/widgets/toggle/toggle_style.dart';
+import 'package:appflowy_backend/log.dart';
 import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pb.dart';
+import 'package:appflowy_backend/protobuf/flowy-error/errors.pbserver.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:dartz/dartz.dart' show Either;
 import 'package:easy_localization/easy_localization.dart';
-import 'package:flowy_infra/theme_extension.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/size.dart';
+import 'package:flowy_infra/theme_extension.dart';
 import 'package:flowy_infra/time/duration.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
-import 'package:appflowy_backend/log.dart';
-import 'package:appflowy_backend/protobuf/flowy-error/errors.pbserver.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:table_calendar/table_calendar.dart';
+
 import '../../../../grid/presentation/layout/sizes.dart';
 import '../../../../grid/presentation/widgets/common/type_option_separator.dart';
 import '../../../../grid/presentation/widgets/header/type_option/date.dart';
@@ -123,7 +124,9 @@ class _CellCalendarWidgetState extends State<_CellCalendarWidget> {
             const TypeOptionSeparator(spacing: 12.0),
             const _IncludeTimeButton(),
             const TypeOptionSeparator(spacing: 12.0),
-            DateTypeOptionButton(popoverMutex: popoverMutex)
+            DateTypeOptionButton(popoverMutex: popoverMutex),
+            const TypeOptionSeparator(spacing: 12.0),
+            const ClearDateButton(),
           ];
 
           return ListView.builder(
@@ -458,3 +461,29 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
     );
   }
 }
+
+@visibleForTesting
+class ClearDateButton extends StatelessWidget {
+  const ClearDateButton({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Padding(
+      padding: const EdgeInsets.symmetric(horizontal: 12.0),
+      child: SizedBox(
+        height: GridSize.popoverItemHeight,
+        child: FlowyButton(
+          text: FlowyText.medium(LocaleKeys.grid_field_clearDate.tr()),
+          onTap: () {
+            context
+                .read<DateCellCalendarBloc>()
+                .add(const DateCellCalendarEvent.clearDate());
+            PopoverContainer.of(context).close();
+          },
+          leftIcon: const FlowySvg(name: "grid/delete"),
+          margin: GridSize.typeOptionContentInsets,
+        ),
+      ),
+    );
+  }
+}

+ 1 - 0
frontend/resources/translations/en.json

@@ -378,6 +378,7 @@
       "invalidTimeFormat": "Invalid format",
       "timeFormatTwelveHour": "12 hour",
       "timeFormatTwentyFourHour": "24 hour",
+      "clearDate": "Clear date",
       "addSelectOption": "Add an option",
       "optionTitle": "Options",
       "addOption": "Add option",

+ 3 - 0
frontend/rust-lib/flowy-database2/src/entities/type_option_entities/date_entities.rs

@@ -35,6 +35,9 @@ pub struct DateChangesetPB {
 
   #[pb(index = 4, one_of)]
   pub include_time: Option<bool>,
+
+  #[pb(index = 5, one_of)]
+  pub clear_flag: Option<bool>,
 }
 
 // Date

+ 1 - 0
frontend/rust-lib/flowy-database2/src/event_handler.rs

@@ -640,6 +640,7 @@ pub(crate) async fn update_date_cell_handler(
     date: data.date,
     time: data.time,
     include_time: data.include_time,
+    clear_flag: data.clear_flag,
   };
   let database_editor = manager.get_database_with_view_id(&cell_id.view_id).await?;
   database_editor

+ 1 - 0
frontend/rust-lib/flowy-database2/src/services/cell/cell_operation.rs

@@ -212,6 +212,7 @@ pub fn insert_date_cell(timestamp: i64, include_time: Option<bool>, field: &Fiel
     date: Some(timestamp.to_string()),
     time: None,
     include_time,
+    clear_flag: None,
   })
   .unwrap();
   apply_cell_changeset(cell_data, None, field, None).unwrap()

+ 49 - 0
frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_tests.rs

@@ -27,6 +27,7 @@ mod tests {
               date: Some("1647251762".to_owned()),
               time: None,
               include_time: None,
+              clear_flag: None,
             },
             None,
             "Mar 14, 2022",
@@ -40,6 +41,7 @@ mod tests {
               date: Some("1647251762".to_owned()),
               time: None,
               include_time: None,
+              clear_flag: None,
             },
             None,
             "2022/03/14",
@@ -53,6 +55,7 @@ mod tests {
               date: Some("1647251762".to_owned()),
               time: None,
               include_time: None,
+              clear_flag: None,
             },
             None,
             "2022-03-14",
@@ -66,6 +69,7 @@ mod tests {
               date: Some("1647251762".to_owned()),
               time: None,
               include_time: None,
+              clear_flag: None,
             },
             None,
             "03/14/2022",
@@ -79,6 +83,7 @@ mod tests {
               date: Some("1647251762".to_owned()),
               time: None,
               include_time: None,
+              clear_flag: None,
             },
             None,
             "14/03/2022",
@@ -104,6 +109,7 @@ mod tests {
               date: Some("1653609600".to_owned()),
               time: None,
               include_time: Some(true),
+              clear_flag: None,
             },
             None,
             "May 27, 2022 00:00",
@@ -115,6 +121,7 @@ mod tests {
               date: Some("1653609600".to_owned()),
               time: Some("9:00".to_owned()),
               include_time: Some(true),
+              clear_flag: None,
             },
             None,
             "May 27, 2022 09:00",
@@ -126,6 +133,7 @@ mod tests {
               date: Some("1653609600".to_owned()),
               time: Some("23:00".to_owned()),
               include_time: Some(true),
+              clear_flag: None,
             },
             None,
             "May 27, 2022 23:00",
@@ -139,6 +147,7 @@ mod tests {
               date: Some("1653609600".to_owned()),
               time: None,
               include_time: Some(true),
+              clear_flag: None,
             },
             None,
             "May 27, 2022 12:00 AM",
@@ -150,6 +159,7 @@ mod tests {
               date: Some("1653609600".to_owned()),
               time: Some("9:00 AM".to_owned()),
               include_time: Some(true),
+              clear_flag: None,
             },
             None,
             "May 27, 2022 09:00 AM",
@@ -161,6 +171,7 @@ mod tests {
               date: Some("1653609600".to_owned()),
               time: Some("11:23 pm".to_owned()),
               include_time: Some(true),
+              clear_flag: None,
             },
             None,
             "May 27, 2022 11:23 PM",
@@ -182,6 +193,7 @@ mod tests {
         date: Some("abc".to_owned()),
         time: None,
         include_time: None,
+        clear_flag: None,
       },
       None,
       "",
@@ -202,6 +214,7 @@ mod tests {
         date: Some("1653609600".to_owned()),
         time: Some("1:".to_owned()),
         include_time: Some(true),
+        clear_flag: None,
       },
       None,
       "May 27, 2022 01:00",
@@ -222,6 +235,7 @@ mod tests {
         date: Some("1653609600".to_owned()),
         time: Some("".to_owned()),
         include_time: Some(true),
+        clear_flag: None,
       },
       None,
       "May 27, 2022 01:00",
@@ -240,6 +254,7 @@ mod tests {
         date: Some("1653609600".to_owned()),
         time: Some("00:00".to_owned()),
         include_time: Some(true),
+        clear_flag: None,
       },
       None,
       "May 27, 2022 00:00",
@@ -260,6 +275,7 @@ mod tests {
         date: Some("1653609600".to_owned()),
         time: Some("1:00 am".to_owned()),
         include_time: Some(true),
+        clear_flag: None,
       },
       None,
       "May 27, 2022 01:00 AM",
@@ -283,6 +299,7 @@ mod tests {
         date: Some("1653609600".to_owned()),
         time: Some("20:00".to_owned()),
         include_time: Some(true),
+        clear_flag: None,
       },
       None,
       "May 27, 2022 08:00 PM",
@@ -330,6 +347,7 @@ mod tests {
         date: Some("1700006400".to_owned()),
         time: Some("08:00".to_owned()),
         include_time: Some(true),
+        clear_flag: None,
       },
     );
     assert_date(
@@ -339,6 +357,7 @@ mod tests {
         date: Some("1701302400".to_owned()),
         time: None,
         include_time: None,
+        clear_flag: None,
       },
       Some(old_cell_data),
       "Nov 30, 2023 08:00",
@@ -356,6 +375,7 @@ mod tests {
         date: Some("1700006400".to_owned()),
         time: Some("08:00".to_owned()),
         include_time: Some(true),
+        clear_flag: None,
       },
     );
     assert_date(
@@ -365,12 +385,41 @@ mod tests {
         date: None,
         time: Some("14:00".to_owned()),
         include_time: None,
+        clear_flag: None,
       },
       Some(old_cell_data),
       "Nov 15, 2023 14:00",
     );
   }
 
+  #[test]
+  fn clear_date() {
+    let type_option = DateTypeOption::test();
+    let field = FieldBuilder::from_field_type(FieldType::DateTime).build();
+
+    let old_cell_data = initialize_date_cell(
+      &type_option,
+      DateCellChangeset {
+        date: Some("1700006400".to_owned()),
+        time: Some("08:00".to_owned()),
+        include_time: Some(true),
+        clear_flag: None,
+      },
+    );
+    assert_date(
+      &type_option,
+      &field,
+      DateCellChangeset {
+        date: None,
+        time: None,
+        include_time: Some(true),
+        clear_flag: Some(true),
+      },
+      Some(old_cell_data),
+      "",
+    );
+  }
+
   fn assert_date(
     type_option: &DateTypeOption,
     field: &Field,

+ 12 - 0
frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_type_option.rs

@@ -232,6 +232,18 @@ impl CellDataChangeset for DateTypeOption {
       None => (None, false),
     };
 
+    if changeset.clear_flag == Some(true) {
+      let (timestamp, include_time) = (None, include_time);
+
+      let cell_data = DateCellData {
+        timestamp,
+        include_time,
+      };
+
+      let cell_wrapper: DateCellDataWrapper = (self.field_type.clone(), cell_data.clone()).into();
+      return Ok((Cell::from(cell_wrapper), cell_data));
+    }
+
     // update include_time if necessary
     let include_time = changeset.include_time.unwrap_or(include_time);
 

+ 1 - 0
frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_type_option_entities.rs

@@ -22,6 +22,7 @@ pub struct DateCellChangeset {
   pub date: Option<String>,
   pub time: Option<String>,
   pub include_time: Option<bool>,
+  pub clear_flag: Option<bool>,
 }
 
 impl DateCellChangeset {

+ 1 - 0
frontend/rust-lib/flowy-database2/tests/database/database_editor.rs

@@ -331,6 +331,7 @@ impl<'a> TestRowBuilder<'a> {
       date: Some(data.to_string()),
       time,
       include_time,
+      clear_flag: None,
     })
     .unwrap();
     let date_field = self.field_with_type(field_type);

+ 1 - 0
frontend/rust-lib/flowy-database2/tests/database/field_test/util.rs

@@ -83,6 +83,7 @@ pub fn make_date_cell_string(s: &str) -> String {
     date: Some(s.to_string()),
     time: None,
     include_time: Some(false),
+    clear_flag: None,
   })
   .unwrap()
 }

+ 2 - 0
frontend/rust-lib/flowy-test/tests/database/local_test/test.rs

@@ -531,6 +531,7 @@ async fn update_date_cell_event_test() {
       date: Some(timestamp_str.clone()),
       time: None,
       include_time: None,
+      clear_flag: None,
     })
     .await;
   assert!(error.is_none());
@@ -895,6 +896,7 @@ async fn create_calendar_event_test() {
       date: Some(timestamp_str.clone()),
       time: None,
       include_time: None,
+      clear_flag: None,
     })
     .await;
   assert!(error.is_none());