mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-16 14:40:43 +03:00
fix: number and select filter logic (#4828)
* fix: number and select option filter bugs * chore: rename filter condition enum and variants
This commit is contained in:
parent
1a34366a3f
commit
5a837a9482
2
frontend/.vscode/tasks.json
vendored
2
frontend/.vscode/tasks.json
vendored
@ -257,7 +257,7 @@
|
||||
"label": "AF: Tauri UI Dev",
|
||||
"type": "shell",
|
||||
"isBackground": true,
|
||||
"command": "pnpm run sync:i18n && pnpm run dev",
|
||||
"command": "pnpm sync:i18n && pnpm run dev",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/appflowy_tauri"
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ void main() {
|
||||
// select the option 's4'
|
||||
await tester.tapOptionFilterWithName('s4');
|
||||
|
||||
// The row with 's4' or 's5' should be shown.
|
||||
await tester.assertNumberOfRowsInGridPage(2);
|
||||
// The row with 's4' should be shown.
|
||||
await tester.assertNumberOfRowsInGridPage(1);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
@ -171,7 +171,7 @@ class FilterBackendService {
|
||||
Future<FlowyResult<void, FlowyError>> insertSelectOptionFilter({
|
||||
required String fieldId,
|
||||
required FieldType fieldType,
|
||||
required SelectOptionConditionPB condition,
|
||||
required SelectOptionFilterConditionPB condition,
|
||||
String? filterId,
|
||||
List<String> optionIds = const [],
|
||||
}) {
|
||||
|
@ -114,7 +114,7 @@ class GridCreateFilterBloc
|
||||
case FieldType.MultiSelect:
|
||||
return _filterBackendSvc.insertSelectOptionFilter(
|
||||
fieldId: fieldId,
|
||||
condition: SelectOptionConditionPB.OptionIs,
|
||||
condition: SelectOptionFilterConditionPB.OptionContains,
|
||||
fieldType: FieldType.MultiSelect,
|
||||
);
|
||||
case FieldType.Checklist:
|
||||
@ -130,19 +130,19 @@ class GridCreateFilterBloc
|
||||
case FieldType.RichText:
|
||||
return _filterBackendSvc.insertTextFilter(
|
||||
fieldId: fieldId,
|
||||
condition: TextFilterConditionPB.Contains,
|
||||
condition: TextFilterConditionPB.TextContains,
|
||||
content: '',
|
||||
);
|
||||
case FieldType.SingleSelect:
|
||||
return _filterBackendSvc.insertSelectOptionFilter(
|
||||
fieldId: fieldId,
|
||||
condition: SelectOptionConditionPB.OptionIs,
|
||||
condition: SelectOptionFilterConditionPB.OptionIs,
|
||||
fieldType: FieldType.SingleSelect,
|
||||
);
|
||||
case FieldType.URL:
|
||||
return _filterBackendSvc.insertURLFilter(
|
||||
fieldId: fieldId,
|
||||
condition: TextFilterConditionPB.Contains,
|
||||
condition: TextFilterConditionPB.TextContains,
|
||||
);
|
||||
default:
|
||||
throw UnimplementedError();
|
||||
|
@ -38,7 +38,7 @@ class SelectOptionFilterEditorBloc
|
||||
_startListening();
|
||||
_loadOptions();
|
||||
},
|
||||
updateCondition: (SelectOptionConditionPB condition) {
|
||||
updateCondition: (SelectOptionFilterConditionPB condition) {
|
||||
_filterBackendSvc.insertSelectOptionFilter(
|
||||
filterId: filterInfo.filter.id,
|
||||
fieldId: filterInfo.fieldInfo.id,
|
||||
@ -117,7 +117,7 @@ class SelectOptionFilterEditorEvent with _$SelectOptionFilterEditorEvent {
|
||||
FilterPB filter,
|
||||
) = _DidReceiveFilter;
|
||||
const factory SelectOptionFilterEditorEvent.updateCondition(
|
||||
SelectOptionConditionPB condition,
|
||||
SelectOptionFilterConditionPB condition,
|
||||
) = _UpdateCondition;
|
||||
const factory SelectOptionFilterEditorEvent.updateContent(
|
||||
List<String> optionIds,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/choicechip/select_option/select_option_loader.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
@ -24,9 +24,12 @@ class SelectOptionFilterListBloc<T>
|
||||
_startListening();
|
||||
_loadOptions();
|
||||
},
|
||||
selectOption: (option) {
|
||||
final selectedOptionIds = Set<String>.from(state.selectedOptionIds);
|
||||
selectedOptionIds.add(option.id);
|
||||
selectOption: (option, condition) {
|
||||
final selectedOptionIds = delegate.selectOption(
|
||||
state.selectedOptionIds,
|
||||
option.id,
|
||||
condition,
|
||||
);
|
||||
|
||||
_updateSelectOptions(
|
||||
selectedOptionIds: selectedOptionIds,
|
||||
@ -116,6 +119,7 @@ class SelectOptionFilterListEvent with _$SelectOptionFilterListEvent {
|
||||
const factory SelectOptionFilterListEvent.initial() = _Initial;
|
||||
const factory SelectOptionFilterListEvent.selectOption(
|
||||
SelectOptionPB option,
|
||||
SelectOptionFilterConditionPB condition,
|
||||
) = _SelectOption;
|
||||
const factory SelectOptionFilterListEvent.unselectOption(
|
||||
SelectOptionPB option,
|
||||
|
@ -1,15 +1,12 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/condition_button.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/filter_info.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_filter.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../condition_button.dart';
|
||||
import '../../filter_info.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class SelectOptionFilterConditionList extends StatelessWidget {
|
||||
const SelectOptionFilterConditionList({
|
||||
@ -21,7 +18,7 @@ class SelectOptionFilterConditionList extends StatelessWidget {
|
||||
|
||||
final FilterInfo filterInfo;
|
||||
final PopoverMutex popoverMutex;
|
||||
final Function(SelectOptionConditionPB) onCondition;
|
||||
final Function(SelectOptionFilterConditionPB) onCondition;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -30,18 +27,17 @@ class SelectOptionFilterConditionList extends StatelessWidget {
|
||||
asBarrier: true,
|
||||
mutex: popoverMutex,
|
||||
direction: PopoverDirection.bottomWithCenterAligned,
|
||||
actions: SelectOptionConditionPB.values
|
||||
actions: _conditionsForFieldType(filterInfo.fieldInfo.fieldType)
|
||||
.map(
|
||||
(action) => ConditionWrapper(
|
||||
action,
|
||||
selectOptionFilter.condition == action,
|
||||
filterInfo.fieldInfo.fieldType,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
buildChild: (controller) {
|
||||
return ConditionButton(
|
||||
conditionName: filterName(selectOptionFilter),
|
||||
conditionName: selectOptionFilter.condition.i18n,
|
||||
onTap: () => controller.show(),
|
||||
);
|
||||
},
|
||||
@ -52,69 +48,62 @@ class SelectOptionFilterConditionList extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
String filterName(SelectOptionFilterPB filter) {
|
||||
if (filterInfo.fieldInfo.fieldType == FieldType.SingleSelect) {
|
||||
return filter.condition.singleSelectFilterName;
|
||||
} else {
|
||||
return filter.condition.multiSelectFilterName;
|
||||
}
|
||||
List<SelectOptionFilterConditionPB> _conditionsForFieldType(
|
||||
FieldType fieldType,
|
||||
) {
|
||||
// SelectOptionFilterConditionPB.values is not in order
|
||||
return switch (fieldType) {
|
||||
FieldType.SingleSelect => [
|
||||
SelectOptionFilterConditionPB.OptionIs,
|
||||
SelectOptionFilterConditionPB.OptionIsNot,
|
||||
SelectOptionFilterConditionPB.OptionIsEmpty,
|
||||
SelectOptionFilterConditionPB.OptionIsNotEmpty,
|
||||
],
|
||||
FieldType.MultiSelect => [
|
||||
SelectOptionFilterConditionPB.OptionContains,
|
||||
SelectOptionFilterConditionPB.OptionDoesNotContain,
|
||||
SelectOptionFilterConditionPB.OptionIs,
|
||||
SelectOptionFilterConditionPB.OptionIsNot,
|
||||
SelectOptionFilterConditionPB.OptionIsEmpty,
|
||||
SelectOptionFilterConditionPB.OptionIsNotEmpty,
|
||||
],
|
||||
_ => [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class ConditionWrapper extends ActionCell {
|
||||
ConditionWrapper(this.inner, this.isSelected, this.fieldType);
|
||||
ConditionWrapper(this.inner, this.isSelected);
|
||||
|
||||
final SelectOptionConditionPB inner;
|
||||
final SelectOptionFilterConditionPB inner;
|
||||
final bool isSelected;
|
||||
final FieldType fieldType;
|
||||
|
||||
@override
|
||||
Widget? rightIcon(Color iconColor) {
|
||||
if (isSelected) {
|
||||
return const FlowySvg(FlowySvgs.check_s);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return isSelected ? const FlowySvg(FlowySvgs.check_s) : null;
|
||||
}
|
||||
|
||||
@override
|
||||
String get name {
|
||||
if (fieldType == FieldType.SingleSelect) {
|
||||
return inner.singleSelectFilterName;
|
||||
} else {
|
||||
return inner.multiSelectFilterName;
|
||||
}
|
||||
}
|
||||
String get name => inner.i18n;
|
||||
}
|
||||
|
||||
extension SelectOptionConditionPBExtension on SelectOptionConditionPB {
|
||||
String get singleSelectFilterName {
|
||||
switch (this) {
|
||||
case SelectOptionConditionPB.OptionIs:
|
||||
return LocaleKeys.grid_singleSelectOptionFilter_is.tr();
|
||||
case SelectOptionConditionPB.OptionIsEmpty:
|
||||
return LocaleKeys.grid_singleSelectOptionFilter_isEmpty.tr();
|
||||
case SelectOptionConditionPB.OptionIsNot:
|
||||
return LocaleKeys.grid_singleSelectOptionFilter_isNot.tr();
|
||||
case SelectOptionConditionPB.OptionIsNotEmpty:
|
||||
return LocaleKeys.grid_singleSelectOptionFilter_isNotEmpty.tr();
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
String get multiSelectFilterName {
|
||||
switch (this) {
|
||||
case SelectOptionConditionPB.OptionIs:
|
||||
return LocaleKeys.grid_multiSelectOptionFilter_contains.tr();
|
||||
case SelectOptionConditionPB.OptionIsEmpty:
|
||||
return LocaleKeys.grid_multiSelectOptionFilter_isEmpty.tr();
|
||||
case SelectOptionConditionPB.OptionIsNot:
|
||||
return LocaleKeys.grid_multiSelectOptionFilter_doesNotContain.tr();
|
||||
case SelectOptionConditionPB.OptionIsNotEmpty:
|
||||
return LocaleKeys.grid_multiSelectOptionFilter_isNotEmpty.tr();
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
extension SelectOptionFilterConditionPBExtension
|
||||
on SelectOptionFilterConditionPB {
|
||||
String get i18n {
|
||||
return switch (this) {
|
||||
SelectOptionFilterConditionPB.OptionIs =>
|
||||
LocaleKeys.grid_selectOptionFilter_is.tr(),
|
||||
SelectOptionFilterConditionPB.OptionIsNot =>
|
||||
LocaleKeys.grid_selectOptionFilter_isNot.tr(),
|
||||
SelectOptionFilterConditionPB.OptionContains =>
|
||||
LocaleKeys.grid_selectOptionFilter_isNot.tr(),
|
||||
SelectOptionFilterConditionPB.OptionDoesNotContain =>
|
||||
LocaleKeys.grid_selectOptionFilter_isNot.tr(),
|
||||
SelectOptionFilterConditionPB.OptionIsEmpty =>
|
||||
LocaleKeys.grid_selectOptionFilter_isEmpty.tr(),
|
||||
SelectOptionFilterConditionPB.OptionIsNotEmpty =>
|
||||
LocaleKeys.grid_selectOptionFilter_isNotEmpty.tr(),
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/plugins/database/grid/application/filter/select_option_filter_bloc.dart';
|
||||
import 'package:appflowy/plugins/database/grid/application/filter/select_option_filter_list_bloc.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/filter_info.dart';
|
||||
@ -90,9 +91,16 @@ class _SelectOptionFilterCellState extends State<SelectOptionFilterCell> {
|
||||
.read<SelectOptionFilterListBloc>()
|
||||
.add(SelectOptionFilterListEvent.unselectOption(widget.option));
|
||||
} else {
|
||||
context
|
||||
.read<SelectOptionFilterListBloc>()
|
||||
.add(SelectOptionFilterListEvent.selectOption(widget.option));
|
||||
context.read<SelectOptionFilterListBloc>().add(
|
||||
SelectOptionFilterListEvent.selectOption(
|
||||
widget.option,
|
||||
context
|
||||
.read<SelectOptionFilterEditorBloc>()
|
||||
.state
|
||||
.filter
|
||||
.condition,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
children: [
|
||||
|
@ -101,9 +101,10 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
|
||||
SliverToBoxAdapter(child: _buildFilterPanel(context, state)),
|
||||
];
|
||||
|
||||
if (state.filter.condition != SelectOptionConditionPB.OptionIsEmpty &&
|
||||
if (state.filter.condition !=
|
||||
SelectOptionFilterConditionPB.OptionIsEmpty &&
|
||||
state.filter.condition !=
|
||||
SelectOptionConditionPB.OptionIsNotEmpty) {
|
||||
SelectOptionFilterConditionPB.OptionIsNotEmpty) {
|
||||
slivers.add(const SliverToBoxAdapter(child: VSpace(4)));
|
||||
slivers.add(
|
||||
SliverToBoxAdapter(
|
||||
|
@ -1,9 +1,15 @@
|
||||
import 'package:appflowy/plugins/database/application/field/type_option/type_option_data_parser.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/filter_info.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_entities.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
|
||||
abstract class SelectOptionFilterDelegate {
|
||||
List<SelectOptionPB> loadOptions();
|
||||
|
||||
Set<String> selectOption(
|
||||
Set<String> currentOptionIds,
|
||||
String optionId,
|
||||
SelectOptionFilterConditionPB condition,
|
||||
);
|
||||
}
|
||||
|
||||
class SingleSelectOptionFilterDelegateImpl
|
||||
@ -17,6 +23,22 @@ class SingleSelectOptionFilterDelegateImpl
|
||||
final parser = SingleSelectTypeOptionDataParser();
|
||||
return parser.fromBuffer(filterInfo.fieldInfo.field.typeOptionData).options;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<String> selectOption(
|
||||
Set<String> currentOptionIds,
|
||||
String optionId,
|
||||
SelectOptionFilterConditionPB condition,
|
||||
) {
|
||||
final selectOptionIds = Set<String>.from(currentOptionIds);
|
||||
|
||||
if (condition == SelectOptionFilterConditionPB.OptionIsNot ||
|
||||
selectOptionIds.isEmpty) {
|
||||
selectOptionIds.add(optionId);
|
||||
}
|
||||
|
||||
return selectOptionIds;
|
||||
}
|
||||
}
|
||||
|
||||
class MultiSelectOptionFilterDelegateImpl
|
||||
@ -30,4 +52,12 @@ class MultiSelectOptionFilterDelegateImpl
|
||||
final parser = MultiSelectTypeOptionDataParser();
|
||||
return parser.fromBuffer(filterInfo.fieldInfo.field.typeOptionData).options;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<String> selectOption(
|
||||
Set<String> currentOptionIds,
|
||||
String optionId,
|
||||
SelectOptionFilterConditionPB condition,
|
||||
) =>
|
||||
Set<String>.from(currentOptionIds)..add(optionId);
|
||||
}
|
||||
|
@ -236,17 +236,17 @@ class ConditionWrapper extends ActionCell {
|
||||
extension TextFilterConditionPBExtension on TextFilterConditionPB {
|
||||
String get filterName {
|
||||
switch (this) {
|
||||
case TextFilterConditionPB.Contains:
|
||||
case TextFilterConditionPB.TextContains:
|
||||
return LocaleKeys.grid_textFilter_contains.tr();
|
||||
case TextFilterConditionPB.DoesNotContain:
|
||||
case TextFilterConditionPB.TextDoesNotContain:
|
||||
return LocaleKeys.grid_textFilter_doesNotContain.tr();
|
||||
case TextFilterConditionPB.EndsWith:
|
||||
case TextFilterConditionPB.TextEndsWith:
|
||||
return LocaleKeys.grid_textFilter_endsWith.tr();
|
||||
case TextFilterConditionPB.Is:
|
||||
case TextFilterConditionPB.TextIs:
|
||||
return LocaleKeys.grid_textFilter_is.tr();
|
||||
case TextFilterConditionPB.IsNot:
|
||||
case TextFilterConditionPB.TextIsNot:
|
||||
return LocaleKeys.grid_textFilter_isNot.tr();
|
||||
case TextFilterConditionPB.StartsWith:
|
||||
case TextFilterConditionPB.TextStartsWith:
|
||||
return LocaleKeys.grid_textFilter_startWith.tr();
|
||||
case TextFilterConditionPB.TextIsEmpty:
|
||||
return LocaleKeys.grid_textFilter_isEmpty.tr();
|
||||
@ -259,13 +259,13 @@ extension TextFilterConditionPBExtension on TextFilterConditionPB {
|
||||
|
||||
String get choicechipPrefix {
|
||||
switch (this) {
|
||||
case TextFilterConditionPB.DoesNotContain:
|
||||
case TextFilterConditionPB.TextDoesNotContain:
|
||||
return LocaleKeys.grid_textFilter_choicechipPrefix_isNot.tr();
|
||||
case TextFilterConditionPB.EndsWith:
|
||||
case TextFilterConditionPB.TextEndsWith:
|
||||
return LocaleKeys.grid_textFilter_choicechipPrefix_endWith.tr();
|
||||
case TextFilterConditionPB.IsNot:
|
||||
case TextFilterConditionPB.TextIsNot:
|
||||
return LocaleKeys.grid_textFilter_choicechipPrefix_isNot.tr();
|
||||
case TextFilterConditionPB.StartsWith:
|
||||
case TextFilterConditionPB.TextStartsWith:
|
||||
return LocaleKeys.grid_textFilter_choicechipPrefix_startWith.tr();
|
||||
case TextFilterConditionPB.TextIsEmpty:
|
||||
return LocaleKeys.grid_textFilter_choicechipPrefix_isEmpty.tr();
|
||||
|
@ -55,13 +55,13 @@ void main() {
|
||||
await service.insertTextFilter(
|
||||
fieldId: textField.id,
|
||||
filterId: textFilter.filter.id,
|
||||
condition: TextFilterConditionPB.Is,
|
||||
condition: TextFilterConditionPB.TextIs,
|
||||
content: "ABC",
|
||||
);
|
||||
await gridResponseFuture();
|
||||
assert(
|
||||
menuBloc.state.filters.first.textFilter()!.condition ==
|
||||
TextFilterConditionPB.Is,
|
||||
TextFilterConditionPB.TextIs,
|
||||
);
|
||||
assert(menuBloc.state.filters.first.textFilter()!.content == "ABC");
|
||||
});
|
||||
|
@ -118,7 +118,7 @@ void main() {
|
||||
// create a new filter
|
||||
await service.insertTextFilter(
|
||||
fieldId: textField.id,
|
||||
condition: TextFilterConditionPB.Is,
|
||||
condition: TextFilterConditionPB.TextIs,
|
||||
content: "A",
|
||||
);
|
||||
await gridResponseFuture();
|
||||
@ -132,7 +132,7 @@ void main() {
|
||||
await service.insertTextFilter(
|
||||
fieldId: textField.id,
|
||||
filterId: textFilter.filter.id,
|
||||
condition: TextFilterConditionPB.Is,
|
||||
condition: TextFilterConditionPB.TextIs,
|
||||
content: "B",
|
||||
);
|
||||
await gridResponseFuture();
|
||||
@ -142,7 +142,7 @@ void main() {
|
||||
await service.insertTextFilter(
|
||||
fieldId: textField.id,
|
||||
filterId: textFilter.filter.id,
|
||||
condition: TextFilterConditionPB.Is,
|
||||
condition: TextFilterConditionPB.TextIs,
|
||||
content: "b",
|
||||
);
|
||||
await gridResponseFuture();
|
||||
@ -152,7 +152,7 @@ void main() {
|
||||
await service.insertTextFilter(
|
||||
fieldId: textField.id,
|
||||
filterId: textFilter.filter.id,
|
||||
condition: TextFilterConditionPB.Is,
|
||||
condition: TextFilterConditionPB.TextIs,
|
||||
content: "C",
|
||||
);
|
||||
await gridResponseFuture();
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
ChecklistFilterConditionPB,
|
||||
FieldType,
|
||||
NumberFilterConditionPB,
|
||||
SelectOptionFilterConditionPB,
|
||||
TextFilterConditionPB,
|
||||
} from '@/services/backend';
|
||||
import { UndeterminedFilter } from '$app/application/database';
|
||||
@ -12,7 +13,7 @@ export function getDefaultFilter(fieldType: FieldType): UndeterminedFilter['data
|
||||
case FieldType.RichText:
|
||||
case FieldType.URL:
|
||||
return {
|
||||
condition: TextFilterConditionPB.Contains,
|
||||
condition: TextFilterConditionPB.TextContains,
|
||||
content: '',
|
||||
};
|
||||
case FieldType.Number:
|
||||
@ -27,6 +28,14 @@ export function getDefaultFilter(fieldType: FieldType): UndeterminedFilter['data
|
||||
return {
|
||||
condition: ChecklistFilterConditionPB.IsIncomplete,
|
||||
};
|
||||
case FieldType.SingleSelect:
|
||||
return {
|
||||
condition: SelectOptionFilterConditionPB.OptionIs,
|
||||
};
|
||||
case FieldType.MultiSelect:
|
||||
return {
|
||||
condition: SelectOptionFilterConditionPB.OptionContains,
|
||||
};
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
FilterPB,
|
||||
NumberFilterConditionPB,
|
||||
NumberFilterPB,
|
||||
SelectOptionConditionPB,
|
||||
SelectOptionFilterConditionPB,
|
||||
SelectOptionFilterPB,
|
||||
TextFilterConditionPB,
|
||||
TextFilterPB,
|
||||
@ -66,7 +66,7 @@ export interface ChecklistFilterData {
|
||||
}
|
||||
|
||||
export interface SelectFilterData {
|
||||
condition?: SelectOptionConditionPB;
|
||||
condition?: SelectOptionFilterConditionPB;
|
||||
optionIds?: string[];
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
DateFilterConditionPB,
|
||||
FieldType,
|
||||
NumberFilterConditionPB,
|
||||
SelectOptionConditionPB,
|
||||
SelectOptionFilterConditionPB,
|
||||
TextFilterConditionPB,
|
||||
} from '@/services/backend';
|
||||
|
||||
@ -30,27 +30,27 @@ function FilterConditionSelect({
|
||||
case FieldType.URL:
|
||||
return [
|
||||
{
|
||||
value: TextFilterConditionPB.Contains,
|
||||
value: TextFilterConditionPB.TextContains,
|
||||
text: t('grid.textFilter.contains'),
|
||||
},
|
||||
{
|
||||
value: TextFilterConditionPB.DoesNotContain,
|
||||
value: TextFilterConditionPB.TextDoesNotContain,
|
||||
text: t('grid.textFilter.doesNotContain'),
|
||||
},
|
||||
{
|
||||
value: TextFilterConditionPB.StartsWith,
|
||||
value: TextFilterConditionPB.TextStartsWith,
|
||||
text: t('grid.textFilter.startWith'),
|
||||
},
|
||||
{
|
||||
value: TextFilterConditionPB.EndsWith,
|
||||
value: TextFilterConditionPB.TextEndsWith,
|
||||
text: t('grid.textFilter.endsWith'),
|
||||
},
|
||||
{
|
||||
value: TextFilterConditionPB.Is,
|
||||
value: TextFilterConditionPB.TextIs,
|
||||
text: t('grid.textFilter.is'),
|
||||
},
|
||||
{
|
||||
value: TextFilterConditionPB.IsNot,
|
||||
value: TextFilterConditionPB.TextIsNot,
|
||||
text: t('grid.textFilter.isNot'),
|
||||
},
|
||||
{
|
||||
@ -63,26 +63,51 @@ function FilterConditionSelect({
|
||||
},
|
||||
];
|
||||
case FieldType.SingleSelect:
|
||||
return [
|
||||
{
|
||||
value: SelectOptionFilterConditionPB.OptionIs,
|
||||
text: t('grid.selectOptionFilter.is'),
|
||||
},
|
||||
{
|
||||
value: SelectOptionFilterConditionPB.OptionIsNot,
|
||||
text: t('grid.selectOptionFilter.isNot'),
|
||||
},
|
||||
{
|
||||
value: SelectOptionFilterConditionPB.OptionIsEmpty,
|
||||
text: t('grid.selectOptionFilter.isEmpty'),
|
||||
},
|
||||
{
|
||||
value: SelectOptionFilterConditionPB.OptionIsNotEmpty,
|
||||
text: t('grid.selectOptionFilter.isNotEmpty'),
|
||||
},
|
||||
];
|
||||
case FieldType.MultiSelect:
|
||||
return [
|
||||
{
|
||||
value: SelectOptionConditionPB.OptionIs,
|
||||
text: t('grid.singleSelectOptionFilter.is'),
|
||||
value: SelectOptionFilterConditionPB.OptionIs,
|
||||
text: t('grid.selectOptionFilter.is'),
|
||||
},
|
||||
{
|
||||
value: SelectOptionConditionPB.OptionIsNot,
|
||||
text: t('grid.singleSelectOptionFilter.isNot'),
|
||||
value: SelectOptionFilterConditionPB.OptionIsNot,
|
||||
text: t('grid.selectOptionFilter.isNot'),
|
||||
},
|
||||
{
|
||||
value: SelectOptionConditionPB.OptionIsEmpty,
|
||||
text: t('grid.singleSelectOptionFilter.isEmpty'),
|
||||
value: SelectOptionFilterConditionPB.OptionContains,
|
||||
text: t('grid.selectOptionFilter.contains'),
|
||||
},
|
||||
{
|
||||
value: SelectOptionConditionPB.OptionIsNotEmpty,
|
||||
text: t('grid.singleSelectOptionFilter.isNotEmpty'),
|
||||
value: SelectOptionFilterConditionPB.OptionDoesNotContain,
|
||||
text: t('grid.selectOptionFilter.doesNotContain'),
|
||||
},
|
||||
{
|
||||
value: SelectOptionFilterConditionPB.OptionIsEmpty,
|
||||
text: t('grid.selectOptionFilter.isEmpty'),
|
||||
},
|
||||
{
|
||||
value: SelectOptionFilterConditionPB.OptionIsNotEmpty,
|
||||
text: t('grid.selectOptionFilter.isNotEmpty'),
|
||||
},
|
||||
];
|
||||
|
||||
case FieldType.Number:
|
||||
return [
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
} from '$app/application/database';
|
||||
import { Tag } from '$app/components/database/components/field_types/select/Tag';
|
||||
import { ReactComponent as SelectCheckSvg } from '$app/assets/select-check.svg';
|
||||
import { SelectOptionConditionPB } from '@/services/backend';
|
||||
import { SelectOptionFilterConditionPB } from '@/services/backend';
|
||||
import { useTypeOption } from '$app/components/database';
|
||||
import KeyboardNavigation, {
|
||||
KeyboardNavigationOption,
|
||||
@ -42,8 +42,8 @@ function SelectFilter({ onClose, filter, field, onChange }: Props) {
|
||||
|
||||
const showOptions =
|
||||
options.length > 0 &&
|
||||
condition !== SelectOptionConditionPB.OptionIsEmpty &&
|
||||
condition !== SelectOptionConditionPB.OptionIsNotEmpty;
|
||||
condition !== SelectOptionFilterConditionPB.OptionIsEmpty &&
|
||||
condition !== SelectOptionFilterConditionPB.OptionIsNotEmpty;
|
||||
|
||||
const handleChange = ({
|
||||
condition,
|
||||
|
@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
|
||||
import { SelectFilterData, SelectTypeOption } from '$app/application/database';
|
||||
import { useStaticTypeOption } from '$app/components/database';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SelectOptionConditionPB } from '@/services/backend';
|
||||
import { SelectOptionFilterConditionPB } from '@/services/backend';
|
||||
|
||||
function SelectFilterValue({ data, fieldId }: { data: SelectFilterData; fieldId: string }) {
|
||||
const typeOption = useStaticTypeOption<SelectTypeOption>(fieldId);
|
||||
@ -19,13 +19,13 @@ function SelectFilterValue({ data, fieldId }: { data: SelectFilterData; fieldId:
|
||||
.join(', ');
|
||||
|
||||
switch (data.condition) {
|
||||
case SelectOptionConditionPB.OptionIs:
|
||||
case SelectOptionFilterConditionPB.OptionIs:
|
||||
return `: ${options}`;
|
||||
case SelectOptionConditionPB.OptionIsNot:
|
||||
case SelectOptionFilterConditionPB.OptionIsNot:
|
||||
return `: ${t('grid.textFilter.choicechipPrefix.isNot')} ${options}`;
|
||||
case SelectOptionConditionPB.OptionIsEmpty:
|
||||
case SelectOptionFilterConditionPB.OptionIsEmpty:
|
||||
return `: ${t('grid.textFilter.choicechipPrefix.isEmpty')}`;
|
||||
case SelectOptionConditionPB.OptionIsNotEmpty:
|
||||
case SelectOptionFilterConditionPB.OptionIsNotEmpty:
|
||||
return `: ${t('grid.textFilter.choicechipPrefix.isNotEmpty')}`;
|
||||
default:
|
||||
return '';
|
||||
|
@ -9,15 +9,15 @@ function TextFilterValue({ data }: { data: TextFilterData }) {
|
||||
const value = useMemo(() => {
|
||||
if (!data.content) return '';
|
||||
switch (data.condition) {
|
||||
case TextFilterConditionPB.Contains:
|
||||
case TextFilterConditionPB.Is:
|
||||
case TextFilterConditionPB.TextContains:
|
||||
case TextFilterConditionPB.TextIs:
|
||||
return `: ${data.content}`;
|
||||
case TextFilterConditionPB.DoesNotContain:
|
||||
case TextFilterConditionPB.IsNot:
|
||||
case TextFilterConditionPB.TextDoesNotContain:
|
||||
case TextFilterConditionPB.TextIsNot:
|
||||
return `: ${t('grid.textFilter.choicechipPrefix.isNot')} ${data.content}`;
|
||||
case TextFilterConditionPB.StartsWith:
|
||||
case TextFilterConditionPB.TextStartsWith:
|
||||
return `: ${t('grid.textFilter.choicechipPrefix.startWith')} ${data.content}`;
|
||||
case TextFilterConditionPB.EndsWith:
|
||||
case TextFilterConditionPB.TextEndsWith:
|
||||
return `: ${t('grid.textFilter.choicechipPrefix.endWith')} ${data.content}`;
|
||||
case TextFilterConditionPB.TextIsEmpty:
|
||||
return `: ${t('grid.textFilter.choicechipPrefix.isEmpty')}`;
|
||||
|
@ -422,13 +422,9 @@
|
||||
"isComplete": "አይደለም",
|
||||
"isIncomplted": "ባዶ ነው"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "ነው",
|
||||
"isNot": "አይደለም",
|
||||
"isEmpty": "ባዶ ነው",
|
||||
"isNotEmpty": "ባዶ አይደለም"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "ይይዛል",
|
||||
"doesNotContain": "አይይዝም",
|
||||
"isEmpty": "ባዶ ነው",
|
||||
|
@ -486,13 +486,9 @@
|
||||
"isComplete": "كاملة",
|
||||
"isIncomplted": "غير مكتمل"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "يكون",
|
||||
"isNot": "ليس",
|
||||
"isEmpty": "فارغ",
|
||||
"isNotEmpty": "ليس فارغا"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "يتضمن",
|
||||
"doesNotContain": "لا يحتوي",
|
||||
"isEmpty": "فارغ",
|
||||
@ -1172,4 +1168,4 @@
|
||||
"addField": "إضافة حقل",
|
||||
"userIcon": "رمز المستخدم"
|
||||
}
|
||||
}
|
||||
}
|
@ -459,13 +459,9 @@
|
||||
"isComplete": "està completa",
|
||||
"isIncomplted": "és incompleta"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "És",
|
||||
"isNot": "No és",
|
||||
"isEmpty": "Està buit",
|
||||
"isNotEmpty": "No està buit"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Conté",
|
||||
"doesNotContain": "No conté",
|
||||
"isEmpty": "Està buit",
|
||||
@ -811,4 +807,4 @@
|
||||
"deleteContentTitle": "Esteu segur que voleu suprimir {pageType}?",
|
||||
"deleteContentCaption": "si suprimiu aquest {pageType}, podeu restaurar-lo des de la paperera."
|
||||
}
|
||||
}
|
||||
}
|
@ -356,13 +356,9 @@
|
||||
"isComplete": "تەواوە",
|
||||
"isIncomplted": "ناتەواوە"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "هەیە",
|
||||
"isNot": "نییە",
|
||||
"isEmpty": "بهتاڵه",
|
||||
"isNotEmpty": "بەتاڵ نییە"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "لەخۆ دەگرێت",
|
||||
"doesNotContain": "لەخۆناگرێت",
|
||||
"isEmpty": "بهتاڵه",
|
||||
@ -673,4 +669,4 @@
|
||||
"frequentlyUsed": "زۆرجار بەکارت هێناوە"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -503,13 +503,9 @@
|
||||
"isComplete": "ist komplett",
|
||||
"isIncomplted": "ist unvollständig"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Ist",
|
||||
"isNot": "Ist nicht",
|
||||
"isEmpty": "Ist leer",
|
||||
"isNotEmpty": "Ist nicht leer"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Enthält",
|
||||
"doesNotContain": "Beinhaltet nicht",
|
||||
"isEmpty": "Ist leer",
|
||||
@ -1202,4 +1198,4 @@
|
||||
"addField": "Ein Feld hinzufügen",
|
||||
"userIcon": "Nutzerbild"
|
||||
}
|
||||
}
|
||||
}
|
@ -570,13 +570,9 @@
|
||||
"isComplete": "is complete",
|
||||
"isIncomplted": "is incomplete"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Is",
|
||||
"isNot": "Is not",
|
||||
"isEmpty": "Is empty",
|
||||
"isNotEmpty": "Is not empty"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Contains",
|
||||
"doesNotContain": "Does not contain",
|
||||
"isEmpty": "Is empty",
|
||||
|
@ -500,13 +500,9 @@
|
||||
"isComplete": "Esta completo",
|
||||
"isIncomplted": "esta incompleto"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Es",
|
||||
"isNot": "No es",
|
||||
"isEmpty": "Esta vacio",
|
||||
"isNotEmpty": "No está vacío"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Contiene",
|
||||
"doesNotContain": "No contiene",
|
||||
"isEmpty": "Esta vacio",
|
||||
@ -1063,4 +1059,4 @@
|
||||
"backgroundColorPink": "fondo rosa",
|
||||
"backgroundColorRed": "fondo rojo"
|
||||
}
|
||||
}
|
||||
}
|
@ -323,13 +323,9 @@
|
||||
"isComplete": "osatu da",
|
||||
"isIncomplted": "osatu gabe dago"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "da",
|
||||
"isNot": "Ez da",
|
||||
"isEmpty": "Hutsa dago",
|
||||
"isNotEmpty": "Ez dago hutsik"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Duen",
|
||||
"doesNotContain": "Ez dauka",
|
||||
"isEmpty": "Hutsa dago",
|
||||
@ -600,4 +596,4 @@
|
||||
"deleteContentTitle": "Ziur {pageType} ezabatu nahi duzula?",
|
||||
"deleteContentCaption": "{pageType} hau ezabatzen baduzu, zaborrontzitik leheneratu dezakezu."
|
||||
}
|
||||
}
|
||||
}
|
@ -356,13 +356,9 @@
|
||||
"isComplete": "کامل است",
|
||||
"isIncomplted": "کامل نیست"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "است",
|
||||
"isNot": "نیست",
|
||||
"isEmpty": "خالی است",
|
||||
"isNotEmpty": "خالی نیست"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "شامل",
|
||||
"doesNotContain": "شامل نیست",
|
||||
"isEmpty": "خالی است",
|
||||
@ -673,4 +669,4 @@
|
||||
"frequentlyUsed": "استفادهشده"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -521,13 +521,9 @@
|
||||
"isComplete": "fait",
|
||||
"isIncomplted": "pas fait"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Est",
|
||||
"isNot": "N'est pas",
|
||||
"isEmpty": "Est vide",
|
||||
"isNotEmpty": "N'est pas vide"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Contient",
|
||||
"doesNotContain": "Ne contient pas",
|
||||
"isEmpty": "Est vide",
|
||||
|
@ -542,13 +542,9 @@
|
||||
"isComplete": "fait",
|
||||
"isIncomplted": "pas fait"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Est",
|
||||
"isNot": "N'est pas",
|
||||
"isEmpty": "Est vide",
|
||||
"isNotEmpty": "N'est pas vide"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Contient",
|
||||
"doesNotContain": "Ne contient pas",
|
||||
"isEmpty": "Est vide",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -325,13 +325,9 @@
|
||||
"isComplete": "teljes",
|
||||
"isIncomplted": "hiányos"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Is",
|
||||
"isNot": "Nem",
|
||||
"isEmpty": "Üres",
|
||||
"isNotEmpty": "Nem üres"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Tartalmaz",
|
||||
"doesNotContain": "Nem tartalmaz",
|
||||
"isEmpty": "Üres",
|
||||
@ -598,4 +594,4 @@
|
||||
"deleteContentTitle": "Biztosan törli a következőt: {pageType}?",
|
||||
"deleteContentCaption": "ha törli ezt a {pageType} oldalt, visszaállíthatja a kukából."
|
||||
}
|
||||
}
|
||||
}
|
@ -452,13 +452,9 @@
|
||||
"isComplete": "selesai",
|
||||
"isIncomplted": "tidak lengkap"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Adalah",
|
||||
"isNot": "Tidak",
|
||||
"isEmpty": "Kosong",
|
||||
"isNotEmpty": "Tidak kosong"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Mengandung",
|
||||
"doesNotContain": "Tidak mengandung",
|
||||
"isEmpty": "Kosong",
|
||||
@ -1021,4 +1017,4 @@
|
||||
"noFavorite": "Tidak ada halaman favorit",
|
||||
"noFavoriteHintText": "Geser halaman ke kiri untuk menambahkannya ke favorit Anda"
|
||||
}
|
||||
}
|
||||
}
|
@ -516,13 +516,9 @@
|
||||
"isComplete": "è completo",
|
||||
"isIncomplted": "è incompleto"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "È",
|
||||
"isNot": "Non è",
|
||||
"isEmpty": "È vuoto",
|
||||
"isNotEmpty": "Non è vuoto"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Contiene",
|
||||
"doesNotContain": "Non contiene",
|
||||
"isEmpty": "È vuoto",
|
||||
|
@ -412,13 +412,9 @@
|
||||
"isComplete": "完了",
|
||||
"isIncomplted": "未完了"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "等しい",
|
||||
"isNot": "等しくない",
|
||||
"isEmpty": "空である",
|
||||
"isNotEmpty": "空ではない"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "を含む",
|
||||
"doesNotContain": "を含まない",
|
||||
"isEmpty": "空である",
|
||||
@ -685,4 +681,4 @@
|
||||
"deleteContentTitle": "{pageType} を削除してもよろしいですか?",
|
||||
"deleteContentCaption": "この {pageType} を削除しても、ゴミ箱から復元できます。"
|
||||
}
|
||||
}
|
||||
}
|
@ -324,13 +324,9 @@
|
||||
"isComplete": "완료되었습니다",
|
||||
"isIncomplted": "불완전하다"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "~이다",
|
||||
"isNot": "아니다",
|
||||
"isEmpty": "비었다",
|
||||
"isNotEmpty": "비어 있지 않음"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "포함",
|
||||
"doesNotContain": "포함되어 있지 않다",
|
||||
"isEmpty": "비었다",
|
||||
@ -597,4 +593,4 @@
|
||||
"deleteContentTitle": "{pageType}을(를) 삭제하시겠습니까?",
|
||||
"deleteContentCaption": "이 {pageType}을(를) 삭제하면 휴지통에서 복원할 수 있습니다."
|
||||
}
|
||||
}
|
||||
}
|
@ -454,13 +454,9 @@
|
||||
"isComplete": "jest kompletna",
|
||||
"isIncomplted": "jest niekompletna"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Jest",
|
||||
"isNot": "Nie jest",
|
||||
"isEmpty": "Jest pusty",
|
||||
"isNotEmpty": "Nie jest pusty"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Zawiera",
|
||||
"doesNotContain": "Nie zawiera",
|
||||
"isEmpty": "Jest pusty",
|
||||
@ -1076,4 +1072,4 @@
|
||||
"language": "Język",
|
||||
"font": "Czcionka"
|
||||
}
|
||||
}
|
||||
}
|
@ -511,13 +511,9 @@
|
||||
"isComplete": "está completo",
|
||||
"isIncomplted": "está imcompleto"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Está",
|
||||
"isNot": "Não está",
|
||||
"isEmpty": "Está vazio",
|
||||
"isNotEmpty": "Não está vazio"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Contém",
|
||||
"doesNotContain": "Não contém",
|
||||
"isEmpty": "Está vazio",
|
||||
@ -1211,4 +1207,4 @@
|
||||
"addField": "Adicionar campo",
|
||||
"userIcon": "Ícone do usuário"
|
||||
}
|
||||
}
|
||||
}
|
@ -426,13 +426,9 @@
|
||||
"isComplete": "está completo",
|
||||
"isIncomplted": "está incompleto"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "É",
|
||||
"isNot": "não é",
|
||||
"isEmpty": "Está vazia",
|
||||
"isNotEmpty": "Não está vazio"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "contém",
|
||||
"doesNotContain": "Não contém",
|
||||
"isEmpty": "Está vazia",
|
||||
@ -856,4 +852,4 @@
|
||||
"noResult": "Nenhum resultado",
|
||||
"caseSensitive": "Maiúsculas e minúsculas"
|
||||
}
|
||||
}
|
||||
}
|
@ -528,13 +528,9 @@
|
||||
"isComplete": "завершено",
|
||||
"isIncomplted": "не завершено"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Является",
|
||||
"isNot": "Не является",
|
||||
"isEmpty": "Пусто",
|
||||
"isNotEmpty": "Не пусто"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Содержит",
|
||||
"doesNotContain": "Не содержит",
|
||||
"isEmpty": "Пусто",
|
||||
|
@ -322,13 +322,9 @@
|
||||
"isComplete": "är komplett",
|
||||
"isIncomplted": "är ofullständig"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Är",
|
||||
"isNot": "Är inte",
|
||||
"isEmpty": "Är tom",
|
||||
"isNotEmpty": "Är inte tom"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Innehåller",
|
||||
"doesNotContain": "Innehåller inte",
|
||||
"isEmpty": "Är tom",
|
||||
@ -595,4 +591,4 @@
|
||||
"deleteContentTitle": "Är du säker på att du vill ta bort {pageType}?",
|
||||
"deleteContentCaption": "om du tar bort denna {pageType} kan du återställa den från papperskorgen."
|
||||
}
|
||||
}
|
||||
}
|
@ -478,13 +478,9 @@
|
||||
"isComplete": "เสร็จสมบูรณ์",
|
||||
"isIncomplted": "ไม่เสร็จสมบูรณ์"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "เป็น",
|
||||
"isNot": "ไม่เป็น",
|
||||
"isEmpty": "ว่างเปล่า",
|
||||
"isNotEmpty": "ไม่ว่างเปล่า"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "ประกอบด้วย",
|
||||
"doesNotContain": "ไม่ประกอบด้วย",
|
||||
"isEmpty": "ว่างเปล่า",
|
||||
|
@ -454,13 +454,9 @@
|
||||
"isComplete": "Tamamlanmış",
|
||||
"isIncomplted": "Tamamlanmamış"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Şu olan",
|
||||
"isNot": "Şu olmayan",
|
||||
"isEmpty": "Boş olan",
|
||||
"isNotEmpty": "Boş olmayan"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Şunu içeren",
|
||||
"doesNotContain": "Şunu içermeyen",
|
||||
"isEmpty": "Boş olan",
|
||||
@ -1093,4 +1089,4 @@
|
||||
"language": "Dil",
|
||||
"font": "Yazı tipi"
|
||||
}
|
||||
}
|
||||
}
|
@ -281,7 +281,6 @@
|
||||
"auto": "АВТО",
|
||||
"fallback": "Такий же, як і напрямок макету"
|
||||
},
|
||||
|
||||
"themeUpload": {
|
||||
"button": "Завантажити",
|
||||
"uploadTheme": "Завантажити тему",
|
||||
@ -347,7 +346,6 @@
|
||||
"exportFileFail": "Помилка експорту файлу!",
|
||||
"export": "Експорт"
|
||||
},
|
||||
|
||||
"user": {
|
||||
"name": "Ім'я",
|
||||
"email": "Електронна пошта",
|
||||
@ -416,13 +414,9 @@
|
||||
"isComplete": "є завершено",
|
||||
"isIncomplted": "є незавершено"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "є",
|
||||
"isNot": "не є",
|
||||
"isEmpty": "порожнє",
|
||||
"isNotEmpty": "не порожнє"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Містить",
|
||||
"doesNotContain": "Не містить",
|
||||
"isEmpty": "порожнє",
|
||||
|
@ -391,7 +391,7 @@
|
||||
"isComplete": "مکمل ہے",
|
||||
"isIncomplted": "نامکمل ہے"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "ہے",
|
||||
"isNot": "نہیں ہے",
|
||||
"isEmpty": "خالی ہے",
|
||||
|
@ -491,13 +491,9 @@
|
||||
"isComplete": "hoàn tất",
|
||||
"isIncomplted": "chưa hoàn tất"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "Là",
|
||||
"isNot": "Không phải",
|
||||
"isEmpty": "Rỗng",
|
||||
"isNotEmpty": "Không rỗng"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "Chứa",
|
||||
"doesNotContain": "Không chứa",
|
||||
"isEmpty": "Rỗng",
|
||||
@ -811,4 +807,4 @@
|
||||
"font": "Phông chữ",
|
||||
"date": "Ngày"
|
||||
}
|
||||
}
|
||||
}
|
@ -531,13 +531,9 @@
|
||||
"isComplete": "已完成",
|
||||
"isIncomplted": "未完成"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "是",
|
||||
"isNot": "不是",
|
||||
"isEmpty": "为空",
|
||||
"isNotEmpty": "不为空"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "包含",
|
||||
"doesNotContain": "不包含",
|
||||
"isEmpty": "为空",
|
||||
|
@ -513,13 +513,9 @@
|
||||
"isComplete": "已完成",
|
||||
"isIncomplted": "未完成"
|
||||
},
|
||||
"singleSelectOptionFilter": {
|
||||
"selectOptionFilter": {
|
||||
"is": "是",
|
||||
"isNot": "不是",
|
||||
"isEmpty": "為空",
|
||||
"isNotEmpty": "不為空"
|
||||
},
|
||||
"multiSelectOptionFilter": {
|
||||
"contains": "包含",
|
||||
"doesNotContain": "不包含",
|
||||
"isEmpty": "為空",
|
||||
@ -1261,4 +1257,4 @@
|
||||
"userIcon": "使用者圖示"
|
||||
},
|
||||
"noLogFiles": "這裡沒有日誌記錄檔案"
|
||||
}
|
||||
}
|
@ -8,38 +8,41 @@ use crate::services::{field::SelectOptionIds, filter::ParseFilterData};
|
||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||
pub struct SelectOptionFilterPB {
|
||||
#[pb(index = 1)]
|
||||
pub condition: SelectOptionConditionPB,
|
||||
pub condition: SelectOptionFilterConditionPB,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub option_ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, ProtoBuf_Enum)]
|
||||
#[repr(u8)]
|
||||
#[derive(Default)]
|
||||
pub enum SelectOptionConditionPB {
|
||||
pub enum SelectOptionFilterConditionPB {
|
||||
#[default]
|
||||
OptionIs = 0,
|
||||
OptionIsNot = 1,
|
||||
OptionIsEmpty = 2,
|
||||
OptionIsNotEmpty = 3,
|
||||
OptionContains = 2,
|
||||
OptionDoesNotContain = 3,
|
||||
OptionIsEmpty = 4,
|
||||
OptionIsNotEmpty = 5,
|
||||
}
|
||||
|
||||
impl std::convert::From<SelectOptionConditionPB> for u32 {
|
||||
fn from(value: SelectOptionConditionPB) -> Self {
|
||||
impl From<SelectOptionFilterConditionPB> for u32 {
|
||||
fn from(value: SelectOptionFilterConditionPB) -> Self {
|
||||
value as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<u8> for SelectOptionConditionPB {
|
||||
impl TryFrom<u8> for SelectOptionFilterConditionPB {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(SelectOptionConditionPB::OptionIs),
|
||||
1 => Ok(SelectOptionConditionPB::OptionIsNot),
|
||||
2 => Ok(SelectOptionConditionPB::OptionIsEmpty),
|
||||
3 => Ok(SelectOptionConditionPB::OptionIsNotEmpty),
|
||||
0 => Ok(SelectOptionFilterConditionPB::OptionIs),
|
||||
1 => Ok(SelectOptionFilterConditionPB::OptionIsNot),
|
||||
2 => Ok(SelectOptionFilterConditionPB::OptionContains),
|
||||
3 => Ok(SelectOptionFilterConditionPB::OptionDoesNotContain),
|
||||
4 => Ok(SelectOptionFilterConditionPB::OptionIsEmpty),
|
||||
5 => Ok(SelectOptionFilterConditionPB::OptionIsNotEmpty),
|
||||
_ => Err(ErrorCode::InvalidParams),
|
||||
}
|
||||
}
|
||||
@ -47,8 +50,8 @@ impl std::convert::TryFrom<u8> for SelectOptionConditionPB {
|
||||
impl ParseFilterData for SelectOptionFilterPB {
|
||||
fn parse(condition: u8, content: String) -> Self {
|
||||
Self {
|
||||
condition: SelectOptionConditionPB::try_from(condition)
|
||||
.unwrap_or(SelectOptionConditionPB::OptionIs),
|
||||
condition: SelectOptionFilterConditionPB::try_from(condition)
|
||||
.unwrap_or(SelectOptionFilterConditionPB::OptionIs),
|
||||
option_ids: SelectOptionIds::from_str(&content)
|
||||
.unwrap_or_default()
|
||||
.into_inner(),
|
||||
|
@ -12,17 +12,16 @@ pub struct TextFilterPB {
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, ProtoBuf_Enum)]
|
||||
#[repr(u8)]
|
||||
#[derive(Default)]
|
||||
pub enum TextFilterConditionPB {
|
||||
#[default]
|
||||
Is = 0,
|
||||
IsNot = 1,
|
||||
Contains = 2,
|
||||
DoesNotContain = 3,
|
||||
StartsWith = 4,
|
||||
EndsWith = 5,
|
||||
TextIs = 0,
|
||||
TextIsNot = 1,
|
||||
TextContains = 2,
|
||||
TextDoesNotContain = 3,
|
||||
TextStartsWith = 4,
|
||||
TextEndsWith = 5,
|
||||
TextIsEmpty = 6,
|
||||
TextIsNotEmpty = 7,
|
||||
}
|
||||
@ -38,12 +37,12 @@ impl std::convert::TryFrom<u8> for TextFilterConditionPB {
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(TextFilterConditionPB::Is),
|
||||
1 => Ok(TextFilterConditionPB::IsNot),
|
||||
2 => Ok(TextFilterConditionPB::Contains),
|
||||
3 => Ok(TextFilterConditionPB::DoesNotContain),
|
||||
4 => Ok(TextFilterConditionPB::StartsWith),
|
||||
5 => Ok(TextFilterConditionPB::EndsWith),
|
||||
0 => Ok(TextFilterConditionPB::TextIs),
|
||||
1 => Ok(TextFilterConditionPB::TextIsNot),
|
||||
2 => Ok(TextFilterConditionPB::TextContains),
|
||||
3 => Ok(TextFilterConditionPB::TextDoesNotContain),
|
||||
4 => Ok(TextFilterConditionPB::TextStartsWith),
|
||||
5 => Ok(TextFilterConditionPB::TextEndsWith),
|
||||
6 => Ok(TextFilterConditionPB::TextIsEmpty),
|
||||
7 => Ok(TextFilterConditionPB::TextIsNotEmpty),
|
||||
_ => Err(ErrorCode::InvalidParams),
|
||||
@ -54,7 +53,8 @@ impl std::convert::TryFrom<u8> for TextFilterConditionPB {
|
||||
impl ParseFilterData for TextFilterPB {
|
||||
fn parse(condition: u8, content: String) -> Self {
|
||||
Self {
|
||||
condition: TextFilterConditionPB::try_from(condition).unwrap_or(TextFilterConditionPB::Is),
|
||||
condition: TextFilterConditionPB::try_from(condition)
|
||||
.unwrap_or(TextFilterConditionPB::TextIs),
|
||||
content,
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,26 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
use crate::entities::{NumberFilterConditionPB, NumberFilterPB};
|
||||
use crate::services::field::NumberCellFormat;
|
||||
use rust_decimal::prelude::Zero;
|
||||
use rust_decimal::Decimal;
|
||||
use std::str::FromStr;
|
||||
|
||||
impl NumberFilterPB {
|
||||
pub fn is_visible(&self, cell_data: &NumberCellFormat) -> Option<bool> {
|
||||
let expected_decimal = Decimal::from_str(&self.content).unwrap_or_else(|_| Decimal::zero());
|
||||
let expected_decimal = || Decimal::from_str(&self.content).ok();
|
||||
|
||||
let strategy = match self.condition {
|
||||
NumberFilterConditionPB::Equal => NumberFilterStrategy::Equal(expected_decimal),
|
||||
NumberFilterConditionPB::NotEqual => NumberFilterStrategy::NotEqual(expected_decimal),
|
||||
NumberFilterConditionPB::GreaterThan => NumberFilterStrategy::GreaterThan(expected_decimal),
|
||||
NumberFilterConditionPB::LessThan => NumberFilterStrategy::LessThan(expected_decimal),
|
||||
NumberFilterConditionPB::Equal => NumberFilterStrategy::Equal(expected_decimal()?),
|
||||
NumberFilterConditionPB::NotEqual => NumberFilterStrategy::NotEqual(expected_decimal()?),
|
||||
NumberFilterConditionPB::GreaterThan => {
|
||||
NumberFilterStrategy::GreaterThan(expected_decimal()?)
|
||||
},
|
||||
NumberFilterConditionPB::LessThan => NumberFilterStrategy::LessThan(expected_decimal()?),
|
||||
NumberFilterConditionPB::GreaterThanOrEqualTo => {
|
||||
NumberFilterStrategy::GreaterThanOrEqualTo(expected_decimal)
|
||||
NumberFilterStrategy::GreaterThanOrEqualTo(expected_decimal()?)
|
||||
},
|
||||
NumberFilterConditionPB::LessThanOrEqualTo => {
|
||||
NumberFilterStrategy::LessThanOrEqualTo(expected_decimal)
|
||||
NumberFilterStrategy::LessThanOrEqualTo(expected_decimal()?)
|
||||
},
|
||||
NumberFilterConditionPB::NumberIsEmpty => NumberFilterStrategy::Empty,
|
||||
NumberFilterConditionPB::NumberIsNotEmpty => NumberFilterStrategy::NotEmpty,
|
||||
|
@ -128,7 +128,7 @@ impl TypeOptionCellDataFilter for MultiSelectTypeOption {
|
||||
cell_data: &<Self as TypeOption>::CellData,
|
||||
) -> bool {
|
||||
let selected_options = self.get_selected_options(cell_data.clone()).select_options;
|
||||
filter.is_visible(&selected_options, FieldType::MultiSelect)
|
||||
filter.is_visible(&selected_options).unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,106 +1,110 @@
|
||||
#![allow(clippy::needless_collect)]
|
||||
|
||||
use crate::entities::{FieldType, SelectOptionConditionPB, SelectOptionFilterPB};
|
||||
use crate::entities::{SelectOptionFilterConditionPB, SelectOptionFilterPB};
|
||||
use crate::services::field::SelectOption;
|
||||
|
||||
impl SelectOptionFilterPB {
|
||||
pub fn is_visible(&self, selected_options: &[SelectOption], field_type: FieldType) -> bool {
|
||||
let selected_option_ids: Vec<&String> =
|
||||
selected_options.iter().map(|option| &option.id).collect();
|
||||
match self.condition {
|
||||
SelectOptionConditionPB::OptionIs => match field_type {
|
||||
FieldType::SingleSelect => {
|
||||
if self.option_ids.is_empty() {
|
||||
return true;
|
||||
}
|
||||
pub fn is_visible(&self, selected_options: &[SelectOption]) -> Option<bool> {
|
||||
let selected_option_ids = selected_options
|
||||
.iter()
|
||||
.map(|option| &option.id)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if selected_options.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let get_non_empty_expected_options =
|
||||
|| (!self.option_ids.is_empty()).then(|| self.option_ids.clone());
|
||||
|
||||
let required_options = self
|
||||
.option_ids
|
||||
.iter()
|
||||
.filter(|id| selected_option_ids.contains(id))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
!required_options.is_empty()
|
||||
},
|
||||
FieldType::MultiSelect => {
|
||||
if self.option_ids.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let required_options = self
|
||||
.option_ids
|
||||
.iter()
|
||||
.filter(|id| selected_option_ids.contains(id))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
!required_options.is_empty()
|
||||
},
|
||||
_ => false,
|
||||
let strategy = match self.condition {
|
||||
SelectOptionFilterConditionPB::OptionIs => {
|
||||
SelectOptionFilterStrategy::Is(get_non_empty_expected_options()?)
|
||||
},
|
||||
SelectOptionConditionPB::OptionIsNot => match field_type {
|
||||
FieldType::SingleSelect => {
|
||||
if self.option_ids.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if selected_options.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let required_options = self
|
||||
.option_ids
|
||||
.iter()
|
||||
.filter(|id| selected_option_ids.contains(id))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
required_options.is_empty()
|
||||
},
|
||||
FieldType::MultiSelect => {
|
||||
let required_options = self
|
||||
.option_ids
|
||||
.iter()
|
||||
.filter(|id| selected_option_ids.contains(id))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
required_options.is_empty()
|
||||
},
|
||||
_ => false,
|
||||
SelectOptionFilterConditionPB::OptionIsNot => {
|
||||
SelectOptionFilterStrategy::IsNot(get_non_empty_expected_options()?)
|
||||
},
|
||||
SelectOptionConditionPB::OptionIsEmpty => selected_option_ids.is_empty(),
|
||||
SelectOptionConditionPB::OptionIsNotEmpty => !selected_option_ids.is_empty(),
|
||||
SelectOptionFilterConditionPB::OptionContains => {
|
||||
SelectOptionFilterStrategy::Contains(get_non_empty_expected_options()?)
|
||||
},
|
||||
SelectOptionFilterConditionPB::OptionDoesNotContain => {
|
||||
SelectOptionFilterStrategy::DoesNotContain(get_non_empty_expected_options()?)
|
||||
},
|
||||
SelectOptionFilterConditionPB::OptionIsEmpty => SelectOptionFilterStrategy::IsEmpty,
|
||||
SelectOptionFilterConditionPB::OptionIsNotEmpty => SelectOptionFilterStrategy::IsNotEmpty,
|
||||
};
|
||||
|
||||
Some(strategy.filter(&selected_option_ids))
|
||||
}
|
||||
}
|
||||
|
||||
enum SelectOptionFilterStrategy {
|
||||
Is(Vec<String>),
|
||||
IsNot(Vec<String>),
|
||||
Contains(Vec<String>),
|
||||
DoesNotContain(Vec<String>),
|
||||
IsEmpty,
|
||||
IsNotEmpty,
|
||||
}
|
||||
|
||||
impl SelectOptionFilterStrategy {
|
||||
fn filter(self, selected_option_ids: &[&String]) -> bool {
|
||||
match self {
|
||||
SelectOptionFilterStrategy::Is(option_ids) => {
|
||||
if selected_option_ids.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
selected_option_ids.len() == option_ids.len()
|
||||
&& selected_option_ids.iter().all(|id| option_ids.contains(id))
|
||||
},
|
||||
SelectOptionFilterStrategy::IsNot(option_ids) => {
|
||||
if selected_option_ids.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
selected_option_ids.len() != option_ids.len()
|
||||
|| !selected_option_ids.iter().all(|id| option_ids.contains(id))
|
||||
},
|
||||
SelectOptionFilterStrategy::Contains(option_ids) => {
|
||||
if selected_option_ids.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let required_options = option_ids
|
||||
.into_iter()
|
||||
.filter(|id| selected_option_ids.contains(&id))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
!required_options.is_empty()
|
||||
},
|
||||
SelectOptionFilterStrategy::DoesNotContain(option_ids) => {
|
||||
if selected_option_ids.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let required_options = option_ids
|
||||
.into_iter()
|
||||
.filter(|id| selected_option_ids.contains(&id))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
required_options.is_empty()
|
||||
},
|
||||
SelectOptionFilterStrategy::IsEmpty => selected_option_ids.is_empty(),
|
||||
SelectOptionFilterStrategy::IsNotEmpty => !selected_option_ids.is_empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![allow(clippy::all)]
|
||||
use crate::entities::{FieldType, SelectOptionConditionPB, SelectOptionFilterPB};
|
||||
use crate::entities::{SelectOptionFilterConditionPB, SelectOptionFilterPB};
|
||||
use crate::services::field::SelectOption;
|
||||
|
||||
#[test]
|
||||
fn select_option_filter_is_empty_test() {
|
||||
let option = SelectOption::new("A");
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIsEmpty,
|
||||
condition: SelectOptionFilterConditionPB::OptionIsEmpty,
|
||||
option_ids: vec![],
|
||||
};
|
||||
|
||||
assert_eq!(filter.is_visible(&vec![], FieldType::SingleSelect), true);
|
||||
assert_eq!(
|
||||
filter.is_visible(&vec![option.clone()], FieldType::SingleSelect),
|
||||
false,
|
||||
);
|
||||
|
||||
assert_eq!(filter.is_visible(&vec![], FieldType::MultiSelect), true);
|
||||
assert_eq!(
|
||||
filter.is_visible(&vec![option], FieldType::MultiSelect),
|
||||
false,
|
||||
);
|
||||
assert_eq!(filter.is_visible(&[]), Some(true));
|
||||
assert_eq!(filter.is_visible(&[option.clone()]), Some(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -108,157 +112,227 @@ mod tests {
|
||||
let option_1 = SelectOption::new("A");
|
||||
let option_2 = SelectOption::new("B");
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIsNotEmpty,
|
||||
condition: SelectOptionFilterConditionPB::OptionIsNotEmpty,
|
||||
option_ids: vec![option_1.id.clone(), option_2.id.clone()],
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
filter.is_visible(&vec![option_1.clone()], FieldType::SingleSelect),
|
||||
true
|
||||
);
|
||||
assert_eq!(filter.is_visible(&vec![], FieldType::SingleSelect), false,);
|
||||
|
||||
assert_eq!(
|
||||
filter.is_visible(&vec![option_1.clone()], FieldType::MultiSelect),
|
||||
true
|
||||
);
|
||||
assert_eq!(filter.is_visible(&vec![], FieldType::MultiSelect), false,);
|
||||
assert_eq!(filter.is_visible(&[]), Some(false));
|
||||
assert_eq!(filter.is_visible(&[option_1.clone()]), Some(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_select_option_filter_is_not_test() {
|
||||
fn select_option_filter_is_test() {
|
||||
let option_1 = SelectOption::new("A");
|
||||
let option_2 = SelectOption::new("B");
|
||||
let option_3 = SelectOption::new("C");
|
||||
|
||||
// no expected options
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIsNot,
|
||||
option_ids: vec![option_1.id.clone(), option_2.id.clone()],
|
||||
condition: SelectOptionFilterConditionPB::OptionIs,
|
||||
option_ids: vec![],
|
||||
};
|
||||
|
||||
for (options, is_visible) in vec![
|
||||
(vec![option_2.clone()], false),
|
||||
(vec![option_1.clone()], false),
|
||||
(vec![option_3.clone()], true),
|
||||
(vec![option_1.clone(), option_2.clone()], false),
|
||||
for (options, is_visible) in [
|
||||
(vec![], None),
|
||||
(vec![option_1.clone()], None),
|
||||
(vec![option_1.clone(), option_2.clone()], None),
|
||||
] {
|
||||
assert_eq!(
|
||||
filter.is_visible(&options, FieldType::SingleSelect),
|
||||
is_visible
|
||||
);
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_select_option_filter_is_test() {
|
||||
let option_1 = SelectOption::new("A");
|
||||
let option_2 = SelectOption::new("B");
|
||||
let option_3 = SelectOption::new("c");
|
||||
|
||||
// one expected option
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIs,
|
||||
condition: SelectOptionFilterConditionPB::OptionIs,
|
||||
option_ids: vec![option_1.id.clone()],
|
||||
};
|
||||
for (options, is_visible) in vec![
|
||||
(vec![option_1.clone()], true),
|
||||
(vec![option_2.clone()], false),
|
||||
(vec![option_3.clone()], false),
|
||||
(vec![option_1.clone(), option_2.clone()], true),
|
||||
for (options, is_visible) in [
|
||||
(vec![], Some(false)),
|
||||
(vec![option_1.clone()], Some(true)),
|
||||
(vec![option_2.clone()], Some(false)),
|
||||
(vec![option_3.clone()], Some(false)),
|
||||
(vec![option_1.clone(), option_2.clone()], Some(false)),
|
||||
] {
|
||||
assert_eq!(
|
||||
filter.is_visible(&options, FieldType::SingleSelect),
|
||||
is_visible
|
||||
);
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_select_option_filter_is_test2() {
|
||||
let option_1 = SelectOption::new("A");
|
||||
let option_2 = SelectOption::new("B");
|
||||
|
||||
// multiple expected options
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIs,
|
||||
option_ids: vec![],
|
||||
};
|
||||
for (options, is_visible) in vec![
|
||||
(vec![option_1.clone()], true),
|
||||
(vec![option_2.clone()], true),
|
||||
(vec![option_1.clone(), option_2.clone()], true),
|
||||
] {
|
||||
assert_eq!(
|
||||
filter.is_visible(&options, FieldType::SingleSelect),
|
||||
is_visible
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_select_option_filter_not_contains_test() {
|
||||
let option_1 = SelectOption::new("A");
|
||||
let option_2 = SelectOption::new("B");
|
||||
let option_3 = SelectOption::new("C");
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIsNot,
|
||||
condition: SelectOptionFilterConditionPB::OptionIs,
|
||||
option_ids: vec![option_1.id.clone(), option_2.id.clone()],
|
||||
};
|
||||
|
||||
for (options, is_visible) in vec![
|
||||
(vec![option_1.clone(), option_2.clone()], false),
|
||||
(vec![option_1.clone()], false),
|
||||
(vec![option_2.clone()], false),
|
||||
(vec![option_3.clone()], true),
|
||||
for (options, is_visible) in [
|
||||
(vec![], Some(false)),
|
||||
(vec![option_1.clone()], Some(false)),
|
||||
(vec![option_1.clone(), option_2.clone()], Some(true)),
|
||||
(
|
||||
vec![option_1.clone(), option_2.clone(), option_3.clone()],
|
||||
false,
|
||||
Some(false),
|
||||
),
|
||||
(vec![], true),
|
||||
] {
|
||||
assert_eq!(
|
||||
filter.is_visible(&options, FieldType::MultiSelect),
|
||||
is_visible
|
||||
);
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_select_option_filter_contains_test() {
|
||||
fn select_option_filter_is_not_test() {
|
||||
let option_1 = SelectOption::new("A");
|
||||
let option_2 = SelectOption::new("B");
|
||||
let option_3 = SelectOption::new("C");
|
||||
|
||||
// no expected options
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIs,
|
||||
condition: SelectOptionFilterConditionPB::OptionIsNot,
|
||||
option_ids: vec![],
|
||||
};
|
||||
for (options, is_visible) in [
|
||||
(vec![], None),
|
||||
(vec![option_1.clone()], None),
|
||||
(vec![option_1.clone(), option_2.clone()], None),
|
||||
] {
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
|
||||
// one expected option
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionFilterConditionPB::OptionIsNot,
|
||||
option_ids: vec![option_1.id.clone()],
|
||||
};
|
||||
for (options, is_visible) in [
|
||||
(vec![], Some(true)),
|
||||
(vec![option_1.clone()], Some(false)),
|
||||
(vec![option_2.clone()], Some(true)),
|
||||
(vec![option_3.clone()], Some(true)),
|
||||
(vec![option_1.clone(), option_2.clone()], Some(true)),
|
||||
] {
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
|
||||
// multiple expected options
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionFilterConditionPB::OptionIsNot,
|
||||
option_ids: vec![option_1.id.clone(), option_2.id.clone()],
|
||||
};
|
||||
for (options, is_visible) in vec![
|
||||
for (options, is_visible) in [
|
||||
(vec![], Some(true)),
|
||||
(vec![option_1.clone()], Some(true)),
|
||||
(vec![option_1.clone(), option_2.clone()], Some(false)),
|
||||
(
|
||||
vec![option_1.clone(), option_2.clone(), option_3.clone()],
|
||||
true,
|
||||
Some(true),
|
||||
),
|
||||
(vec![option_2.clone(), option_1.clone()], true),
|
||||
(vec![option_2.clone()], true),
|
||||
(vec![option_1.clone(), option_3.clone()], true),
|
||||
(vec![option_3.clone()], false),
|
||||
] {
|
||||
assert_eq!(
|
||||
filter.is_visible(&options, FieldType::MultiSelect),
|
||||
is_visible
|
||||
);
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_select_option_filter_contains_test2() {
|
||||
fn select_option_filter_contains_test() {
|
||||
let option_1 = SelectOption::new("A");
|
||||
let option_2 = SelectOption::new("B");
|
||||
let option_3 = SelectOption::new("C");
|
||||
let option_4 = SelectOption::new("D");
|
||||
|
||||
// no expected options
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIs,
|
||||
condition: SelectOptionFilterConditionPB::OptionContains,
|
||||
option_ids: vec![],
|
||||
};
|
||||
for (options, is_visible) in vec![(vec![option_1.clone()], true), (vec![], true)] {
|
||||
assert_eq!(
|
||||
filter.is_visible(&options, FieldType::MultiSelect),
|
||||
is_visible
|
||||
);
|
||||
for (options, is_visible) in [
|
||||
(vec![], None),
|
||||
(vec![option_1.clone()], None),
|
||||
(vec![option_1.clone(), option_2.clone()], None),
|
||||
] {
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
|
||||
// one expected option
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionFilterConditionPB::OptionContains,
|
||||
option_ids: vec![option_1.id.clone()],
|
||||
};
|
||||
for (options, is_visible) in [
|
||||
(vec![], Some(false)),
|
||||
(vec![option_1.clone()], Some(true)),
|
||||
(vec![option_2.clone()], Some(false)),
|
||||
(vec![option_1.clone(), option_2.clone()], Some(true)),
|
||||
(vec![option_3.clone(), option_4.clone()], Some(false)),
|
||||
] {
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
|
||||
// multiple expected options
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionFilterConditionPB::OptionContains,
|
||||
option_ids: vec![option_1.id.clone(), option_2.id.clone()],
|
||||
};
|
||||
for (options, is_visible) in [
|
||||
(vec![], Some(false)),
|
||||
(vec![option_1.clone()], Some(true)),
|
||||
(vec![option_3.clone()], Some(false)),
|
||||
(vec![option_1.clone(), option_2.clone()], Some(true)),
|
||||
(vec![option_1.clone(), option_3.clone()], Some(true)),
|
||||
(vec![option_3.clone(), option_4.clone()], Some(false)),
|
||||
(
|
||||
vec![option_1.clone(), option_3.clone(), option_4.clone()],
|
||||
Some(true),
|
||||
),
|
||||
] {
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_option_filter_does_not_contain_test() {
|
||||
let option_1 = SelectOption::new("A");
|
||||
let option_2 = SelectOption::new("B");
|
||||
let option_3 = SelectOption::new("C");
|
||||
let option_4 = SelectOption::new("D");
|
||||
|
||||
// no expected options
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionFilterConditionPB::OptionDoesNotContain,
|
||||
option_ids: vec![],
|
||||
};
|
||||
for (options, is_visible) in [
|
||||
(vec![], None),
|
||||
(vec![option_1.clone()], None),
|
||||
(vec![option_1.clone(), option_2.clone()], None),
|
||||
] {
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
|
||||
// one expected option
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionFilterConditionPB::OptionDoesNotContain,
|
||||
option_ids: vec![option_1.id.clone()],
|
||||
};
|
||||
for (options, is_visible) in [
|
||||
(vec![], Some(true)),
|
||||
(vec![option_1.clone()], Some(false)),
|
||||
(vec![option_2.clone()], Some(true)),
|
||||
(vec![option_1.clone(), option_2.clone()], Some(false)),
|
||||
(vec![option_3.clone(), option_4.clone()], Some(true)),
|
||||
] {
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
|
||||
// multiple expected options
|
||||
let filter = SelectOptionFilterPB {
|
||||
condition: SelectOptionFilterConditionPB::OptionDoesNotContain,
|
||||
option_ids: vec![option_1.id.clone(), option_2.id.clone()],
|
||||
};
|
||||
for (options, is_visible) in [
|
||||
(vec![], Some(true)),
|
||||
(vec![option_1.clone()], Some(false)),
|
||||
(vec![option_3.clone()], Some(true)),
|
||||
(vec![option_1.clone(), option_2.clone()], Some(false)),
|
||||
(vec![option_1.clone(), option_3.clone()], Some(false)),
|
||||
(vec![option_3.clone(), option_4.clone()], Some(true)),
|
||||
(
|
||||
vec![option_1.clone(), option_3.clone(), option_4.clone()],
|
||||
Some(false),
|
||||
),
|
||||
] {
|
||||
assert_eq!(filter.is_visible(&options), is_visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ impl TypeOptionCellDataFilter for SingleSelectTypeOption {
|
||||
cell_data: &<Self as TypeOption>::CellData,
|
||||
) -> bool {
|
||||
let selected_options = self.get_selected_options(cell_data.clone()).select_options;
|
||||
filter.is_visible(&selected_options, FieldType::SingleSelect)
|
||||
filter.is_visible(&selected_options).unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,12 @@ impl TextFilterPB {
|
||||
let cell_data = cell_data.as_ref().to_lowercase();
|
||||
let content = &self.content.to_lowercase();
|
||||
match self.condition {
|
||||
TextFilterConditionPB::Is => &cell_data == content,
|
||||
TextFilterConditionPB::IsNot => &cell_data != content,
|
||||
TextFilterConditionPB::Contains => cell_data.contains(content),
|
||||
TextFilterConditionPB::DoesNotContain => !cell_data.contains(content),
|
||||
TextFilterConditionPB::StartsWith => cell_data.starts_with(content),
|
||||
TextFilterConditionPB::EndsWith => cell_data.ends_with(content),
|
||||
TextFilterConditionPB::TextIs => &cell_data == content,
|
||||
TextFilterConditionPB::TextIsNot => &cell_data != content,
|
||||
TextFilterConditionPB::TextContains => cell_data.contains(content),
|
||||
TextFilterConditionPB::TextDoesNotContain => !cell_data.contains(content),
|
||||
TextFilterConditionPB::TextStartsWith => cell_data.starts_with(content),
|
||||
TextFilterConditionPB::TextEndsWith => cell_data.ends_with(content),
|
||||
TextFilterConditionPB::TextIsEmpty => cell_data.is_empty(),
|
||||
TextFilterConditionPB::TextIsNotEmpty => !cell_data.is_empty(),
|
||||
}
|
||||
@ -25,7 +25,7 @@ mod tests {
|
||||
#[test]
|
||||
fn text_filter_equal_test() {
|
||||
let text_filter = TextFilterPB {
|
||||
condition: TextFilterConditionPB::Is,
|
||||
condition: TextFilterConditionPB::TextIs,
|
||||
content: "appflowy".to_owned(),
|
||||
};
|
||||
|
||||
@ -37,7 +37,7 @@ mod tests {
|
||||
#[test]
|
||||
fn text_filter_start_with_test() {
|
||||
let text_filter = TextFilterPB {
|
||||
condition: TextFilterConditionPB::StartsWith,
|
||||
condition: TextFilterConditionPB::TextStartsWith,
|
||||
content: "appflowy".to_owned(),
|
||||
};
|
||||
|
||||
@ -49,7 +49,7 @@ mod tests {
|
||||
#[test]
|
||||
fn text_filter_end_with_test() {
|
||||
let text_filter = TextFilterPB {
|
||||
condition: TextFilterConditionPB::EndsWith,
|
||||
condition: TextFilterConditionPB::TextEndsWith,
|
||||
content: "appflowy".to_owned(),
|
||||
};
|
||||
|
||||
@ -70,7 +70,7 @@ mod tests {
|
||||
#[test]
|
||||
fn text_filter_contain_test() {
|
||||
let text_filter = TextFilterPB {
|
||||
condition: TextFilterConditionPB::Contains,
|
||||
condition: TextFilterConditionPB::TextContains,
|
||||
content: "appflowy".to_owned(),
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use flowy_database2::entities::{FieldType, SelectOptionConditionPB, SelectOptionFilterPB};
|
||||
use flowy_database2::entities::{FieldType, SelectOptionFilterConditionPB, SelectOptionFilterPB};
|
||||
use lib_infra::box_any::BoxAny;
|
||||
|
||||
use crate::database::filter_test::script::FilterScript::*;
|
||||
@ -12,7 +12,7 @@ async fn grid_filter_multi_select_is_empty_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::MultiSelect,
|
||||
data: BoxAny::new(SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIsEmpty,
|
||||
condition: SelectOptionFilterConditionPB::OptionIsEmpty,
|
||||
option_ids: vec![],
|
||||
}),
|
||||
changed: None,
|
||||
@ -30,7 +30,7 @@ async fn grid_filter_multi_select_is_not_empty_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::MultiSelect,
|
||||
data: BoxAny::new(SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIsNotEmpty,
|
||||
condition: SelectOptionFilterConditionPB::OptionIsNotEmpty,
|
||||
option_ids: vec![],
|
||||
}),
|
||||
changed: None,
|
||||
@ -50,12 +50,12 @@ async fn grid_filter_multi_select_is_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::MultiSelect,
|
||||
data: BoxAny::new(SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIs,
|
||||
condition: SelectOptionFilterConditionPB::OptionIs,
|
||||
option_ids: vec![options.remove(0).id, options.remove(0).id],
|
||||
}),
|
||||
changed: None,
|
||||
},
|
||||
AssertNumberOfVisibleRows { expected: 5 },
|
||||
AssertNumberOfVisibleRows { expected: 1 },
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
@ -70,12 +70,12 @@ async fn grid_filter_multi_select_is_test2() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::MultiSelect,
|
||||
data: BoxAny::new(SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIs,
|
||||
condition: SelectOptionFilterConditionPB::OptionIs,
|
||||
option_ids: vec![options.remove(1).id],
|
||||
}),
|
||||
changed: None,
|
||||
},
|
||||
AssertNumberOfVisibleRows { expected: 4 },
|
||||
AssertNumberOfVisibleRows { expected: 1 },
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
@ -90,7 +90,7 @@ async fn grid_filter_single_select_is_empty_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::SingleSelect,
|
||||
data: BoxAny::new(SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIsEmpty,
|
||||
condition: SelectOptionFilterConditionPB::OptionIsEmpty,
|
||||
option_ids: vec![],
|
||||
}),
|
||||
changed: Some(FilterRowChanged {
|
||||
@ -115,7 +115,7 @@ async fn grid_filter_single_select_is_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::SingleSelect,
|
||||
data: BoxAny::new(SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIs,
|
||||
condition: SelectOptionFilterConditionPB::OptionIs,
|
||||
option_ids: vec![options.remove(0).id],
|
||||
}),
|
||||
changed: Some(FilterRowChanged {
|
||||
@ -142,7 +142,7 @@ async fn grid_filter_single_select_is_test2() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::SingleSelect,
|
||||
data: BoxAny::new(SelectOptionFilterPB {
|
||||
condition: SelectOptionConditionPB::OptionIs,
|
||||
condition: SelectOptionFilterConditionPB::OptionIs,
|
||||
option_ids: vec![option.id.clone()],
|
||||
}),
|
||||
changed: Some(FilterRowChanged {
|
||||
@ -169,3 +169,43 @@ async fn grid_filter_single_select_is_test2() {
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_filter_multi_select_contains_test() {
|
||||
let mut test = DatabaseFilterTest::new().await;
|
||||
let field = test.get_first_field(FieldType::MultiSelect);
|
||||
let mut options = test.get_multi_select_type_option(&field.id);
|
||||
let scripts = vec![
|
||||
CreateDataFilter {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::MultiSelect,
|
||||
data: BoxAny::new(SelectOptionFilterPB {
|
||||
condition: SelectOptionFilterConditionPB::OptionContains,
|
||||
option_ids: vec![options.remove(0).id, options.remove(0).id],
|
||||
}),
|
||||
changed: None,
|
||||
},
|
||||
AssertNumberOfVisibleRows { expected: 5 },
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn grid_filter_multi_select_contains_test2() {
|
||||
let mut test = DatabaseFilterTest::new().await;
|
||||
let field = test.get_first_field(FieldType::MultiSelect);
|
||||
let mut options = test.get_multi_select_type_option(&field.id);
|
||||
let scripts = vec![
|
||||
CreateDataFilter {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::MultiSelect,
|
||||
data: BoxAny::new(SelectOptionFilterPB {
|
||||
condition: SelectOptionFilterConditionPB::OptionContains,
|
||||
option_ids: vec![options.remove(1).id],
|
||||
}),
|
||||
changed: None,
|
||||
},
|
||||
AssertNumberOfVisibleRows { expected: 4 },
|
||||
];
|
||||
test.run_scripts(scripts).await;
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ async fn grid_filter_is_text_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::RichText,
|
||||
data: BoxAny::new(TextFilterPB {
|
||||
condition: TextFilterConditionPB::Is,
|
||||
condition: TextFilterConditionPB::TextIs,
|
||||
content: "A".to_string(),
|
||||
}),
|
||||
changed: Some(FilterRowChanged {
|
||||
@ -88,7 +88,7 @@ async fn grid_filter_contain_text_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::RichText,
|
||||
data: BoxAny::new(TextFilterPB {
|
||||
condition: TextFilterConditionPB::Contains,
|
||||
condition: TextFilterConditionPB::TextContains,
|
||||
content: "A".to_string(),
|
||||
}),
|
||||
changed: Some(FilterRowChanged {
|
||||
@ -109,7 +109,7 @@ async fn grid_filter_contain_text_test2() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::RichText,
|
||||
data: BoxAny::new(TextFilterPB {
|
||||
condition: TextFilterConditionPB::Contains,
|
||||
condition: TextFilterConditionPB::TextContains,
|
||||
content: "A".to_string(),
|
||||
}),
|
||||
changed: Some(FilterRowChanged {
|
||||
@ -137,7 +137,7 @@ async fn grid_filter_does_not_contain_text_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::RichText,
|
||||
data: BoxAny::new(TextFilterPB {
|
||||
condition: TextFilterConditionPB::DoesNotContain,
|
||||
condition: TextFilterConditionPB::TextDoesNotContain,
|
||||
content: "AB".to_string(),
|
||||
}),
|
||||
changed: Some(FilterRowChanged {
|
||||
@ -155,7 +155,7 @@ async fn grid_filter_start_with_text_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::RichText,
|
||||
data: BoxAny::new(TextFilterPB {
|
||||
condition: TextFilterConditionPB::StartsWith,
|
||||
condition: TextFilterConditionPB::TextStartsWith,
|
||||
content: "A".to_string(),
|
||||
}),
|
||||
changed: Some(FilterRowChanged {
|
||||
@ -174,7 +174,7 @@ async fn grid_filter_ends_with_text_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::RichText,
|
||||
data: BoxAny::new(TextFilterPB {
|
||||
condition: TextFilterConditionPB::EndsWith,
|
||||
condition: TextFilterConditionPB::TextEndsWith,
|
||||
content: "A".to_string(),
|
||||
}),
|
||||
changed: None,
|
||||
@ -192,7 +192,7 @@ async fn grid_update_text_filter_test() {
|
||||
parent_filter_id: None,
|
||||
field_type: FieldType::RichText,
|
||||
data: BoxAny::new(TextFilterPB {
|
||||
condition: TextFilterConditionPB::EndsWith,
|
||||
condition: TextFilterConditionPB::TextEndsWith,
|
||||
content: "A".to_string(),
|
||||
}),
|
||||
changed: Some(FilterRowChanged {
|
||||
@ -210,7 +210,7 @@ async fn grid_update_text_filter_test() {
|
||||
let scripts = vec![
|
||||
UpdateTextFilter {
|
||||
filter,
|
||||
condition: TextFilterConditionPB::Is,
|
||||
condition: TextFilterConditionPB::TextIs,
|
||||
content: "A".to_string(),
|
||||
changed: Some(FilterRowChanged {
|
||||
showing_num_of_rows: 0,
|
||||
|
Loading…
Reference in New Issue
Block a user