From 9b7d38bca7c613685defc2470bf97aa493977927 Mon Sep 17 00:00:00 2001 From: Richard Shiue <71320345+richardshiue@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:28:47 +0800 Subject: [PATCH] feat(flutter_desktop): allow filtering by date end (#6399) --- .../database/database_filter_test.dart | 5 +- .../shared/database_test_op.dart | 3 +- .../application/field/filter_entities.dart | 125 ++++++- .../filter/filter_editor_bloc.dart | 2 +- .../widgets/filter/choicechip/date.dart | 165 +++++++-- .../date_picker/appflowy_date_picker.dart | 48 +-- frontend/resources/translations/en.json | 5 +- .../entities/filter_entities/date_filter.rs | 65 +++- .../src/services/cell/cell_operation.rs | 10 +- .../date_type_option/date_filter.rs | 330 +++++++++++++----- .../group/controller_impls/date_controller.rs | 2 +- .../select_option_controller/util.rs | 2 +- .../filter_test/advanced_filter_test.rs | 4 +- .../database/filter_test/date_filter_test.rs | 10 +- .../tests/database/group_test/script.rs | 10 +- .../pre_fill_row_according_to_filter_test.rs | 4 +- 16 files changed, 586 insertions(+), 204 deletions(-) diff --git a/frontend/appflowy_flutter/integration_test/desktop/database/database_filter_test.dart b/frontend/appflowy_flutter/integration_test/desktop/database/database_filter_test.dart index df36eb864c48..6d19ca5d39ec 100644 --- a/frontend/appflowy_flutter/integration_test/desktop/database/database_filter_test.dart +++ b/frontend/appflowy_flutter/integration_test/desktop/database/database_filter_test.dart @@ -1,3 +1,4 @@ +import 'package:appflowy/plugins/database/application/field/filter_entities.dart'; import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/checkbox.dart'; import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/text.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; @@ -151,11 +152,11 @@ void main() { await tester.tapFilterButtonInGrid('date'); await tester.tapDateFilterButtonInGrid(); - await tester.tapDateFilterCondition(DateFilterConditionPB.DateBefore); + await tester.tapDateFilterCondition(DateTimeFilterCondition.before); tester.assertNumberOfRowsInGridPage(7); await tester.tapDateFilterButtonInGrid(); - await tester.tapDateFilterCondition(DateFilterConditionPB.DateIsEmpty); + await tester.tapDateFilterCondition(DateTimeFilterCondition.isEmpty); tester.assertNumberOfRowsInGridPage(3); await tester.pumpAndSettle(); diff --git a/frontend/appflowy_flutter/integration_test/shared/database_test_op.dart b/frontend/appflowy_flutter/integration_test/shared/database_test_op.dart index 8c7b155c1d73..1a7c7e5953c0 100644 --- a/frontend/appflowy_flutter/integration_test/shared/database_test_op.dart +++ b/frontend/appflowy_flutter/integration_test/shared/database_test_op.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:appflowy/plugins/database/application/field/filter_entities.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -1135,7 +1136,7 @@ extension AppFlowyDatabaseTest on WidgetTester { await tapButton(button); } - Future tapDateFilterCondition(DateFilterConditionPB condition) async { + Future tapDateFilterCondition(DateTimeFilterCondition condition) async { final button = find.descendant( of: find.byType(HoverButton), matching: find.text(condition.filterName), diff --git a/frontend/appflowy_flutter/lib/plugins/database/application/field/filter_entities.dart b/frontend/appflowy_flutter/lib/plugins/database/application/field/filter_entities.dart index c2b47d74134a..1cbd35fb5d84 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/application/field/filter_entities.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/application/field/filter_entities.dart @@ -1,5 +1,6 @@ import 'dart:typed_data'; +import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/database/application/field/field_info.dart'; import 'package:appflowy/plugins/database/grid/application/filter/select_option_loader.dart'; import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/checkbox.dart'; @@ -10,6 +11,7 @@ import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choic import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/text.dart'; import 'package:appflowy/util/int64_extension.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:fixnum/fixnum.dart'; abstract class DatabaseFilter { @@ -319,6 +321,67 @@ final class SelectOptionFilter extends DatabaseFilter { } } +enum DateTimeFilterCondition { + on, + before, + after, + onOrBefore, + onOrAfter, + between, + isEmpty, + isNotEmpty; + + DateFilterConditionPB toPB(bool isStart) { + return isStart + ? switch (this) { + on => DateFilterConditionPB.DateStartsOn, + before => DateFilterConditionPB.DateStartsBefore, + after => DateFilterConditionPB.DateStartsAfter, + onOrBefore => DateFilterConditionPB.DateStartsOnOrBefore, + onOrAfter => DateFilterConditionPB.DateStartsOnOrAfter, + between => DateFilterConditionPB.DateStartsBetween, + isEmpty => DateFilterConditionPB.DateStartIsEmpty, + isNotEmpty => DateFilterConditionPB.DateStartIsNotEmpty, + } + : switch (this) { + on => DateFilterConditionPB.DateEndsOn, + before => DateFilterConditionPB.DateEndsBefore, + after => DateFilterConditionPB.DateEndsAfter, + onOrBefore => DateFilterConditionPB.DateEndsOnOrBefore, + onOrAfter => DateFilterConditionPB.DateEndsOnOrAfter, + between => DateFilterConditionPB.DateEndsBetween, + isEmpty => DateFilterConditionPB.DateEndIsEmpty, + isNotEmpty => DateFilterConditionPB.DateEndIsNotEmpty, + }; + } + + String get choiceChipPrefix { + return switch (this) { + on => "", + before => LocaleKeys.grid_dateFilter_choicechipPrefix_before.tr(), + after => LocaleKeys.grid_dateFilter_choicechipPrefix_after.tr(), + onOrBefore => LocaleKeys.grid_dateFilter_choicechipPrefix_onOrBefore.tr(), + onOrAfter => LocaleKeys.grid_dateFilter_choicechipPrefix_onOrAfter.tr(), + between => LocaleKeys.grid_dateFilter_choicechipPrefix_between.tr(), + isEmpty => LocaleKeys.grid_dateFilter_choicechipPrefix_isEmpty.tr(), + isNotEmpty => LocaleKeys.grid_dateFilter_choicechipPrefix_isNotEmpty.tr(), + }; + } + + String get filterName { + return switch (this) { + on => LocaleKeys.grid_dateFilter_is.tr(), + before => LocaleKeys.grid_dateFilter_before.tr(), + after => LocaleKeys.grid_dateFilter_after.tr(), + onOrBefore => LocaleKeys.grid_dateFilter_onOrBefore.tr(), + onOrAfter => LocaleKeys.grid_dateFilter_onOrAfter.tr(), + between => LocaleKeys.grid_dateFilter_between.tr(), + isEmpty => LocaleKeys.grid_dateFilter_empty.tr(), + isNotEmpty => LocaleKeys.grid_dateFilter_notEmpty.tr(), + }; + } +} + final class DateTimeFilter extends DatabaseFilter { const DateTimeFilter({ required super.filterId, @@ -341,12 +404,19 @@ final class DateTimeFilter extends DatabaseFilter { @override String getDescription(FieldInfo field) { return switch (condition) { - DateFilterConditionPB.DateIsEmpty || - DateFilterConditionPB.DateIsNotEmpty => - condition.filterName, - DateFilterConditionPB.DateWithIn => - "${condition.filterName} ${start?.defaultFormat ?? ""} - ${end?.defaultFormat ?? ""}", - _ => "${condition.filterName} ${timestamp?.defaultFormat ?? ""}" + DateFilterConditionPB.DateStartIsEmpty || + DateFilterConditionPB.DateStartIsNotEmpty || + DateFilterConditionPB.DateEndIsEmpty || + DateFilterConditionPB.DateEndIsNotEmpty => + condition.toCondition().choiceChipPrefix, + DateFilterConditionPB.DateStartsOn || + DateFilterConditionPB.DateEndsOn => + timestamp?.defaultFormat ?? "", + DateFilterConditionPB.DateStartsBetween || + DateFilterConditionPB.DateEndsBetween => + "${condition.toCondition().choiceChipPrefix} ${start?.defaultFormat ?? ""} - ${end?.defaultFormat ?? ""}", + _ => + "${condition.toCondition().choiceChipPrefix} ${timestamp?.defaultFormat ?? ""}" }; } @@ -359,22 +429,29 @@ final class DateTimeFilter extends DatabaseFilter { } switch (condition) { - case DateFilterConditionPB.DateIs: - case DateFilterConditionPB.DateBefore: - case DateFilterConditionPB.DateOnOrBefore: - case DateFilterConditionPB.DateAfter: - case DateFilterConditionPB.DateOnOrAfter: + case DateFilterConditionPB.DateStartsOn: + case DateFilterConditionPB.DateStartsBefore: + case DateFilterConditionPB.DateStartsOnOrBefore: + case DateFilterConditionPB.DateStartsAfter: + case DateFilterConditionPB.DateStartsOnOrAfter: + case DateFilterConditionPB.DateEndsOn: + case DateFilterConditionPB.DateEndsBefore: + case DateFilterConditionPB.DateEndsOnOrBefore: + case DateFilterConditionPB.DateEndsAfter: + case DateFilterConditionPB.DateEndsOnOrAfter: if (timestamp != null) { filterPB.timestamp = dateTimeToInt(timestamp!); } break; - case DateFilterConditionPB.DateWithIn: + case DateFilterConditionPB.DateStartsBetween: + case DateFilterConditionPB.DateEndsBetween: if (start != null) { filterPB.start = dateTimeToInt(start!); } if (end != null) { filterPB.end = dateTimeToInt(end!); } + break; default: break; } @@ -382,18 +459,32 @@ final class DateTimeFilter extends DatabaseFilter { return filterPB.writeToBuffer(); } - DateTimeFilter copyWith({ - DateFilterConditionPB? condition, - DateTime? timestamp, + DateTimeFilter copyWithCondition({ + required bool isStart, + required DateTimeFilterCondition condition, }) { return DateTimeFilter( filterId: filterId, fieldId: fieldId, fieldType: fieldType, + condition: condition.toPB(isStart), start: start, end: end, - condition: condition ?? this.condition, - timestamp: timestamp ?? this.timestamp, + timestamp: timestamp, + ); + } + + DateTimeFilter copyWithTimestamp({ + required DateTime timestamp, + }) { + return DateTimeFilter( + filterId: filterId, + fieldId: fieldId, + fieldType: fieldType, + condition: condition, + start: start, + end: end, + timestamp: timestamp, ); } diff --git a/frontend/appflowy_flutter/lib/plugins/database/grid/application/filter/filter_editor_bloc.dart b/frontend/appflowy_flutter/lib/plugins/database/grid/application/filter/filter_editor_bloc.dart index d5edf4506e6a..1c3c03290b4a 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/grid/application/filter/filter_editor_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/grid/application/filter/filter_editor_bloc.dart @@ -115,7 +115,7 @@ class FilterEditorBloc extends Bloc { final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; return _filterBackendSvc.insertDateFilter( fieldId: fieldId, - condition: DateFilterConditionPB.DateIs, + condition: DateFilterConditionPB.DateStartsOn, timestamp: timestamp, ); case FieldType.MultiSelect: diff --git a/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/filter/choicechip/date.dart b/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/filter/choicechip/date.dart index 8a22036fc104..3913be1ce39f 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/filter/choicechip/date.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/filter/choicechip/date.dart @@ -29,7 +29,7 @@ class DateFilterChoicechip extends StatelessWidget { @override Widget build(BuildContext context) { return AppFlowyPopover( - constraints: BoxConstraints.loose(const Size(200, 120)), + constraints: BoxConstraints.loose(const Size(275, 120)), direction: PopoverDirection.bottomWithLeftAligned, popupBuilder: (_) { return BlocProvider.value( @@ -79,8 +79,12 @@ class _DateFilterEditorState extends State { builder: (context, filter, field) { final List children = [ _buildFilterPanel(filter, field), - if (filter.condition != DateFilterConditionPB.DateIsEmpty && - filter.condition != DateFilterConditionPB.DateIsNotEmpty) ...[ + if (![ + DateFilterConditionPB.DateStartIsEmpty, + DateFilterConditionPB.DateStartIsNotEmpty, + DateFilterConditionPB.DateEndIsEmpty, + DateFilterConditionPB.DateStartIsNotEmpty, + ].contains(filter.condition)) ...[ const VSpace(4), _buildFilterContentField(filter), ], @@ -103,9 +107,18 @@ class _DateFilterEditorState extends State { child: Row( children: [ Expanded( - child: FlowyText( - field.name, - overflow: TextOverflow.ellipsis, + child: DateFilterIsStartList( + filter: filter, + popoverMutex: popoverMutex, + onChangeIsStart: (isStart) { + final newFilter = filter.copyWithCondition( + isStart: isStart, + condition: filter.condition.toCondition(), + ); + context + .read() + .add(FilterEditorEvent.updateFilter(newFilter)); + }, ), ), const HSpace(4), @@ -114,7 +127,10 @@ class _DateFilterEditorState extends State { filter: filter, popoverMutex: popoverMutex, onCondition: (condition) { - final newFilter = filter.copyWith(condition: condition); + final newFilter = filter.copyWithCondition( + isStart: filter.condition.isStart, + condition: condition, + ); context .read() .add(FilterEditorEvent.updateFilter(newFilter)); @@ -140,7 +156,9 @@ class _DateFilterEditorState extends State { } Widget _buildFilterContentField(DateTimeFilter filter) { - final isRange = filter.condition == DateFilterConditionPB.DateWithIn; + final isRange = + filter.condition == DateFilterConditionPB.DateStartsBetween || + filter.condition == DateFilterConditionPB.DateEndsBetween; String? text; if (isRange) { @@ -187,10 +205,11 @@ class _DateFilterEditorState extends State { selectedDay: isRange ? filter.start : filter.timestamp, startDay: isRange ? filter.start : null, endDay: isRange ? filter.end : null, + enableReminder: false, onDaySelected: (selectedDay, _) { final newFilter = isRange ? filter.copyWithRange(start: selectedDay, end: null) - : filter.copyWith(timestamp: selectedDay); + : filter.copyWithTimestamp(timestamp: selectedDay); context .read() .add(FilterEditorEvent.updateFilter(newFilter)); @@ -207,7 +226,6 @@ class _DateFilterEditorState extends State { .read() .add(FilterEditorEvent.updateFilter(newFilter)); }, - onIncludeTimeChanged: (_) {}, ); }, ), @@ -217,6 +235,66 @@ class _DateFilterEditorState extends State { } } +class DateFilterIsStartList extends StatelessWidget { + const DateFilterIsStartList({ + super.key, + required this.filter, + required this.popoverMutex, + required this.onChangeIsStart, + }); + + final DateTimeFilter filter; + final PopoverMutex popoverMutex; + final Function(bool isStart) onChangeIsStart; + + @override + Widget build(BuildContext context) { + return PopoverActionList<_IsStartWrapper>( + asBarrier: true, + mutex: popoverMutex, + direction: PopoverDirection.bottomWithCenterAligned, + actions: [ + _IsStartWrapper( + true, + filter.condition.isStart, + ), + _IsStartWrapper( + false, + !filter.condition.isStart, + ), + ], + buildChild: (controller) { + return ConditionButton( + conditionName: filter.condition.isStart + ? LocaleKeys.grid_dateFilter_startDate.tr() + : LocaleKeys.grid_dateFilter_endDate.tr(), + onTap: () => controller.show(), + ); + }, + onSelected: (action, controller) { + onChangeIsStart(action.inner); + controller.close(); + }, + ); + } +} + +class _IsStartWrapper extends ActionCell { + _IsStartWrapper(this.inner, this.isSelected); + + final bool inner; + final bool isSelected; + + @override + Widget? rightIcon(Color iconColor) => + isSelected ? const FlowySvg(FlowySvgs.check_s) : null; + + @override + String get name => inner + ? LocaleKeys.grid_dateFilter_startDate.tr() + : LocaleKeys.grid_dateFilter_endDate.tr(); +} + class DateFilterConditionList extends StatelessWidget { const DateFilterConditionList({ super.key, @@ -227,7 +305,7 @@ class DateFilterConditionList extends StatelessWidget { final DateTimeFilter filter; final PopoverMutex popoverMutex; - final Function(DateFilterConditionPB) onCondition; + final Function(DateTimeFilterCondition) onCondition; @override Widget build(BuildContext context) { @@ -235,17 +313,17 @@ class DateFilterConditionList extends StatelessWidget { asBarrier: true, mutex: popoverMutex, direction: PopoverDirection.bottomWithCenterAligned, - actions: DateFilterConditionPB.values + actions: DateTimeFilterCondition.values .map( (action) => ConditionWrapper( action, - filter.condition == action, + filter.condition.toCondition() == action, ), ) .toList(), buildChild: (controller) { return ConditionButton( - conditionName: filter.condition.filterName, + conditionName: filter.condition.toCondition().filterName, onTap: () => controller.show(), ); }, @@ -260,7 +338,7 @@ class DateFilterConditionList extends StatelessWidget { class ConditionWrapper extends ActionCell { ConditionWrapper(this.inner, this.isSelected); - final DateFilterConditionPB inner; + final DateTimeFilterCondition inner; final bool isSelected; @override @@ -272,23 +350,48 @@ class ConditionWrapper extends ActionCell { } extension DateFilterConditionPBExtension on DateFilterConditionPB { - String get filterName { + bool get isStart { + return switch (this) { + DateFilterConditionPB.DateStartsOn || + DateFilterConditionPB.DateStartsBefore || + DateFilterConditionPB.DateStartsAfter || + DateFilterConditionPB.DateStartsOnOrBefore || + DateFilterConditionPB.DateStartsOnOrAfter || + DateFilterConditionPB.DateStartsBetween || + DateFilterConditionPB.DateStartIsEmpty || + DateFilterConditionPB.DateStartIsNotEmpty => + true, + _ => false + }; + } + + DateTimeFilterCondition toCondition() { return switch (this) { - DateFilterConditionPB.DateIs => LocaleKeys.grid_dateFilter_is.tr(), - DateFilterConditionPB.DateBefore => - LocaleKeys.grid_dateFilter_before.tr(), - DateFilterConditionPB.DateAfter => LocaleKeys.grid_dateFilter_after.tr(), - DateFilterConditionPB.DateOnOrBefore => - LocaleKeys.grid_dateFilter_onOrBefore.tr(), - DateFilterConditionPB.DateOnOrAfter => - LocaleKeys.grid_dateFilter_onOrAfter.tr(), - DateFilterConditionPB.DateWithIn => - LocaleKeys.grid_dateFilter_between.tr(), - DateFilterConditionPB.DateIsEmpty => - LocaleKeys.grid_dateFilter_empty.tr(), - DateFilterConditionPB.DateIsNotEmpty => - LocaleKeys.grid_dateFilter_notEmpty.tr(), - _ => "", + DateFilterConditionPB.DateStartsOn || + DateFilterConditionPB.DateEndsOn => + DateTimeFilterCondition.on, + DateFilterConditionPB.DateStartsBefore || + DateFilterConditionPB.DateEndsBefore => + DateTimeFilterCondition.before, + DateFilterConditionPB.DateStartsAfter || + DateFilterConditionPB.DateEndsAfter => + DateTimeFilterCondition.after, + DateFilterConditionPB.DateStartsOnOrBefore || + DateFilterConditionPB.DateEndsOnOrBefore => + DateTimeFilterCondition.onOrBefore, + DateFilterConditionPB.DateStartsOnOrAfter || + DateFilterConditionPB.DateEndsOnOrAfter => + DateTimeFilterCondition.onOrAfter, + DateFilterConditionPB.DateStartsBetween || + DateFilterConditionPB.DateEndsBetween => + DateTimeFilterCondition.between, + DateFilterConditionPB.DateStartIsEmpty || + DateFilterConditionPB.DateStartIsEmpty => + DateTimeFilterCondition.isEmpty, + DateFilterConditionPB.DateStartIsNotEmpty || + DateFilterConditionPB.DateStartIsNotEmpty => + DateTimeFilterCondition.isNotEmpty, + _ => throw ArgumentError(), }; } } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/date_picker/appflowy_date_picker.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/date_picker/appflowy_date_picker.dart index b33175ffac36..64220fab282b 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/date_picker/appflowy_date_picker.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/date_picker/appflowy_date_picker.dart @@ -26,7 +26,7 @@ class AppFlowyDatePicker extends StatefulWidget { const AppFlowyDatePicker({ super.key, required this.includeTime, - required this.onIncludeTimeChanged, + this.onIncludeTimeChanged, this.rebuildOnDaySelected = true, this.enableRanges = true, this.isRange = false, @@ -50,6 +50,7 @@ class AppFlowyDatePicker extends StatefulWidget { this.onEndTimeSubmitted, this.onDaySelected, this.onRangeSelected, + this.enableReminder = true, this.onReminderSelected, this.options, this.allowFormatChanges = false, @@ -61,7 +62,7 @@ class AppFlowyDatePicker extends StatefulWidget { }); final bool includeTime; - final Function(bool) onIncludeTimeChanged; + final Function(bool)? onIncludeTimeChanged; final bool enableRanges; final bool isRange; @@ -95,6 +96,8 @@ class AppFlowyDatePicker extends StatefulWidget { final TimeChangedCallback? onEndTimeSubmitted; final DaySelectedCallback? onDaySelected; final RangeSelectedCallback? onRangeSelected; + + final bool enableReminder; final OnReminderSelected? onReminderSelected; /// A list of [OptionGroup] that will be rendered with proper @@ -221,7 +224,9 @@ class _AppFlowyDatePickerState extends State { onCalendarCreated: widget.onCalendarCreated, onPageChanged: widget.onPageChanged, ), - const TypeOptionSeparator(spacing: 12.0), + if (widget.enableRanges && widget.onIsRangeChanged != null || + widget.onIncludeTimeChanged != null) + const TypeOptionSeparator(spacing: 12.0), if (widget.enableRanges && widget.onIsRangeChanged != null) ...[ EndTimeButton( isRange: widget.isRange, @@ -229,24 +234,27 @@ class _AppFlowyDatePickerState extends State { ), const VSpace(4.0), ], - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: IncludeTimeButton( - value: widget.includeTime, - onChanged: widget.onIncludeTimeChanged, + if (widget.onIncludeTimeChanged != null) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: IncludeTimeButton( + value: widget.includeTime, + onChanged: widget.onIncludeTimeChanged!, + ), ), - ), - const _GroupSeparator(), - ReminderSelector( - mutex: widget.popoverMutex, - hasTime: widget.includeTime, - timeFormat: widget.timeFormat, - selectedOption: _selectedReminderOption, - onOptionSelected: (option) { - setState(() => _selectedReminderOption = option); - widget.onReminderSelected?.call(option); - }, - ), + if (widget.enableReminder) ...[ + const _GroupSeparator(), + ReminderSelector( + mutex: widget.popoverMutex, + hasTime: widget.includeTime, + timeFormat: widget.timeFormat, + selectedOption: _selectedReminderOption, + onOptionSelected: (option) { + setState(() => _selectedReminderOption = option); + widget.onReminderSelected?.call(option); + }, + ), + ], if (widget.options?.isNotEmpty ?? false) ...[ const _GroupSeparator(), ListView.separated( diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index d9f37901fd22..5f978a5a3841 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -1280,7 +1280,7 @@ "isNotEmpty": "Is not empty" }, "dateFilter": { - "is": "Is", + "is": "Is on", "before": "Is before", "after": "Is after", "onOrBefore": "Is on or before", @@ -1288,9 +1288,12 @@ "between": "Is between", "empty": "Is empty", "notEmpty": "Is not empty", + "startDate": "Start date", + "endDate": "End date", "choicechipPrefix": { "before": "Before", "after": "After", + "between": "Between", "onOrBefore": "On or before", "onOrAfter": "On or after", "isEmpty": "Is empty", diff --git a/frontend/rust-lib/flowy-database2/src/entities/filter_entities/date_filter.rs b/frontend/rust-lib/flowy-database2/src/entities/filter_entities/date_filter.rs index 01c3c9687c67..edb863aae0ee 100644 --- a/frontend/rust-lib/flowy-database2/src/entities/filter_entities/date_filter.rs +++ b/frontend/rust-lib/flowy-database2/src/entities/filter_entities/date_filter.rs @@ -47,14 +47,38 @@ impl FromStr for DateFilterContent { #[repr(u8)] pub enum DateFilterConditionPB { #[default] - DateIs = 0, - DateBefore = 1, - DateAfter = 2, - DateOnOrBefore = 3, - DateOnOrAfter = 4, - DateWithIn = 5, - DateIsEmpty = 6, - DateIsNotEmpty = 7, + DateStartsOn = 0, + DateStartsBefore = 1, + DateStartsAfter = 2, + DateStartsOnOrBefore = 3, + DateStartsOnOrAfter = 4, + DateStartsBetween = 5, + DateStartIsEmpty = 6, + DateStartIsNotEmpty = 7, + DateEndsOn = 8, + DateEndsBefore = 9, + DateEndsAfter = 10, + DateEndsOnOrBefore = 11, + DateEndsOnOrAfter = 12, + DateEndsBetween = 13, + DateEndIsEmpty = 14, + DateEndIsNotEmpty = 15, +} + +impl DateFilterConditionPB { + pub fn is_filter_on_start_timestamp(&self) -> bool { + matches!( + self, + Self::DateStartsOn + | Self::DateStartsBefore + | Self::DateStartsAfter + | Self::DateStartsOnOrBefore + | Self::DateStartsOnOrAfter + | Self::DateStartsBetween + | Self::DateStartIsEmpty + | Self::DateStartIsNotEmpty, + ) + } } impl std::convert::From for u32 { @@ -68,13 +92,22 @@ impl std::convert::TryFrom for DateFilterConditionPB { fn try_from(value: u8) -> Result { match value { - 0 => Ok(DateFilterConditionPB::DateIs), - 1 => Ok(DateFilterConditionPB::DateBefore), - 2 => Ok(DateFilterConditionPB::DateAfter), - 3 => Ok(DateFilterConditionPB::DateOnOrBefore), - 4 => Ok(DateFilterConditionPB::DateOnOrAfter), - 5 => Ok(DateFilterConditionPB::DateWithIn), - 6 => Ok(DateFilterConditionPB::DateIsEmpty), + 0 => Ok(Self::DateStartsOn), + 1 => Ok(Self::DateStartsBefore), + 2 => Ok(Self::DateStartsAfter), + 3 => Ok(Self::DateStartsOnOrBefore), + 4 => Ok(Self::DateStartsOnOrAfter), + 5 => Ok(Self::DateStartsBetween), + 6 => Ok(Self::DateStartIsEmpty), + 7 => Ok(Self::DateStartIsNotEmpty), + 8 => Ok(Self::DateEndsOn), + 9 => Ok(Self::DateEndsBefore), + 10 => Ok(Self::DateEndsAfter), + 11 => Ok(Self::DateEndsOnOrBefore), + 12 => Ok(Self::DateEndsOnOrAfter), + 13 => Ok(Self::DateEndsBetween), + 14 => Ok(Self::DateEndIsEmpty), + 15 => Ok(Self::DateEndIsNotEmpty), _ => Err(ErrorCode::InvalidParams), } } @@ -83,7 +116,7 @@ impl std::convert::TryFrom for DateFilterConditionPB { impl ParseFilterData for DateFilterPB { fn parse(condition: u8, content: String) -> Self { let condition = - DateFilterConditionPB::try_from(condition).unwrap_or(DateFilterConditionPB::DateIs); + DateFilterConditionPB::try_from(condition).unwrap_or(DateFilterConditionPB::DateStartsOn); let mut date_filter = Self { condition, ..Default::default() diff --git a/frontend/rust-lib/flowy-database2/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-database2/src/services/cell/cell_operation.rs index be608749d4ad..d4bb5dd74259 100644 --- a/frontend/rust-lib/flowy-database2/src/services/cell/cell_operation.rs +++ b/frontend/rust-lib/flowy-database2/src/services/cell/cell_operation.rs @@ -172,13 +172,15 @@ pub fn insert_checkbox_cell(is_checked: bool, field: &Field) -> Cell { pub fn insert_date_cell( timestamp: i64, - time: Option, + start_time: Option, + end_timestamp: Option, include_time: Option, field: &Field, ) -> Cell { let cell_data = DateCellChangeset { date: Some(timestamp), - time, + time: start_time, + end_date: end_timestamp, include_time, ..Default::default() }; @@ -233,7 +235,7 @@ impl<'a> CellBuilder<'a> { if let Ok(timestamp) = cell_str.parse::() { cells.insert( field_id, - insert_date_cell(timestamp, None, Some(false), field), + insert_date_cell(timestamp, None, None, Some(false), field), ); } }, @@ -331,7 +333,7 @@ impl<'a> CellBuilder<'a> { Some(field) => { self.cells.insert( field_id.to_owned(), - insert_date_cell(timestamp, time, include_time, field), + insert_date_cell(timestamp, time, None, include_time, field), ); }, } diff --git a/frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_filter.rs b/frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_filter.rs index 9d888e5f7cee..85cf805636dd 100644 --- a/frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_filter.rs +++ b/frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/date_filter.rs @@ -10,23 +10,45 @@ use collab_database::rows::Cell; impl DateFilterPB { /// Returns `None` if the DateFilterPB doesn't have the necessary data for /// the condition. For example, `start` and `end` timestamps for - /// `DateFilterConditionPB::DateWithin`. + /// `DateFilterConditionPB::DateStartsBetween`. pub fn is_visible(&self, cell_data: &DateCellData) -> Option { let strategy = match self.condition { - DateFilterConditionPB::DateIs => DateFilterStrategy::On(self.timestamp?), - DateFilterConditionPB::DateBefore => DateFilterStrategy::Before(self.timestamp?), - DateFilterConditionPB::DateAfter => DateFilterStrategy::After(self.timestamp?), - DateFilterConditionPB::DateOnOrBefore => DateFilterStrategy::OnOrBefore(self.timestamp?), - DateFilterConditionPB::DateOnOrAfter => DateFilterStrategy::OnOrAfter(self.timestamp?), - DateFilterConditionPB::DateWithIn => DateFilterStrategy::DateWithin { - start: self.start?, - end: self.end?, + DateFilterConditionPB::DateStartsOn | DateFilterConditionPB::DateEndsOn => { + DateFilterStrategy::On(self.timestamp?) }, - DateFilterConditionPB::DateIsEmpty => DateFilterStrategy::Empty, - DateFilterConditionPB::DateIsNotEmpty => DateFilterStrategy::NotEmpty, + DateFilterConditionPB::DateStartsBefore | DateFilterConditionPB::DateEndsBefore => { + DateFilterStrategy::Before(self.timestamp?) + }, + DateFilterConditionPB::DateStartsAfter | DateFilterConditionPB::DateEndsAfter => { + DateFilterStrategy::After(self.timestamp?) + }, + DateFilterConditionPB::DateStartsOnOrBefore | DateFilterConditionPB::DateEndsOnOrBefore => { + DateFilterStrategy::OnOrBefore(self.timestamp?) + }, + DateFilterConditionPB::DateStartsOnOrAfter | DateFilterConditionPB::DateEndsOnOrAfter => { + DateFilterStrategy::OnOrAfter(self.timestamp?) + }, + DateFilterConditionPB::DateStartsBetween | DateFilterConditionPB::DateEndsBetween => { + DateFilterStrategy::DateBetween { + start: self.start?, + end: self.end?, + } + }, + DateFilterConditionPB::DateStartIsEmpty | DateFilterConditionPB::DateEndIsEmpty => { + DateFilterStrategy::Empty + }, + DateFilterConditionPB::DateStartIsNotEmpty | DateFilterConditionPB::DateEndIsNotEmpty => { + DateFilterStrategy::NotEmpty + }, + }; + + let timestamp = if self.condition.is_filter_on_start_timestamp() { + cell_data.timestamp + } else { + cell_data.end_timestamp.or_else(|| cell_data.timestamp) }; - Some(strategy.filter(cell_data)) + Some(strategy.filter(timestamp)) } } @@ -41,70 +63,67 @@ enum DateFilterStrategy { After(i64), OnOrBefore(i64), OnOrAfter(i64), - DateWithin { start: i64, end: i64 }, + DateBetween { start: i64, end: i64 }, Empty, NotEmpty, } impl DateFilterStrategy { - fn filter(self, cell_data: &DateCellData) -> bool { + fn filter(self, cell_data: Option) -> bool { match self { - DateFilterStrategy::On(expected_timestamp) => cell_data.timestamp.is_some_and(|timestamp| { + DateFilterStrategy::On(expected_timestamp) => cell_data.is_some_and(|timestamp| { let cell_date = naive_date_from_timestamp(timestamp); let expected_date = naive_date_from_timestamp(expected_timestamp); cell_date == expected_date }), - DateFilterStrategy::Before(expected_timestamp) => { - cell_data.timestamp.is_some_and(|timestamp| { - let cell_date = naive_date_from_timestamp(timestamp); - let expected_date = naive_date_from_timestamp(expected_timestamp); - cell_date < expected_date - }) - }, - DateFilterStrategy::After(expected_timestamp) => { - cell_data.timestamp.is_some_and(|timestamp| { - let cell_date = naive_date_from_timestamp(timestamp); - let expected_date = naive_date_from_timestamp(expected_timestamp); - cell_date > expected_date - }) - }, - DateFilterStrategy::OnOrBefore(expected_timestamp) => { - cell_data.timestamp.is_some_and(|timestamp| { - let cell_date = naive_date_from_timestamp(timestamp); - let expected_date = naive_date_from_timestamp(expected_timestamp); - cell_date <= expected_date - }) - }, - DateFilterStrategy::OnOrAfter(expected_timestamp) => { - cell_data.timestamp.is_some_and(|timestamp| { - let cell_date = naive_date_from_timestamp(timestamp); - let expected_date = naive_date_from_timestamp(expected_timestamp); - cell_date >= expected_date - }) - }, - DateFilterStrategy::DateWithin { start, end } => { - cell_data.timestamp.is_some_and(|timestamp| { - let cell_date = naive_date_from_timestamp(timestamp); - let expected_start_date = naive_date_from_timestamp(start); - let expected_end_date = naive_date_from_timestamp(end); - cell_date >= expected_start_date && cell_date <= expected_end_date - }) + DateFilterStrategy::Before(expected_timestamp) => cell_data.is_some_and(|timestamp| { + let cell_date = naive_date_from_timestamp(timestamp); + let expected_date = naive_date_from_timestamp(expected_timestamp); + cell_date < expected_date + }), + DateFilterStrategy::After(expected_timestamp) => cell_data.is_some_and(|timestamp| { + let cell_date = naive_date_from_timestamp(timestamp); + let expected_date = naive_date_from_timestamp(expected_timestamp); + cell_date > expected_date + }), + DateFilterStrategy::OnOrBefore(expected_timestamp) => cell_data.is_some_and(|timestamp| { + let cell_date = naive_date_from_timestamp(timestamp); + let expected_date = naive_date_from_timestamp(expected_timestamp); + cell_date <= expected_date + }), + DateFilterStrategy::OnOrAfter(expected_timestamp) => cell_data.is_some_and(|timestamp| { + let cell_date = naive_date_from_timestamp(timestamp); + let expected_date = naive_date_from_timestamp(expected_timestamp); + cell_date >= expected_date + }), + DateFilterStrategy::DateBetween { start, end } => cell_data.is_some_and(|timestamp| { + let cell_date = naive_date_from_timestamp(timestamp); + let expected_start_date = naive_date_from_timestamp(start); + let expected_end_date = naive_date_from_timestamp(end); + cell_date >= expected_start_date && cell_date <= expected_end_date + }), + DateFilterStrategy::Empty => match cell_data { + None => true, + Some(timestamp) if naive_date_from_timestamp(timestamp).is_none() => true, + _ => false, }, - DateFilterStrategy::Empty => { - cell_data.timestamp.is_none() && cell_data.end_timestamp.is_none() + DateFilterStrategy::NotEmpty => { + matches!(cell_data, Some(timestamp) if naive_date_from_timestamp(timestamp).is_some() ) }, - DateFilterStrategy::NotEmpty => cell_data.timestamp.is_some(), } } } impl PreFillCellsWithFilter for DateFilterPB { fn get_compliant_cell(&self, field: &Field) -> (Option, bool) { - let timestamp = match self.condition { - DateFilterConditionPB::DateIs - | DateFilterConditionPB::DateOnOrBefore - | DateFilterConditionPB::DateOnOrAfter => self.timestamp, - DateFilterConditionPB::DateBefore => self + let start_timestamp = match self.condition { + DateFilterConditionPB::DateStartsOn + | DateFilterConditionPB::DateStartsOnOrBefore + | DateFilterConditionPB::DateStartsOnOrAfter + | DateFilterConditionPB::DateEndsOn + | DateFilterConditionPB::DateEndsOnOrBefore + | DateFilterConditionPB::DateEndsOnOrAfter => self.timestamp, + DateFilterConditionPB::DateStartsBefore | DateFilterConditionPB::DateEndsBefore => self .timestamp .and_then(|timestamp| { chrono::DateTime::from_timestamp(timestamp, 0).map(|date| date.naive_utc()) @@ -113,7 +132,7 @@ impl PreFillCellsWithFilter for DateFilterPB { let answer = date_time - Duration::days(1); answer.and_utc().timestamp() }), - DateFilterConditionPB::DateAfter => self + DateFilterConditionPB::DateStartsAfter | DateFilterConditionPB::DateEndsAfter => self .timestamp .and_then(|timestamp| { chrono::DateTime::from_timestamp(timestamp, 0).map(|date| date.naive_utc()) @@ -122,16 +141,24 @@ impl PreFillCellsWithFilter for DateFilterPB { let answer = date_time + Duration::days(1); answer.and_utc().timestamp() }), - DateFilterConditionPB::DateWithIn => self.start, + DateFilterConditionPB::DateStartsBetween | DateFilterConditionPB::DateEndsBetween => { + self.start + }, _ => None, }; - let open_after_create = matches!(self.condition, DateFilterConditionPB::DateIsNotEmpty); + let end_timestamp = if self.condition.is_filter_on_start_timestamp() { + start_timestamp + } else { + None + }; + + let cell = start_timestamp + .map(|timestamp| insert_date_cell(timestamp, None, end_timestamp, None, field)); + + let open_after_create = matches!(self.condition, DateFilterConditionPB::DateStartIsNotEmpty); - ( - timestamp.map(|timestamp| insert_date_cell(timestamp, None, None, field)), - open_after_create, - ) + (cell, open_after_create) } } @@ -140,39 +167,69 @@ mod tests { use crate::entities::{DateFilterConditionPB, DateFilterPB}; use collab_database::fields::date_type_option::DateCellData; - fn to_cell_data(timestamp: i32) -> DateCellData { - DateCellData::new(timestamp as i64, false, false, "".to_string()) + fn to_cell_data(timestamp: Option, end_timestamp: Option) -> DateCellData { + DateCellData { + timestamp, + end_timestamp, + ..Default::default() + } } #[test] fn date_filter_is_test() { let filter = DateFilterPB { - condition: DateFilterConditionPB::DateIs, + condition: DateFilterConditionPB::DateStartsOn, timestamp: Some(1668387885), end: None, start: None, }; - for (val, visible) in [(1668387885, true), (1647251762, false)] { - assert_eq!(filter.is_visible(&to_cell_data(val)).unwrap(), visible); + for (start, end, is_visible) in [ + (Some(1668387885), None, true), + (Some(1647251762), None, false), + (None, None, false), + ] { + assert_eq!( + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible + ); + } + + let filter = DateFilterPB { + condition: DateFilterConditionPB::DateStartsOn, + timestamp: None, + end: None, + start: None, + }; + + for (start, end, is_visible) in [ + (Some(1668387885), None, true), + (Some(1647251762), None, true), + (None, None, true), + ] { + assert_eq!( + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible + ); } } #[test] fn date_filter_before_test() { let filter = DateFilterPB { - condition: DateFilterConditionPB::DateBefore, + condition: DateFilterConditionPB::DateStartsBefore, timestamp: Some(1668387885), start: None, end: None, }; - for (val, visible, msg) in [(1668387884, false, "1"), (1647251762, true, "2")] { + for (start, end, is_visible) in [ + (Some(1668387884), None, false), + (Some(1647251762), None, true), + ] { assert_eq!( - filter.is_visible(&to_cell_data(val)).unwrap(), - visible, - "{}", - msg + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible, ); } } @@ -180,66 +237,145 @@ mod tests { #[test] fn date_filter_before_or_on_test() { let filter = DateFilterPB { - condition: DateFilterConditionPB::DateOnOrBefore, + condition: DateFilterConditionPB::DateStartsOnOrBefore, timestamp: Some(1668387885), start: None, end: None, }; - for (val, visible) in [(1668387884, true), (1668387885, true)] { - assert_eq!(filter.is_visible(&to_cell_data(val)).unwrap(), visible); + for (start, end, is_visible) in [ + (Some(1668387884), None, true), + (Some(1668387885), None, true), + ] { + assert_eq!( + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible + ); } } #[test] fn date_filter_after_test() { let filter = DateFilterPB { - condition: DateFilterConditionPB::DateAfter, + condition: DateFilterConditionPB::DateStartsAfter, timestamp: Some(1668387885), start: None, end: None, }; - for (val, visible) in [(1668387888, false), (1668531885, true), (0, false)] { - assert_eq!(filter.is_visible(&to_cell_data(val)).unwrap(), visible); + for (start, end, is_visible) in [ + (Some(1668387888), None, false), + (Some(1668531885), None, true), + (Some(0), None, false), + ] { + assert_eq!( + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible + ); } } #[test] fn date_filter_within_test() { let filter = DateFilterPB { - condition: DateFilterConditionPB::DateWithIn, + condition: DateFilterConditionPB::DateStartsBetween, start: Some(1668272685), // 11/13 end: Some(1668618285), // 11/17 timestamp: None, }; - for (val, visible, _msg) in [ - (1668272685, true, "11/13"), - (1668359085, true, "11/14"), - (1668704685, false, "11/18"), + for (start, end, is_visible, msg) in [ + (Some(1668272685), None, true, "11/13"), + (Some(1668359085), None, true, "11/14"), + (Some(1668704685), None, false, "11/18"), + (None, None, false, "empty"), ] { - assert_eq!(filter.is_visible(&to_cell_data(val)).unwrap(), visible); + assert_eq!( + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible, + "{msg}" + ); + } + + let filter = DateFilterPB { + condition: DateFilterConditionPB::DateStartsBetween, + start: None, + end: Some(1668618285), // 11/17 + timestamp: None, + }; + + for (start, end, is_visible, msg) in [ + (Some(1668272685), None, true, "11/13"), + (Some(1668359085), None, true, "11/14"), + (Some(1668704685), None, true, "11/18"), + (None, None, true, "empty"), + ] { + assert_eq!( + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible, + "{msg}" + ); } } #[test] fn date_filter_is_empty_test() { let filter = DateFilterPB { - condition: DateFilterConditionPB::DateIsEmpty, + condition: DateFilterConditionPB::DateStartIsEmpty, start: None, end: None, timestamp: None, }; - for (val, visible) in [(None, true), (Some(123), false)] { + for (start, end, is_visible) in [(None, None, true), (Some(123), None, false)] { + assert_eq!( + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible + ); + } + } + + #[test] + fn date_filter_end_test() { + let filter = DateFilterPB { + condition: DateFilterConditionPB::DateEndsOnOrBefore, + timestamp: Some(1668359085), // 11/14 + end: None, + start: None, + }; + + for (start, end, is_visible, msg) in [ + (Some(1668272685), None, true, "11/13"), + (Some(1668359085), None, true, "11/14"), + (Some(1668704685), None, false, "11/18"), + (None, None, false, "empty"), + (Some(1668272685), Some(1668272685), true, "11/13"), + (Some(1668272685), Some(1668359085), true, "11/14"), + (Some(1668272685), Some(1668704685), false, "11/18"), + ] { + assert_eq!( + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible, + "{msg}" + ); + } + + let filter = DateFilterPB { + condition: DateFilterConditionPB::DateEndsOnOrBefore, + timestamp: None, + start: None, + end: None, + }; + + for (start, end, is_visible, msg) in [ + (Some(1668272685), Some(1668272685), true, "11/13"), + (Some(1668272685), Some(1668359085), true, "11/14"), + (Some(1668272685), Some(1668704685), true, "11/18"), + (None, None, true, "empty"), + ] { assert_eq!( - filter - .is_visible(&DateCellData { - timestamp: val, - ..Default::default() - }) - .unwrap(), - visible + filter.is_visible(&to_cell_data(start, end)).unwrap_or(true), + is_visible, + "{msg}" ); } } diff --git a/frontend/rust-lib/flowy-database2/src/services/group/controller_impls/date_controller.rs b/frontend/rust-lib/flowy-database2/src/services/group/controller_impls/date_controller.rs index ba70618388aa..ad2fd069eb32 100644 --- a/frontend/rust-lib/flowy-database2/src/services/group/controller_impls/date_controller.rs +++ b/frontend/rust-lib/flowy-database2/src/services/group/controller_impls/date_controller.rs @@ -221,7 +221,7 @@ impl GroupCustomize for DateGroupController { None => tracing::warn!("Can not find the group: {}", group_id), Some((_, _)) => { let date = DateTime::parse_from_str(group_id, GROUP_ID_DATE_FORMAT).unwrap(); - let cell = insert_date_cell(date.timestamp(), None, Some(false), field); + let cell = insert_date_cell(date.timestamp(), None, None, Some(false), field); cells.insert(field.id.clone(), cell); }, } diff --git a/frontend/rust-lib/flowy-database2/src/services/group/controller_impls/select_option_controller/util.rs b/frontend/rust-lib/flowy-database2/src/services/group/controller_impls/select_option_controller/util.rs index 827e4f0e536b..55c3d5423641 100644 --- a/frontend/rust-lib/flowy-database2/src/services/group/controller_impls/select_option_controller/util.rs +++ b/frontend/rust-lib/flowy-database2/src/services/group/controller_impls/select_option_controller/util.rs @@ -157,7 +157,7 @@ pub fn make_inserted_cell(group_id: &str, field: &Field) -> Option { let date = NaiveDateTime::parse_from_str(&format!("{} 00:00:00", group_id), "%Y/%m/%d %H:%M:%S") .unwrap(); - let cell = insert_date_cell(date.and_utc().timestamp(), None, Some(false), field); + let cell = insert_date_cell(date.and_utc().timestamp(), None, None, Some(false), field); Some(cell) }, _ => { diff --git a/frontend/rust-lib/flowy-database2/tests/database/filter_test/advanced_filter_test.rs b/frontend/rust-lib/flowy-database2/tests/database/filter_test/advanced_filter_test.rs index bc71718437d2..6e3db58723f4 100644 --- a/frontend/rust-lib/flowy-database2/tests/database/filter_test/advanced_filter_test.rs +++ b/frontend/rust-lib/flowy-database2/tests/database/filter_test/advanced_filter_test.rs @@ -27,7 +27,7 @@ async fn create_advanced_filter_test() { let create_date_filter = || -> DateFilterPB { DateFilterPB { - condition: DateFilterConditionPB::DateAfter, + condition: DateFilterConditionPB::DateStartsAfter, timestamp: Some(1651366800), ..Default::default() } @@ -198,7 +198,7 @@ async fn create_advanced_filter_with_conversion_test() { let create_date_filter = || -> DateFilterPB { DateFilterPB { - condition: DateFilterConditionPB::DateAfter, + condition: DateFilterConditionPB::DateStartsAfter, timestamp: Some(1651366800), ..Default::default() } diff --git a/frontend/rust-lib/flowy-database2/tests/database/filter_test/date_filter_test.rs b/frontend/rust-lib/flowy-database2/tests/database/filter_test/date_filter_test.rs index fed356cfbe8d..7cc5cdf9a743 100644 --- a/frontend/rust-lib/flowy-database2/tests/database/filter_test/date_filter_test.rs +++ b/frontend/rust-lib/flowy-database2/tests/database/filter_test/date_filter_test.rs @@ -14,7 +14,7 @@ async fn grid_filter_date_is_test() { parent_filter_id: None, field_type: FieldType::DateTime, data: BoxAny::new(DateFilterPB { - condition: DateFilterConditionPB::DateIs, + condition: DateFilterConditionPB::DateStartsOn, start: None, end: None, timestamp: Some(1647251762), @@ -39,7 +39,7 @@ async fn grid_filter_date_after_test() { parent_filter_id: None, field_type: FieldType::DateTime, data: BoxAny::new(DateFilterPB { - condition: DateFilterConditionPB::DateAfter, + condition: DateFilterConditionPB::DateStartsAfter, start: None, end: None, timestamp: Some(1647251762), @@ -64,7 +64,7 @@ async fn grid_filter_date_on_or_after_test() { parent_filter_id: None, field_type: FieldType::DateTime, data: BoxAny::new(DateFilterPB { - condition: DateFilterConditionPB::DateOnOrAfter, + condition: DateFilterConditionPB::DateStartsOnOrAfter, start: None, end: None, timestamp: Some(1668359085), @@ -89,7 +89,7 @@ async fn grid_filter_date_on_or_before_test() { parent_filter_id: None, field_type: FieldType::DateTime, data: BoxAny::new(DateFilterPB { - condition: DateFilterConditionPB::DateOnOrBefore, + condition: DateFilterConditionPB::DateStartsOnOrBefore, start: None, end: None, timestamp: Some(1668359085), @@ -114,7 +114,7 @@ async fn grid_filter_date_within_test() { parent_filter_id: None, field_type: FieldType::DateTime, data: BoxAny::new(DateFilterPB { - condition: DateFilterConditionPB::DateWithIn, + condition: DateFilterConditionPB::DateStartsBetween, start: Some(1647251762), end: Some(1668704685), timestamp: None, diff --git a/frontend/rust-lib/flowy-database2/tests/database/group_test/script.rs b/frontend/rust-lib/flowy-database2/tests/database/group_test/script.rs index ce3fbe090e6c..f37b37cbbfa3 100644 --- a/frontend/rust-lib/flowy-database2/tests/database/group_test/script.rs +++ b/frontend/rust-lib/flowy-database2/tests/database/group_test/script.rs @@ -211,9 +211,13 @@ impl DatabaseGroupTest { let field_type = FieldType::from(field.field_type); let cell = match field_type { FieldType::URL => insert_url_cell(cell_data, &field), - FieldType::DateTime => { - insert_date_cell(cell_data.parse::().unwrap(), None, Some(true), &field) - }, + FieldType::DateTime => insert_date_cell( + cell_data.parse::().unwrap(), + None, + None, + Some(true), + &field, + ), _ => { panic!("Unsupported group field type"); }, diff --git a/frontend/rust-lib/flowy-database2/tests/database/pre_fill_cell_test/pre_fill_row_according_to_filter_test.rs b/frontend/rust-lib/flowy-database2/tests/database/pre_fill_cell_test/pre_fill_row_according_to_filter_test.rs index bc8fe23e9e16..e391eabce872 100644 --- a/frontend/rust-lib/flowy-database2/tests/database/pre_fill_cell_test/pre_fill_row_according_to_filter_test.rs +++ b/frontend/rust-lib/flowy-database2/tests/database/pre_fill_cell_test/pre_fill_row_according_to_filter_test.rs @@ -215,7 +215,7 @@ async fn according_to_date_time_is_filter_test() { field_id: datetime_field.id.clone(), field_type: FieldType::DateTime, data: DateFilterPB { - condition: DateFilterConditionPB::DateIs, + condition: DateFilterConditionPB::DateStartsOn, timestamp: Some(1710510086), ..Default::default() } @@ -262,7 +262,7 @@ async fn according_to_invalid_date_time_is_filter_test() { field_id: datetime_field.id.clone(), field_type: FieldType::DateTime, data: DateFilterPB { - condition: DateFilterConditionPB::DateIs, + condition: DateFilterConditionPB::DateStartsOn, timestamp: None, ..Default::default() }