mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: support checklist
This commit is contained in:
@ -222,6 +222,7 @@
|
|||||||
"singleSelectFieldName": "Select",
|
"singleSelectFieldName": "Select",
|
||||||
"multiSelectFieldName": "Multiselect",
|
"multiSelectFieldName": "Multiselect",
|
||||||
"urlFieldName": "URL",
|
"urlFieldName": "URL",
|
||||||
|
"checklistFieldName": "Checklist",
|
||||||
"numberFormat": " Number format",
|
"numberFormat": " Number format",
|
||||||
"dateFormat": " Date format",
|
"dateFormat": " Date format",
|
||||||
"includeTime": " Include time",
|
"includeTime": " Include time",
|
||||||
|
@ -10,11 +10,3 @@ class BoardGroupService {
|
|||||||
groupField = field;
|
groupField = field;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class CanBeGroupField {
|
|
||||||
String get groupContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// class SingleSelectGroup extends CanBeGroupField {
|
|
||||||
// final SingleSelectTypeOptionContext typeOptionContext;
|
|
||||||
// }
|
|
||||||
|
@ -358,6 +358,8 @@ Widget? _buildHeaderIcon(GroupData customData) {
|
|||||||
break;
|
break;
|
||||||
case FieldType.URL:
|
case FieldType.URL:
|
||||||
break;
|
break;
|
||||||
|
case FieldType.CheckList:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widget != null) {
|
if (widget != null) {
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class BoardChecklistCell extends StatelessWidget {
|
||||||
|
const BoardChecklistCell({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
import 'board_cell.dart';
|
import 'board_cell.dart';
|
||||||
import 'board_checkbox_cell.dart';
|
import 'board_checkbox_cell.dart';
|
||||||
|
import 'board_checklist_cell.dart';
|
||||||
import 'board_date_cell.dart';
|
import 'board_date_cell.dart';
|
||||||
import 'board_number_cell.dart';
|
import 'board_number_cell.dart';
|
||||||
import 'board_select_option_cell.dart';
|
import 'board_select_option_cell.dart';
|
||||||
@ -58,6 +59,10 @@ class BoardCellBuilder {
|
|||||||
editableNotifier: cellNotifier,
|
editableNotifier: cellNotifier,
|
||||||
key: key,
|
key: key,
|
||||||
);
|
);
|
||||||
|
case FieldType.CheckList:
|
||||||
|
return BoardChecklistCell(
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
case FieldType.Number:
|
case FieldType.Number:
|
||||||
return BoardNumberCell(
|
return BoardNumberCell(
|
||||||
groupId: groupId,
|
groupId: groupId,
|
||||||
|
@ -81,6 +81,7 @@ class GridCellControllerBuilder {
|
|||||||
);
|
);
|
||||||
case FieldType.MultiSelect:
|
case FieldType.MultiSelect:
|
||||||
case FieldType.SingleSelect:
|
case FieldType.SingleSelect:
|
||||||
|
case FieldType.CheckList:
|
||||||
final cellDataLoader = GridCellDataLoader(
|
final cellDataLoader = GridCellDataLoader(
|
||||||
cellId: _cellId,
|
cellId: _cellId,
|
||||||
parser: SelectOptionCellDataParser(),
|
parser: SelectOptionCellDataParser(),
|
||||||
|
@ -506,22 +506,12 @@ class FieldInfo {
|
|||||||
bool get canGroup {
|
bool get canGroup {
|
||||||
switch (_field.fieldType) {
|
switch (_field.fieldType) {
|
||||||
case FieldType.Checkbox:
|
case FieldType.Checkbox:
|
||||||
return true;
|
|
||||||
case FieldType.DateTime:
|
|
||||||
return false;
|
|
||||||
case FieldType.MultiSelect:
|
case FieldType.MultiSelect:
|
||||||
return true;
|
|
||||||
case FieldType.Number:
|
|
||||||
return false;
|
|
||||||
case FieldType.RichText:
|
|
||||||
return false;
|
|
||||||
case FieldType.SingleSelect:
|
case FieldType.SingleSelect:
|
||||||
return true;
|
return true;
|
||||||
case FieldType.URL:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get canCreateFilter {
|
bool get canCreateFilter {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid/checklist_type_option.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
@ -95,6 +96,17 @@ class MultiSelectTypeOptionWidgetDataParser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Multi-select
|
||||||
|
typedef ChecklistTypeOptionContext = TypeOptionContext<ChecklistTypeOptionPB>;
|
||||||
|
|
||||||
|
class ChecklistTypeOptionWidgetDataParser
|
||||||
|
extends TypeOptionDataParser<ChecklistTypeOptionPB> {
|
||||||
|
@override
|
||||||
|
ChecklistTypeOptionPB fromBuffer(List<int> buffer) {
|
||||||
|
return ChecklistTypeOptionPB.fromBuffer(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TypeOptionContext<T extends GeneratedMessage> {
|
class TypeOptionContext<T extends GeneratedMessage> {
|
||||||
T? _typeOptionObject;
|
T? _typeOptionObject;
|
||||||
final TypeOptionDataParser<T> dataParser;
|
final TypeOptionDataParser<T> dataParser;
|
||||||
|
@ -2,6 +2,7 @@ import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
|
|||||||
import 'package:dartz/dartz.dart';
|
import 'package:dartz/dartz.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pbserver.dart';
|
import 'package:flowy_sdk/protobuf/flowy-error/errors.pbserver.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_filter.pbenum.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_filter.pbenum.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid/checklist_filter.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_filter.pbenum.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/date_filter.pbenum.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/number_filter.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/number_filter.pb.dart';
|
||||||
@ -104,6 +105,11 @@ class GridCreateFilterBloc
|
|||||||
condition: SelectOptionCondition.OptionIs,
|
condition: SelectOptionCondition.OptionIs,
|
||||||
fieldType: FieldType.MultiSelect,
|
fieldType: FieldType.MultiSelect,
|
||||||
);
|
);
|
||||||
|
case FieldType.CheckList:
|
||||||
|
return _ffiService.insertChecklistFilter(
|
||||||
|
fieldId: fieldId,
|
||||||
|
condition: ChecklistFilterCondition.IsIncomplete,
|
||||||
|
);
|
||||||
case FieldType.Number:
|
case FieldType.Number:
|
||||||
return _ffiService.insertNumberFilter(
|
return _ffiService.insertNumberFilter(
|
||||||
fieldId: fieldId,
|
fieldId: fieldId,
|
||||||
|
@ -3,6 +3,7 @@ import 'package:flowy_sdk/dispatch/dispatch.dart';
|
|||||||
import 'package:flowy_sdk/log.dart';
|
import 'package:flowy_sdk/log.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_filter.pbserver.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_filter.pbserver.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid/checklist_filter.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_filter.pbserver.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/date_filter.pbserver.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
|
||||||
@ -145,6 +146,24 @@ class FilterFFIService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Either<Unit, FlowyError>> insertChecklistFilter({
|
||||||
|
required String fieldId,
|
||||||
|
required ChecklistFilterCondition condition,
|
||||||
|
String? filterId,
|
||||||
|
List<String> optionIds = const [],
|
||||||
|
}) {
|
||||||
|
final filter = ChecklistFilterPB()
|
||||||
|
..condition = condition
|
||||||
|
..optionIds.addAll(optionIds);
|
||||||
|
|
||||||
|
return insertFilter(
|
||||||
|
fieldId: fieldId,
|
||||||
|
filterId: filterId,
|
||||||
|
fieldType: FieldType.CheckList,
|
||||||
|
data: filter.writeToBuffer(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<Either<Unit, FlowyError>> insertFilter({
|
Future<Either<Unit, FlowyError>> insertFilter({
|
||||||
required String fieldId,
|
required String fieldId,
|
||||||
String? filterId,
|
String? filterId,
|
||||||
|
@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'cell_accessory.dart';
|
import 'cell_accessory.dart';
|
||||||
import 'cell_shortcuts.dart';
|
import 'cell_shortcuts.dart';
|
||||||
import 'checkbox_cell.dart';
|
import 'checkbox_cell.dart';
|
||||||
|
import 'checklist_cell.dart';
|
||||||
import 'date_cell/date_cell.dart';
|
import 'date_cell/date_cell.dart';
|
||||||
import 'number_cell.dart';
|
import 'number_cell.dart';
|
||||||
import 'select_option_cell/select_option_cell.dart';
|
import 'select_option_cell/select_option_cell.dart';
|
||||||
@ -55,6 +56,10 @@ class GridCellBuilder {
|
|||||||
style: style,
|
style: style,
|
||||||
key: key,
|
key: key,
|
||||||
);
|
);
|
||||||
|
case FieldType.CheckList:
|
||||||
|
return GridChecklistCell(
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
case FieldType.Number:
|
case FieldType.Number:
|
||||||
return GridNumberCell(
|
return GridNumberCell(
|
||||||
cellControllerBuilder: cellControllerBuilder,
|
cellControllerBuilder: cellControllerBuilder,
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'cell_builder.dart';
|
||||||
|
|
||||||
|
class GridChecklistCell extends GridCellWidget {
|
||||||
|
GridChecklistCell({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ChecklistCellState createState() => ChecklistCellState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChecklistCellState extends State<GridChecklistCell> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
import 'package:app_flowy/plugins/grid/presentation/widgets/filter/filter_info.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'choicechip.dart';
|
||||||
|
|
||||||
|
class ChecklistFilterChoicechip extends StatelessWidget {
|
||||||
|
final FilterInfo filterInfo;
|
||||||
|
const ChecklistFilterChoicechip({required this.filterInfo, Key? key})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ChoiceChipButton(filterInfo: filterInfo);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pbenum.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'choicechip/checkbox.dart';
|
import 'choicechip/checkbox.dart';
|
||||||
|
import 'choicechip/checklist.dart';
|
||||||
import 'choicechip/date.dart';
|
import 'choicechip/date.dart';
|
||||||
import 'choicechip/number.dart';
|
import 'choicechip/number.dart';
|
||||||
import 'choicechip/select_option/select_option.dart';
|
import 'choicechip/select_option/select_option.dart';
|
||||||
@ -35,6 +36,8 @@ Widget buildFilterChoicechip(FilterInfo filterInfo) {
|
|||||||
return SelectOptionFilterChoicechip(filterInfo: filterInfo);
|
return SelectOptionFilterChoicechip(filterInfo: filterInfo);
|
||||||
case FieldType.URL:
|
case FieldType.URL:
|
||||||
return URLFilterChoicechip(filterInfo: filterInfo);
|
return URLFilterChoicechip(filterInfo: filterInfo);
|
||||||
|
case FieldType.CheckList:
|
||||||
|
return ChecklistFilterChoicechip(filterInfo: filterInfo);
|
||||||
default:
|
default:
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ extension FieldTypeListExtension on FieldType {
|
|||||||
return "grid/field/single_select";
|
return "grid/field/single_select";
|
||||||
case FieldType.URL:
|
case FieldType.URL:
|
||||||
return "grid/field/url";
|
return "grid/field/url";
|
||||||
|
case FieldType.CheckList:
|
||||||
|
return "grid/field/checklist";
|
||||||
}
|
}
|
||||||
throw UnimplementedError;
|
throw UnimplementedError;
|
||||||
}
|
}
|
||||||
@ -39,6 +41,8 @@ extension FieldTypeListExtension on FieldType {
|
|||||||
return LocaleKeys.grid_field_singleSelectFieldName.tr();
|
return LocaleKeys.grid_field_singleSelectFieldName.tr();
|
||||||
case FieldType.URL:
|
case FieldType.URL:
|
||||||
return LocaleKeys.grid_field_urlFieldName.tr();
|
return LocaleKeys.grid_field_urlFieldName.tr();
|
||||||
|
case FieldType.CheckList:
|
||||||
|
return LocaleKeys.grid_field_checklistFieldName.tr();
|
||||||
}
|
}
|
||||||
throw UnimplementedError;
|
throw UnimplementedError;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart';
|
|||||||
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/multi_select_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/multi_select_type_option.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart';
|
||||||
|
import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/single_select_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/single_select_type_option.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
|
||||||
@ -15,6 +16,7 @@ import 'package:protobuf/protobuf.dart' hide FieldInfo;
|
|||||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'checkbox.dart';
|
import 'checkbox.dart';
|
||||||
|
import 'checklist.dart';
|
||||||
import 'date.dart';
|
import 'date.dart';
|
||||||
import 'multi_select.dart';
|
import 'multi_select.dart';
|
||||||
import 'number.dart';
|
import 'number.dart';
|
||||||
@ -124,6 +126,15 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
|
|||||||
dataController: dataController,
|
dataController: dataController,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case FieldType.CheckList:
|
||||||
|
return ChecklistTypeOptionWidgetBuilder(
|
||||||
|
makeTypeOptionContextWithDataController<ChecklistTypeOptionPB>(
|
||||||
|
gridId: gridId,
|
||||||
|
fieldType: fieldType,
|
||||||
|
dataController: dataController,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
throw UnimplementedError;
|
throw UnimplementedError;
|
||||||
}
|
}
|
||||||
@ -206,6 +217,11 @@ TypeOptionContext<T>
|
|||||||
dataController: dataController,
|
dataController: dataController,
|
||||||
dataParser: MultiSelectTypeOptionWidgetDataParser(),
|
dataParser: MultiSelectTypeOptionWidgetDataParser(),
|
||||||
) as TypeOptionContext<T>;
|
) as TypeOptionContext<T>;
|
||||||
|
case FieldType.CheckList:
|
||||||
|
return ChecklistTypeOptionContext(
|
||||||
|
dataController: dataController,
|
||||||
|
dataParser: ChecklistTypeOptionWidgetDataParser(),
|
||||||
|
) as TypeOptionContext<T>;
|
||||||
case FieldType.Number:
|
case FieldType.Number:
|
||||||
return NumberTypeOptionContext(
|
return NumberTypeOptionContext(
|
||||||
dataController: dataController,
|
dataController: dataController,
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'builder.dart';
|
||||||
|
|
||||||
|
class ChecklistTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
|
||||||
|
ChecklistTypeOptionWidgetBuilder(
|
||||||
|
ChecklistTypeOptionContext typeOptionContext);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget? build(BuildContext context) => null;
|
||||||
|
}
|
@ -331,6 +331,10 @@ GridCellStyle? _customCellStyle(FieldType fieldType) {
|
|||||||
return SelectOptionCellStyle(
|
return SelectOptionCellStyle(
|
||||||
placeholder: LocaleKeys.grid_row_textPlaceholder.tr(),
|
placeholder: LocaleKeys.grid_row_textPlaceholder.tr(),
|
||||||
);
|
);
|
||||||
|
case FieldType.CheckList:
|
||||||
|
return SelectOptionCellStyle(
|
||||||
|
placeholder: LocaleKeys.grid_row_textPlaceholder.tr(),
|
||||||
|
);
|
||||||
case FieldType.Number:
|
case FieldType.Number:
|
||||||
return null;
|
return null;
|
||||||
case FieldType.RichText:
|
case FieldType.RichText:
|
||||||
|
@ -491,6 +491,7 @@ pub enum FieldType {
|
|||||||
MultiSelect = 4,
|
MultiSelect = 4,
|
||||||
Checkbox = 5,
|
Checkbox = 5,
|
||||||
URL = 6,
|
URL = 6,
|
||||||
|
CheckList = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const RICH_TEXT_FIELD: FieldType = FieldType::RichText;
|
pub const RICH_TEXT_FIELD: FieldType = FieldType::RichText;
|
||||||
@ -500,6 +501,7 @@ pub const SINGLE_SELECT_FIELD: FieldType = FieldType::SingleSelect;
|
|||||||
pub const MULTI_SELECT_FIELD: FieldType = FieldType::MultiSelect;
|
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;
|
||||||
|
|
||||||
impl std::default::Default for FieldType {
|
impl std::default::Default for FieldType {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -563,6 +565,10 @@ impl FieldType {
|
|||||||
self == &MULTI_SELECT_FIELD || self == &SINGLE_SELECT_FIELD
|
self == &MULTI_SELECT_FIELD || self == &SINGLE_SELECT_FIELD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_check_list(&self) -> bool {
|
||||||
|
self == &CHECKLIST_FIELD
|
||||||
|
}
|
||||||
|
|
||||||
pub fn can_be_group(&self) -> bool {
|
pub fn can_be_group(&self) -> bool {
|
||||||
self.is_select_option()
|
self.is_select_option()
|
||||||
}
|
}
|
||||||
@ -596,8 +602,9 @@ impl std::convert::From<FieldTypeRevision> for FieldType {
|
|||||||
4 => FieldType::MultiSelect,
|
4 => FieldType::MultiSelect,
|
||||||
5 => FieldType::Checkbox,
|
5 => FieldType::Checkbox,
|
||||||
6 => FieldType::URL,
|
6 => FieldType::URL,
|
||||||
|
7 => FieldType::CheckList,
|
||||||
_ => {
|
_ => {
|
||||||
tracing::error!("Can't parser FieldTypeRevision: {} to FieldType", ty);
|
tracing::error!("Can't convert FieldTypeRevision: {} to FieldType", ty);
|
||||||
FieldType::RichText
|
FieldType::RichText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
use crate::services::field::SelectOptionIds;
|
||||||
|
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||||
|
use flowy_error::ErrorCode;
|
||||||
|
use grid_rev_model::FilterRevision;
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||||
|
pub struct ChecklistFilterPB {
|
||||||
|
#[pb(index = 1)]
|
||||||
|
pub condition: ChecklistFilterCondition,
|
||||||
|
|
||||||
|
#[pb(index = 2)]
|
||||||
|
pub option_ids: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum ChecklistFilterCondition {
|
||||||
|
IsComplete = 0,
|
||||||
|
IsIncomplete = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<ChecklistFilterCondition> for u32 {
|
||||||
|
fn from(value: ChecklistFilterCondition) -> Self {
|
||||||
|
value as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::default::Default for ChecklistFilterCondition {
|
||||||
|
fn default() -> Self {
|
||||||
|
ChecklistFilterCondition::IsIncomplete
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::TryFrom<u8> for ChecklistFilterCondition {
|
||||||
|
type Error = ErrorCode;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(ChecklistFilterCondition::IsComplete),
|
||||||
|
1 => Ok(ChecklistFilterCondition::IsIncomplete),
|
||||||
|
_ => Err(ErrorCode::InvalidData),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<&FilterRevision> for ChecklistFilterPB {
|
||||||
|
fn from(rev: &FilterRevision) -> Self {
|
||||||
|
let ids = SelectOptionIds::from(rev.content.clone());
|
||||||
|
ChecklistFilterPB {
|
||||||
|
condition: ChecklistFilterCondition::try_from(rev.condition)
|
||||||
|
.unwrap_or(ChecklistFilterCondition::IsIncomplete),
|
||||||
|
option_ids: ids.into_inner(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
mod checkbox_filter;
|
mod checkbox_filter;
|
||||||
|
mod checklist_filter;
|
||||||
mod date_filter;
|
mod date_filter;
|
||||||
mod filter_changeset;
|
mod filter_changeset;
|
||||||
mod number_filter;
|
mod number_filter;
|
||||||
@ -7,6 +8,7 @@ mod text_filter;
|
|||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub use checkbox_filter::*;
|
pub use checkbox_filter::*;
|
||||||
|
pub use checklist_filter::*;
|
||||||
pub use date_filter::*;
|
pub use date_filter::*;
|
||||||
pub use filter_changeset::*;
|
pub use filter_changeset::*;
|
||||||
pub use number_filter::*;
|
pub use number_filter::*;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::entities::parser::NotEmptyStr;
|
use crate::entities::parser::NotEmptyStr;
|
||||||
use crate::entities::{
|
use crate::entities::{
|
||||||
CheckboxFilterPB, DateFilterContent, DateFilterPB, FieldType, NumberFilterPB, SelectOptionFilterPB, TextFilterPB,
|
CheckboxFilterPB, ChecklistFilterPB, DateFilterContent, DateFilterPB, FieldType, NumberFilterPB,
|
||||||
|
SelectOptionFilterPB, TextFilterPB,
|
||||||
};
|
};
|
||||||
use crate::services::field::SelectOptionIds;
|
use crate::services::field::SelectOptionIds;
|
||||||
use crate::services::filter::FilterType;
|
use crate::services::filter::FilterType;
|
||||||
@ -35,6 +36,7 @@ impl std::convert::From<&FilterRevision> for FilterPB {
|
|||||||
FieldType::DateTime => DateFilterPB::from(rev).try_into().unwrap(),
|
FieldType::DateTime => DateFilterPB::from(rev).try_into().unwrap(),
|
||||||
FieldType::SingleSelect => SelectOptionFilterPB::from(rev).try_into().unwrap(),
|
FieldType::SingleSelect => SelectOptionFilterPB::from(rev).try_into().unwrap(),
|
||||||
FieldType::MultiSelect => SelectOptionFilterPB::from(rev).try_into().unwrap(),
|
FieldType::MultiSelect => SelectOptionFilterPB::from(rev).try_into().unwrap(),
|
||||||
|
FieldType::CheckList => ChecklistFilterPB::from(rev).try_into().unwrap(),
|
||||||
FieldType::Checkbox => CheckboxFilterPB::from(rev).try_into().unwrap(),
|
FieldType::Checkbox => CheckboxFilterPB::from(rev).try_into().unwrap(),
|
||||||
FieldType::URL => TextFilterPB::from(rev).try_into().unwrap(),
|
FieldType::URL => TextFilterPB::from(rev).try_into().unwrap(),
|
||||||
};
|
};
|
||||||
@ -174,7 +176,7 @@ impl TryInto<AlterFilterParams> for AlterFilterPayloadPB {
|
|||||||
}
|
}
|
||||||
.to_string();
|
.to_string();
|
||||||
}
|
}
|
||||||
FieldType::SingleSelect | FieldType::MultiSelect => {
|
FieldType::SingleSelect | FieldType::MultiSelect | FieldType::CheckList => {
|
||||||
let filter = SelectOptionFilterPB::try_from(bytes).map_err(|_| ErrorCode::ProtobufSerde)?;
|
let filter = SelectOptionFilterPB::try_from(bytes).map_err(|_| ErrorCode::ProtobufSerde)?;
|
||||||
condition = filter.condition as u8;
|
condition = filter.condition as u8;
|
||||||
content = SelectOptionIds::from(filter.option_ids).to_string();
|
content = SelectOptionIds::from(filter.option_ids).to_string();
|
||||||
|
@ -104,6 +104,9 @@ impl TypeCellData {
|
|||||||
pub fn is_multi_select(&self) -> bool {
|
pub fn is_multi_select(&self) -> bool {
|
||||||
self.field_type == FieldType::MultiSelect
|
self.field_type == FieldType::MultiSelect
|
||||||
}
|
}
|
||||||
|
pub fn is_checklist(&self) -> bool {
|
||||||
|
self.field_type == FieldType::CheckList
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_url(&self) -> bool {
|
pub fn is_url(&self) -> bool {
|
||||||
self.field_type == FieldType::URL
|
self.field_type == FieldType::URL
|
||||||
|
@ -122,6 +122,7 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
|
|||||||
SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
|
SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
|
||||||
}
|
}
|
||||||
FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
|
FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
|
||||||
|
FieldType::CheckList => ChecklistTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
|
||||||
FieldType::Checkbox => CheckboxTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
|
FieldType::Checkbox => CheckboxTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
|
||||||
FieldType::URL => URLTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
|
FieldType::URL => URLTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
|
||||||
}?;
|
}?;
|
||||||
@ -180,6 +181,9 @@ pub fn decode_cell_data_to_string(
|
|||||||
FieldType::MultiSelect => field_rev
|
FieldType::MultiSelect => field_rev
|
||||||
.get_type_option::<MultiSelectTypeOptionPB>(field_type)?
|
.get_type_option::<MultiSelectTypeOptionPB>(field_type)?
|
||||||
.displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
.displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
||||||
|
FieldType::CheckList => field_rev
|
||||||
|
.get_type_option::<ChecklistTypeOptionPB>(field_type)?
|
||||||
|
.displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
||||||
FieldType::Checkbox => field_rev
|
FieldType::Checkbox => field_rev
|
||||||
.get_type_option::<CheckboxTypeOptionPB>(field_type)?
|
.get_type_option::<CheckboxTypeOptionPB>(field_type)?
|
||||||
.displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
.displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
||||||
@ -230,6 +234,9 @@ pub fn try_decode_cell_data(
|
|||||||
FieldType::MultiSelect => field_rev
|
FieldType::MultiSelect => field_rev
|
||||||
.get_type_option::<MultiSelectTypeOptionPB>(field_type)?
|
.get_type_option::<MultiSelectTypeOptionPB>(field_type)?
|
||||||
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||||
|
FieldType::CheckList => field_rev
|
||||||
|
.get_type_option::<ChecklistTypeOptionPB>(field_type)?
|
||||||
|
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||||
FieldType::Checkbox => field_rev
|
FieldType::Checkbox => field_rev
|
||||||
.get_type_option::<CheckboxTypeOptionPB>(field_type)?
|
.get_type_option::<CheckboxTypeOptionPB>(field_type)?
|
||||||
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
.decode_cell_data(cell_data.into(), from_field_type, field_rev),
|
||||||
|
@ -38,6 +38,7 @@ pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn
|
|||||||
FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(),
|
FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(),
|
||||||
FieldType::Checkbox => CheckboxTypeOptionPB::default().into(),
|
FieldType::Checkbox => CheckboxTypeOptionPB::default().into(),
|
||||||
FieldType::URL => URLTypeOptionPB::default().into(),
|
FieldType::URL => URLTypeOptionPB::default().into(),
|
||||||
|
FieldType::CheckList => ChecklistTypeOptionPB::default().into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
type_option_builder_from_json_str(&s, field_type)
|
type_option_builder_from_json_str(&s, field_type)
|
||||||
@ -52,6 +53,7 @@ pub fn type_option_builder_from_json_str(s: &str, field_type: &FieldType) -> Box
|
|||||||
FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_json_str(s)),
|
FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_json_str(s)),
|
||||||
FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_json_str(s)),
|
FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_json_str(s)),
|
||||||
FieldType::URL => Box::new(URLTypeOptionBuilder::from_json_str(s)),
|
FieldType::URL => Box::new(URLTypeOptionBuilder::from_json_str(s)),
|
||||||
|
FieldType::CheckList => Box::new(ChecklistTypeOptionBuilder::from_json_str(s)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,5 +67,6 @@ pub fn type_option_builder_from_bytes<T: Into<Bytes>>(bytes: T, field_type: &Fie
|
|||||||
FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
|
FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
|
||||||
FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_protobuf_bytes(bytes)),
|
FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_protobuf_bytes(bytes)),
|
||||||
FieldType::URL => Box::new(URLTypeOptionBuilder::from_protobuf_bytes(bytes)),
|
FieldType::URL => Box::new(URLTypeOptionBuilder::from_protobuf_bytes(bytes)),
|
||||||
|
FieldType::CheckList => Box::new(ChecklistTypeOptionBuilder::from_protobuf_bytes(bytes)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
use crate::entities::ChecklistFilterPB;
|
||||||
|
use crate::services::field::SelectedSelectOptions;
|
||||||
|
|
||||||
|
impl ChecklistFilterPB {
|
||||||
|
pub fn is_visible(&self, selected_options: &SelectedSelectOptions) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
use crate::entities::FieldType;
|
||||||
|
use crate::impl_type_option;
|
||||||
|
use crate::services::cell::{AnyCellChangeset, CellBytes, CellData, CellDataOperation, CellDisplayable};
|
||||||
|
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
|
||||||
|
use crate::services::field::type_options::util::get_cell_data;
|
||||||
|
use crate::services::field::{
|
||||||
|
BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionIds, SelectOptionPB, SelectTypeOptionSharedAction,
|
||||||
|
TypeOptionBuilder,
|
||||||
|
};
|
||||||
|
use bytes::Bytes;
|
||||||
|
use flowy_derive::ProtoBuf;
|
||||||
|
use flowy_error::{FlowyError, FlowyResult};
|
||||||
|
use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
// Multiple select
|
||||||
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
|
||||||
|
pub struct ChecklistTypeOptionPB {
|
||||||
|
#[pb(index = 1)]
|
||||||
|
pub options: Vec<SelectOptionPB>,
|
||||||
|
|
||||||
|
#[pb(index = 2)]
|
||||||
|
pub disable_color: bool,
|
||||||
|
}
|
||||||
|
impl_type_option!(ChecklistTypeOptionPB, FieldType::CheckList);
|
||||||
|
|
||||||
|
impl SelectTypeOptionSharedAction for ChecklistTypeOptionPB {
|
||||||
|
fn number_of_max_options(&self) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn options(&self) -> &Vec<SelectOptionPB> {
|
||||||
|
&self.options
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_options(&mut self) -> &mut Vec<SelectOptionPB> {
|
||||||
|
&mut self.options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for ChecklistTypeOptionPB {
|
||||||
|
fn decode_cell_data(
|
||||||
|
&self,
|
||||||
|
cell_data: CellData<SelectOptionIds>,
|
||||||
|
decoded_field_type: &FieldType,
|
||||||
|
field_rev: &FieldRevision,
|
||||||
|
) -> FlowyResult<CellBytes> {
|
||||||
|
self.displayed_cell_bytes(cell_data, decoded_field_type, field_rev)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_changeset(
|
||||||
|
&self,
|
||||||
|
changeset: AnyCellChangeset<SelectOptionCellChangeset>,
|
||||||
|
cell_rev: Option<CellRevision>,
|
||||||
|
) -> Result<String, FlowyError> {
|
||||||
|
let content_changeset = changeset.try_into_inner()?;
|
||||||
|
|
||||||
|
let insert_option_ids = content_changeset
|
||||||
|
.insert_option_ids
|
||||||
|
.into_iter()
|
||||||
|
.filter(|insert_option_id| self.options.iter().any(|option| &option.id == insert_option_id))
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
|
let new_cell_data: String;
|
||||||
|
match cell_rev {
|
||||||
|
None => {
|
||||||
|
new_cell_data = SelectOptionIds::from(insert_option_ids).to_string();
|
||||||
|
}
|
||||||
|
Some(cell_rev) => {
|
||||||
|
let cell_data = get_cell_data(&cell_rev);
|
||||||
|
let mut select_ids: SelectOptionIds = cell_data.into();
|
||||||
|
for insert_option_id in insert_option_ids {
|
||||||
|
if !select_ids.contains(&insert_option_id) {
|
||||||
|
select_ids.push(insert_option_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for delete_option_id in content_changeset.delete_option_ids {
|
||||||
|
select_ids.retain(|id| id != &delete_option_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_cell_data = select_ids.to_string();
|
||||||
|
tracing::trace!("checklist's cell data: {}", &new_cell_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(new_cell_data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ChecklistTypeOptionBuilder(ChecklistTypeOptionPB);
|
||||||
|
impl_into_box_type_option_builder!(ChecklistTypeOptionBuilder);
|
||||||
|
impl_builder_from_json_str_and_from_bytes!(ChecklistTypeOptionBuilder, ChecklistTypeOptionPB);
|
||||||
|
impl ChecklistTypeOptionBuilder {
|
||||||
|
pub fn add_option(mut self, opt: SelectOptionPB) -> Self {
|
||||||
|
self.0.options.push(opt);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeOptionBuilder for ChecklistTypeOptionBuilder {
|
||||||
|
fn field_type(&self) -> FieldType {
|
||||||
|
FieldType::CheckList
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serializer(&self) -> &dyn TypeOptionDataSerializer {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform(&mut self, field_type: &FieldType, type_option_data: String) {
|
||||||
|
SelectOptionTypeOptionTransformer::transform_type_option(&mut self.0, field_type, type_option_data)
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,14 @@
|
|||||||
|
mod checklist_filter;
|
||||||
|
mod checklist_type_option;
|
||||||
mod multi_select_type_option;
|
mod multi_select_type_option;
|
||||||
mod select_filter;
|
mod select_filter;
|
||||||
mod select_type_option;
|
mod select_type_option;
|
||||||
mod single_select_type_option;
|
mod single_select_type_option;
|
||||||
mod type_option_transform;
|
mod type_option_transform;
|
||||||
|
|
||||||
|
pub use checklist_type_option::*;
|
||||||
pub use multi_select_type_option::*;
|
pub use multi_select_type_option::*;
|
||||||
pub use select_type_option::*;
|
pub use select_type_option::*;
|
||||||
pub use single_select_type_option::*;
|
pub use single_select_type_option::*;
|
||||||
|
|
||||||
|
pub use checklist_filter::*;
|
||||||
|
@ -80,7 +80,7 @@ impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for MultiSele
|
|||||||
}
|
}
|
||||||
|
|
||||||
new_cell_data = select_ids.to_string();
|
new_cell_data = select_ids.to_string();
|
||||||
tracing::trace!("Multi select cell data: {}", &new_cell_data);
|
tracing::trace!("Multi-select cell data: {}", &new_cell_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#![allow(clippy::needless_collect)]
|
#![allow(clippy::needless_collect)]
|
||||||
|
|
||||||
use crate::entities::{SelectOptionCondition, SelectOptionFilterPB};
|
use crate::entities::{ChecklistFilterPB, SelectOptionCondition, SelectOptionFilterPB};
|
||||||
use crate::services::cell::{CellFilterOperation, TypeCellData};
|
use crate::services::cell::{CellFilterOperation, TypeCellData};
|
||||||
use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
|
use crate::services::field::{ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
|
||||||
use crate::services::field::{SelectTypeOptionSharedAction, SelectedSelectOptions};
|
use crate::services::field::{SelectTypeOptionSharedAction, SelectedSelectOptions};
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
|
|
||||||
@ -61,6 +61,16 @@ impl CellFilterOperation<SelectOptionFilterPB> for SingleSelectTypeOptionPB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CellFilterOperation<ChecklistFilterPB> for ChecklistTypeOptionPB {
|
||||||
|
fn apply_filter(&self, any_cell_data: TypeCellData, filter: &ChecklistFilterPB) -> FlowyResult<bool> {
|
||||||
|
if !any_cell_data.is_checklist() {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
let selected_options = SelectedSelectOptions::from(self.get_selected_options(any_cell_data.into()));
|
||||||
|
Ok(filter.is_visible(&selected_options))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::all)]
|
#![allow(clippy::all)]
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use crate::entities::{CheckboxFilterPB, DateFilterPB, FieldType, NumberFilterPB, SelectOptionFilterPB, TextFilterPB};
|
use crate::entities::{
|
||||||
|
CheckboxFilterPB, ChecklistFilterPB, DateFilterPB, FieldType, NumberFilterPB, SelectOptionFilterPB, TextFilterPB,
|
||||||
|
};
|
||||||
use crate::services::filter::FilterType;
|
use crate::services::filter::FilterType;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -10,6 +12,7 @@ pub(crate) struct FilterMap {
|
|||||||
pub(crate) date_filter: HashMap<FilterType, DateFilterPB>,
|
pub(crate) date_filter: HashMap<FilterType, DateFilterPB>,
|
||||||
pub(crate) select_option_filter: HashMap<FilterType, SelectOptionFilterPB>,
|
pub(crate) select_option_filter: HashMap<FilterType, SelectOptionFilterPB>,
|
||||||
pub(crate) checkbox_filter: HashMap<FilterType, CheckboxFilterPB>,
|
pub(crate) checkbox_filter: HashMap<FilterType, CheckboxFilterPB>,
|
||||||
|
pub(crate) checklist_filter: HashMap<FilterType, ChecklistFilterPB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilterMap {
|
impl FilterMap {
|
||||||
@ -26,6 +29,7 @@ impl FilterMap {
|
|||||||
FieldType::MultiSelect => self.select_option_filter.get(filter_type).is_some(),
|
FieldType::MultiSelect => self.select_option_filter.get(filter_type).is_some(),
|
||||||
FieldType::Checkbox => self.checkbox_filter.get(filter_type).is_some(),
|
FieldType::Checkbox => self.checkbox_filter.get(filter_type).is_some(),
|
||||||
FieldType::URL => self.url_filter.get(filter_type).is_some(),
|
FieldType::URL => self.url_filter.get(filter_type).is_some(),
|
||||||
|
FieldType::CheckList => self.checklist_filter.get(filter_type).is_some(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +87,9 @@ impl FilterMap {
|
|||||||
FieldType::URL => {
|
FieldType::URL => {
|
||||||
let _ = self.url_filter.remove(filter_id);
|
let _ = self.url_filter.remove(filter_id);
|
||||||
}
|
}
|
||||||
|
FieldType::CheckList => {
|
||||||
|
let _ = self.checklist_filter.remove(filter_id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,6 +291,12 @@ impl FilterController {
|
|||||||
.url_filter
|
.url_filter
|
||||||
.insert(filter_type, TextFilterPB::from(filter_rev.as_ref()));
|
.insert(filter_type, TextFilterPB::from(filter_rev.as_ref()));
|
||||||
}
|
}
|
||||||
|
FieldType::CheckList => {
|
||||||
|
let _ = self
|
||||||
|
.filter_map
|
||||||
|
.checklist_filter
|
||||||
|
.insert(filter_type, ChecklistFilterPB::from(filter_rev.as_ref()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,6 +419,14 @@ fn filter_cell(
|
|||||||
.ok(),
|
.ok(),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
FieldType::CheckList => filter_map.checklist_filter.get(filter_id).and_then(|filter| {
|
||||||
|
Some(
|
||||||
|
field_rev
|
||||||
|
.get_type_option::<ChecklistTypeOptionPB>(field_rev.ty)?
|
||||||
|
.apply_filter(any_cell_data, filter)
|
||||||
|
.ok(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
}?;
|
}?;
|
||||||
tracing::Span::current().record(
|
tracing::Span::current().record(
|
||||||
"cell_content",
|
"cell_content",
|
||||||
|
@ -123,6 +123,12 @@ pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurat
|
|||||||
SelectOptionGroupConfigurationRevision::default(),
|
SelectOptionGroupConfigurationRevision::default(),
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
FieldType::CheckList => GroupConfigurationRevision::new(
|
||||||
|
field_id,
|
||||||
|
field_type_rev,
|
||||||
|
SelectOptionGroupConfigurationRevision::default(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
FieldType::Checkbox => {
|
FieldType::Checkbox => {
|
||||||
GroupConfigurationRevision::new(field_id, field_type_rev, CheckboxGroupConfigurationRevision::default())
|
GroupConfigurationRevision::new(field_id, field_type_rev, CheckboxGroupConfigurationRevision::default())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -226,6 +226,24 @@ impl GridRowTest {
|
|||||||
assert_eq!(s, expected);
|
assert_eq!(s, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FieldType::CheckList => {
|
||||||
|
let cell_data = self
|
||||||
|
.editor
|
||||||
|
.get_cell_bytes(&cell_id)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.parser::<SelectOptionCellDataParser>()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let s = cell_data
|
||||||
|
.select_options
|
||||||
|
.into_iter()
|
||||||
|
.map(|option| option.name)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(SELECTION_IDS_SEPARATOR);
|
||||||
|
|
||||||
|
assert_eq!(s, expected);
|
||||||
|
}
|
||||||
FieldType::Checkbox => {
|
FieldType::Checkbox => {
|
||||||
let cell_data = self
|
let cell_data = self
|
||||||
.editor
|
.editor
|
||||||
|
@ -2,7 +2,7 @@ use flowy_grid::entities::FieldType;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use flowy_grid::services::field::{
|
use flowy_grid::services::field::{
|
||||||
DateCellChangeset, MultiSelectTypeOptionPB, SelectOptionPB, SingleSelectTypeOptionPB,
|
ChecklistTypeOptionPB, DateCellChangeset, MultiSelectTypeOptionPB, SelectOptionPB, SingleSelectTypeOptionPB,
|
||||||
};
|
};
|
||||||
use flowy_grid::services::row::RowRevisionBuilder;
|
use flowy_grid::services::row::RowRevisionBuilder;
|
||||||
use grid_rev_model::{FieldRevision, RowRevision};
|
use grid_rev_model::{FieldRevision, RowRevision};
|
||||||
@ -90,6 +90,19 @@ impl<'a> GridRowTestBuilder<'a> {
|
|||||||
multi_select_field.id.clone()
|
multi_select_field.id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_checklist_cell<F>(&mut self, f: F) -> String
|
||||||
|
where
|
||||||
|
F: Fn(Vec<SelectOptionPB>) -> Vec<SelectOptionPB>,
|
||||||
|
{
|
||||||
|
let checklist_field = self.field_rev_with_type(&FieldType::CheckList);
|
||||||
|
let type_option = ChecklistTypeOptionPB::from(&checklist_field);
|
||||||
|
let options = f(type_option.options);
|
||||||
|
let ops_ids = options.iter().map(|option| option.id.clone()).collect::<Vec<_>>();
|
||||||
|
self.inner_builder
|
||||||
|
.insert_select_option_cell(&multi_select_field.id, ops_ids);
|
||||||
|
|
||||||
|
checklist_field.id.clone()
|
||||||
|
}
|
||||||
pub fn field_rev_with_type(&self, field_type: &FieldType) -> FieldRevision {
|
pub fn field_rev_with_type(&self, field_type: &FieldType) -> FieldRevision {
|
||||||
self.field_revs
|
self.field_revs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -3,7 +3,7 @@ use crate::grid::cell_test::script::GridCellTest;
|
|||||||
use crate::grid::field_test::util::make_date_cell_string;
|
use crate::grid::field_test::util::make_date_cell_string;
|
||||||
use flowy_grid::entities::{CellChangesetPB, FieldType};
|
use flowy_grid::entities::{CellChangesetPB, FieldType};
|
||||||
use flowy_grid::services::field::selection_type_option::SelectOptionCellChangeset;
|
use flowy_grid::services::field::selection_type_option::SelectOptionCellChangeset;
|
||||||
use flowy_grid::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
|
use flowy_grid::services::field::{ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn grid_cell_update() {
|
async fn grid_cell_update() {
|
||||||
@ -31,6 +31,10 @@ async fn grid_cell_update() {
|
|||||||
let type_option = MultiSelectTypeOptionPB::from(field_rev);
|
let type_option = MultiSelectTypeOptionPB::from(field_rev);
|
||||||
SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id).to_str()
|
SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id).to_str()
|
||||||
}
|
}
|
||||||
|
FieldType::CheckList => {
|
||||||
|
let type_option = ChecklistTypeOptionPB::from(field_rev);
|
||||||
|
SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id).to_str()
|
||||||
|
}
|
||||||
FieldType::Checkbox => "1".to_string(),
|
FieldType::Checkbox => "1".to_string(),
|
||||||
FieldType::URL => "1".to_string(),
|
FieldType::URL => "1".to_string(),
|
||||||
};
|
};
|
||||||
|
@ -153,6 +153,9 @@ pub const COMPLETED: &str = "Completed";
|
|||||||
pub const PLANNED: &str = "Planned";
|
pub const PLANNED: &str = "Planned";
|
||||||
pub const PAUSED: &str = "Paused";
|
pub const PAUSED: &str = "Paused";
|
||||||
|
|
||||||
|
pub const FIRST_THING: &str = "Wake up at 6:00 am";
|
||||||
|
pub const SECOND_THING: &str = "Get some coffee";
|
||||||
|
pub const THIRD_THING: &str = "Start working";
|
||||||
// This grid is assumed to contain all the Fields.
|
// This grid is assumed to contain all the Fields.
|
||||||
fn make_test_grid() -> BuildGridContext {
|
fn make_test_grid() -> BuildGridContext {
|
||||||
let mut grid_builder = GridBuilder::new();
|
let mut grid_builder = GridBuilder::new();
|
||||||
@ -217,6 +220,14 @@ fn make_test_grid() -> BuildGridContext {
|
|||||||
let url_field = FieldBuilder::new(url).name("link").visibility(true).build();
|
let url_field = FieldBuilder::new(url).name("link").visibility(true).build();
|
||||||
grid_builder.add_field(url_field);
|
grid_builder.add_field(url_field);
|
||||||
}
|
}
|
||||||
|
FieldType::CheckList => {
|
||||||
|
let checklist = ChecklistTypeOptionBuilder::default()
|
||||||
|
.add_option(SelectOptionPB::new(FIRST_THING))
|
||||||
|
.add_option(SelectOptionPB::new(SECOND_THING))
|
||||||
|
.add_option(SelectOptionPB::new(THIRD_THING));
|
||||||
|
let checklist_field = FieldBuilder::new(checklist).name("TODO").visibility(true).build();
|
||||||
|
grid_builder.add_field(checklist_field);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +245,7 @@ fn make_test_grid() -> BuildGridContext {
|
|||||||
FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
|
FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
|
||||||
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::Checkbox => row_builder.insert_checkbox_cell("true"),
|
FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
|
||||||
_ => "".to_owned(),
|
_ => "".to_owned(),
|
||||||
};
|
};
|
||||||
@ -370,6 +382,7 @@ fn make_test_board() -> BuildGridContext {
|
|||||||
let url_field = FieldBuilder::new(url).name("link").visibility(true).build();
|
let url_field = FieldBuilder::new(url).name("link").visibility(true).build();
|
||||||
grid_builder.add_field(url_field);
|
grid_builder.add_field(url_field);
|
||||||
}
|
}
|
||||||
|
FieldType::CheckList => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user