mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: reorder sort precedence (#4592)
* feat: reorder sorts * chore: add tests, fix tests, fix tauri build and fix clippy * fix: add missing import
This commit is contained in:
parent
fda70ff560
commit
a515715543
@ -86,7 +86,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('add checkbox sort', (tester) async {
|
testWidgets('add checkbox sort', (tester) async {
|
||||||
await tester.openV020database();
|
await tester.openV020database();
|
||||||
// create a filter
|
// create a sort
|
||||||
await tester.tapDatabaseSortButton();
|
await tester.tapDatabaseSortButton();
|
||||||
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
|
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('add number sort', (tester) async {
|
testWidgets('add number sort', (tester) async {
|
||||||
await tester.openV020database();
|
await tester.openV020database();
|
||||||
// create a filter
|
// create a sort
|
||||||
await tester.tapDatabaseSortButton();
|
await tester.tapDatabaseSortButton();
|
||||||
await tester.tapCreateSortByFieldType(FieldType.Number, 'number');
|
await tester.tapCreateSortByFieldType(FieldType.Number, 'number');
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('add checkbox and number sort', (tester) async {
|
testWidgets('add checkbox and number sort', (tester) async {
|
||||||
await tester.openV020database();
|
await tester.openV020database();
|
||||||
// create a filter
|
// create a sort
|
||||||
await tester.tapDatabaseSortButton();
|
await tester.tapDatabaseSortButton();
|
||||||
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
|
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
|
||||||
|
|
||||||
@ -264,5 +264,111 @@ void main() {
|
|||||||
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('reorder sort', (tester) async {
|
||||||
|
await tester.openV020database();
|
||||||
|
// create a sort
|
||||||
|
await tester.tapDatabaseSortButton();
|
||||||
|
await tester.tapCreateSortByFieldType(FieldType.Checkbox, 'Done');
|
||||||
|
|
||||||
|
// open the sort menu and sort checkbox by descending
|
||||||
|
await tester.tapSortMenuInSettingBar();
|
||||||
|
await tester.tapSortButtonByName('Done');
|
||||||
|
await tester.tapSortByDescending();
|
||||||
|
|
||||||
|
// add another sort, this time by number descending
|
||||||
|
await tester.tapSortMenuInSettingBar();
|
||||||
|
await tester.tapCreateSortByFieldTypeInSortMenu(
|
||||||
|
FieldType.Number,
|
||||||
|
'number',
|
||||||
|
);
|
||||||
|
await tester.tapSortButtonByName('number');
|
||||||
|
await tester.tapSortByDescending();
|
||||||
|
|
||||||
|
// check checkbox cell order
|
||||||
|
for (final (index, content) in <bool>[
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
].indexed) {
|
||||||
|
await tester.assertCheckboxCell(
|
||||||
|
rowIndex: index,
|
||||||
|
isSelected: content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check number cell order
|
||||||
|
for (final (index, content) in <String>[
|
||||||
|
'1',
|
||||||
|
'0.2',
|
||||||
|
'0.1',
|
||||||
|
'-1',
|
||||||
|
'-2',
|
||||||
|
'12',
|
||||||
|
'11',
|
||||||
|
'10',
|
||||||
|
'2',
|
||||||
|
'',
|
||||||
|
].indexed) {
|
||||||
|
tester.assertCellContent(
|
||||||
|
rowIndex: index,
|
||||||
|
fieldType: FieldType.Number,
|
||||||
|
content: content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reorder sort
|
||||||
|
await tester.tapSortMenuInSettingBar();
|
||||||
|
await tester.reorderSort(
|
||||||
|
(FieldType.Number, 'number'),
|
||||||
|
(FieldType.Checkbox, 'Done'),
|
||||||
|
);
|
||||||
|
|
||||||
|
// check checkbox cell order
|
||||||
|
for (final (index, content) in <bool>[
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
].indexed) {
|
||||||
|
await tester.assertCheckboxCell(
|
||||||
|
rowIndex: index,
|
||||||
|
isSelected: content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the number cell order
|
||||||
|
for (final (index, content) in <String>[
|
||||||
|
'12',
|
||||||
|
'11',
|
||||||
|
'10',
|
||||||
|
'2',
|
||||||
|
'1',
|
||||||
|
'0.2',
|
||||||
|
'0.1',
|
||||||
|
'-1',
|
||||||
|
'-2',
|
||||||
|
'',
|
||||||
|
].indexed) {
|
||||||
|
tester.assertCellContent(
|
||||||
|
rowIndex: index,
|
||||||
|
fieldType: FieldType.Number,
|
||||||
|
content: content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1070,6 +1070,34 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
await tapButton(findSortItem);
|
await tapButton(findSortItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Must call [tapSortMenuInSettingBar] first.
|
||||||
|
Future<void> reorderSort(
|
||||||
|
(FieldType, String) from,
|
||||||
|
(FieldType, String) to,
|
||||||
|
) async {
|
||||||
|
final fromSortItem = find.byWidgetPredicate(
|
||||||
|
(widget) =>
|
||||||
|
widget is DatabaseSortItem &&
|
||||||
|
widget.sortInfo.fieldInfo.fieldType == from.$1 &&
|
||||||
|
widget.sortInfo.fieldInfo.name == from.$2,
|
||||||
|
);
|
||||||
|
final toSortItem = find.byWidgetPredicate(
|
||||||
|
(widget) =>
|
||||||
|
widget is DatabaseSortItem &&
|
||||||
|
widget.sortInfo.fieldInfo.fieldType == to.$1 &&
|
||||||
|
widget.sortInfo.fieldInfo.name == to.$2,
|
||||||
|
);
|
||||||
|
final dragElement = find.descendant(
|
||||||
|
of: fromSortItem,
|
||||||
|
matching: find.byType(ReorderableDragStartListener),
|
||||||
|
);
|
||||||
|
await drag(
|
||||||
|
dragElement,
|
||||||
|
getCenter(toSortItem) - getCenter(fromSortItem),
|
||||||
|
);
|
||||||
|
await pumpAndSettle(const Duration(milliseconds: 200));
|
||||||
|
}
|
||||||
|
|
||||||
/// Must call [tapSortButtonByName] first.
|
/// Must call [tapSortButtonByName] first.
|
||||||
Future<void> tapSortByDescending() async {
|
Future<void> tapSortByDescending() async {
|
||||||
await tapButton(
|
await tapButton(
|
||||||
|
@ -282,16 +282,19 @@ class FieldController {
|
|||||||
) {
|
) {
|
||||||
for (final newSortPB in changeset.insertSorts) {
|
for (final newSortPB in changeset.insertSorts) {
|
||||||
final sortIndex = newSortInfos
|
final sortIndex = newSortInfos
|
||||||
.indexWhere((element) => element.sortId == newSortPB.id);
|
.indexWhere((element) => element.sortId == newSortPB.sort.id);
|
||||||
if (sortIndex == -1) {
|
if (sortIndex == -1) {
|
||||||
final fieldInfo = _findFieldInfo(
|
final fieldInfo = _findFieldInfo(
|
||||||
fieldInfos: fieldInfos,
|
fieldInfos: fieldInfos,
|
||||||
fieldId: newSortPB.fieldId,
|
fieldId: newSortPB.sort.fieldId,
|
||||||
fieldType: newSortPB.fieldType,
|
fieldType: newSortPB.sort.fieldType,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (fieldInfo != null) {
|
if (fieldInfo != null) {
|
||||||
newSortInfos.add(SortInfo(sortPB: newSortPB, fieldInfo: fieldInfo));
|
newSortInfos.insert(
|
||||||
|
newSortPB.index,
|
||||||
|
SortInfo(sortPB: newSortPB.sort, fieldInfo: fieldInfo),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,20 @@ class SortBackendService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Either<Unit, FlowyError>> reorderSort({
|
||||||
|
required String fromSortId,
|
||||||
|
required String toSortId,
|
||||||
|
}) {
|
||||||
|
final payload = DatabaseSettingChangesetPB()
|
||||||
|
..viewId = viewId
|
||||||
|
..reorderSort = (ReorderSortPayloadPB()
|
||||||
|
..viewId = viewId
|
||||||
|
..fromSortId = fromSortId
|
||||||
|
..toSortId = toSortId);
|
||||||
|
|
||||||
|
return DatabaseEventUpdateDatabaseSetting(payload).send();
|
||||||
|
}
|
||||||
|
|
||||||
Future<Either<Unit, FlowyError>> deleteSort({
|
Future<Either<Unit, FlowyError>> deleteSort({
|
||||||
required String fieldId,
|
required String fieldId,
|
||||||
required String sortId,
|
required String sortId,
|
||||||
|
@ -71,6 +71,23 @@ class SortEditorBloc extends Bloc<SortEditorEvent, SortEditorState> {
|
|||||||
);
|
);
|
||||||
result.fold((l) => null, (err) => Log.error(err));
|
result.fold((l) => null, (err) => Log.error(err));
|
||||||
},
|
},
|
||||||
|
reorderSort: (fromIndex, toIndex) async {
|
||||||
|
if (fromIndex < toIndex) {
|
||||||
|
toIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
final fromId = state.sortInfos[fromIndex].sortId;
|
||||||
|
final toId = state.sortInfos[toIndex].sortId;
|
||||||
|
|
||||||
|
final newSorts = [...state.sortInfos];
|
||||||
|
newSorts.insert(toIndex, newSorts.removeAt(fromIndex));
|
||||||
|
emit(state.copyWith(sortInfos: newSorts));
|
||||||
|
final result = await _sortBackendSvc.reorderSort(
|
||||||
|
fromSortId: fromId,
|
||||||
|
toSortId: toId,
|
||||||
|
);
|
||||||
|
result.fold((l) => null, (err) => Log.error(err));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -113,6 +130,8 @@ class SortEditorEvent with _$SortEditorEvent {
|
|||||||
) = _SetCondition;
|
) = _SetCondition;
|
||||||
const factory SortEditorEvent.deleteSort(SortInfo sortInfo) = _DeleteSort;
|
const factory SortEditorEvent.deleteSort(SortInfo sortInfo) = _DeleteSort;
|
||||||
const factory SortEditorEvent.deleteAllSorts() = _DeleteAllSorts;
|
const factory SortEditorEvent.deleteAllSorts() = _DeleteAllSorts;
|
||||||
|
const factory SortEditorEvent.reorderSort(int oldIndex, int newIndex) =
|
||||||
|
_ReorderSort;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
|
import 'package:appflowy/plugins/database/application/field/field_controller.dart';
|
||||||
@ -48,33 +50,58 @@ class _SortEditorState extends State<SortEditor> {
|
|||||||
)..add(const SortEditorEvent.initial()),
|
)..add(const SortEditorEvent.initial()),
|
||||||
child: BlocBuilder<SortEditorBloc, SortEditorState>(
|
child: BlocBuilder<SortEditorBloc, SortEditorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return Column(
|
final sortInfos = state.sortInfos;
|
||||||
children: [
|
|
||||||
...state.sortInfos.map(
|
return ReorderableListView.builder(
|
||||||
(info) => Padding(
|
onReorder: (oldIndex, newIndex) => context
|
||||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
.read<SortEditorBloc>()
|
||||||
child: DatabaseSortItem(
|
.add(SortEditorEvent.reorderSort(oldIndex, newIndex)),
|
||||||
sortInfo: info,
|
itemCount: state.sortInfos.length,
|
||||||
popoverMutex: popoverMutex,
|
itemBuilder: (context, index) => Padding(
|
||||||
),
|
key: ValueKey(sortInfos[index].sortId),
|
||||||
),
|
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||||
|
child: DatabaseSortItem(
|
||||||
|
index: index,
|
||||||
|
sortInfo: sortInfos[index],
|
||||||
|
popoverMutex: popoverMutex,
|
||||||
),
|
),
|
||||||
Row(
|
),
|
||||||
|
proxyDecorator: (child, index, animation) => Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
BlocProvider.value(
|
||||||
child: DatabaseAddSortButton(
|
value: context.read<SortEditorBloc>(),
|
||||||
viewId: widget.viewId,
|
child: child,
|
||||||
fieldController: widget.fieldController,
|
|
||||||
popoverMutex: popoverMutex,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const HSpace(6),
|
MouseRegion(
|
||||||
Flexible(
|
cursor: Platform.isWindows
|
||||||
child: DatabaseDeleteSortButton(popoverMutex: popoverMutex),
|
? SystemMouseCursors.click
|
||||||
|
: SystemMouseCursors.grabbing,
|
||||||
|
child: const SizedBox.expand(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
|
shrinkWrap: true,
|
||||||
|
buildDefaultDragHandles: false,
|
||||||
|
footer: Row(
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: DatabaseAddSortButton(
|
||||||
|
viewId: widget.viewId,
|
||||||
|
fieldController: widget.fieldController,
|
||||||
|
popoverMutex: popoverMutex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HSpace(6),
|
||||||
|
Flexible(
|
||||||
|
child: DatabaseDeleteSortButton(
|
||||||
|
popoverMutex: popoverMutex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -85,10 +112,12 @@ class _SortEditorState extends State<SortEditor> {
|
|||||||
class DatabaseSortItem extends StatelessWidget {
|
class DatabaseSortItem extends StatelessWidget {
|
||||||
const DatabaseSortItem({
|
const DatabaseSortItem({
|
||||||
super.key,
|
super.key,
|
||||||
|
required this.index,
|
||||||
required this.popoverMutex,
|
required this.popoverMutex,
|
||||||
required this.sortInfo,
|
required this.sortInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final int index;
|
||||||
final PopoverMutex popoverMutex;
|
final PopoverMutex popoverMutex;
|
||||||
final SortInfo sortInfo;
|
final SortInfo sortInfo;
|
||||||
|
|
||||||
@ -107,6 +136,23 @@ class DatabaseSortItem extends StatelessWidget {
|
|||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
|
ReorderableDragStartListener(
|
||||||
|
index: index,
|
||||||
|
child: MouseRegion(
|
||||||
|
cursor: Platform.isWindows
|
||||||
|
? SystemMouseCursors.click
|
||||||
|
: SystemMouseCursors.grab,
|
||||||
|
child: SizedBox(
|
||||||
|
width: 14,
|
||||||
|
height: 14,
|
||||||
|
child: FlowySvg(
|
||||||
|
FlowySvgs.drag_element_s,
|
||||||
|
color: Theme.of(context).iconTheme.color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HSpace(6),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 26,
|
height: 26,
|
||||||
child: SortChoiceButton(
|
child: SortChoiceButton(
|
||||||
@ -122,8 +168,8 @@ class DatabaseSortItem extends StatelessWidget {
|
|||||||
popoverMutex: popoverMutex,
|
popoverMutex: popoverMutex,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const HSpace(6),
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
const HSpace(6),
|
||||||
deleteButton,
|
deleteButton,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -31,27 +31,25 @@ class SortMenu extends StatelessWidget {
|
|||||||
)..add(const SortMenuEvent.initial()),
|
)..add(const SortMenuEvent.initial()),
|
||||||
child: BlocBuilder<SortMenuBloc, SortMenuState>(
|
child: BlocBuilder<SortMenuBloc, SortMenuState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.sortInfos.isNotEmpty) {
|
if (state.sortInfos.isEmpty) {
|
||||||
return AppFlowyPopover(
|
return const SizedBox.shrink();
|
||||||
controller: PopoverController(),
|
|
||||||
constraints: BoxConstraints.loose(const Size(320, 200)),
|
|
||||||
direction: PopoverDirection.bottomWithLeftAligned,
|
|
||||||
offset: const Offset(0, 5),
|
|
||||||
popupBuilder: (BuildContext popoverContext) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
child: SortEditor(
|
|
||||||
viewId: state.viewId,
|
|
||||||
fieldController:
|
|
||||||
context.read<SortMenuBloc>().fieldController,
|
|
||||||
sortInfos: state.sortInfos,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: SortChoiceChip(sortInfos: state.sortInfos),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return const SizedBox.shrink();
|
return AppFlowyPopover(
|
||||||
|
controller: PopoverController(),
|
||||||
|
constraints: BoxConstraints.loose(const Size(320, 200)),
|
||||||
|
direction: PopoverDirection.bottomWithLeftAligned,
|
||||||
|
offset: const Offset(0, 5),
|
||||||
|
margin: const EdgeInsets.fromLTRB(6.0, 0.0, 6.0, 6.0),
|
||||||
|
popupBuilder: (BuildContext popoverContext) {
|
||||||
|
return SortEditor(
|
||||||
|
viewId: state.viewId,
|
||||||
|
fieldController: context.read<SortMenuBloc>().fieldController,
|
||||||
|
sortInfos: state.sortInfos,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: SortChoiceChip(sortInfos: state.sortInfos),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -169,6 +169,7 @@ class _DatabasePropertyCellState extends State<DatabasePropertyCell> {
|
|||||||
FlowySvg(
|
FlowySvg(
|
||||||
widget.fieldInfo.fieldType.svgData,
|
widget.fieldInfo.fieldType.svgData,
|
||||||
color: Theme.of(context).iconTheme.color,
|
color: Theme.of(context).iconTheme.color,
|
||||||
|
size: const Size.square(16),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
14
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
14
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -816,7 +816,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab"
|
name = "collab"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -838,7 +838,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-database"
|
name = "collab-database"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -867,7 +867,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-document"
|
name = "collab-document"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
@ -886,7 +886,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-entity"
|
name = "collab-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -901,7 +901,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-folder"
|
name = "collab-folder"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -938,7 +938,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-plugins"
|
name = "collab-plugins"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -977,7 +977,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-user"
|
name = "collab-user"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
|
@ -34,18 +34,38 @@ lru = "0.12.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
tauri = { version = "1.5", features = ["clipboard-all", "fs-all", "shell-open"] }
|
tauri = { version = "1.5", features = [
|
||||||
|
"clipboard-all",
|
||||||
|
"fs-all",
|
||||||
|
"shell-open",
|
||||||
|
] }
|
||||||
tauri-utils = "1.5.2"
|
tauri-utils = "1.5.2"
|
||||||
bytes.workspace = true
|
bytes.workspace = true
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
lib-dispatch = { path = "../../rust-lib/lib-dispatch", features = ["use_serde"] }
|
lib-dispatch = { path = "../../rust-lib/lib-dispatch", features = [
|
||||||
flowy-core = { path = "../../rust-lib/flowy-core", features = ["rev-sqlite", "ts"] }
|
"use_serde",
|
||||||
|
] }
|
||||||
|
flowy-core = { path = "../../rust-lib/flowy-core", features = [
|
||||||
|
"rev-sqlite",
|
||||||
|
"ts",
|
||||||
|
] }
|
||||||
flowy-user = { path = "../../rust-lib/flowy-user", features = ["tauri_ts"] }
|
flowy-user = { path = "../../rust-lib/flowy-user", features = ["tauri_ts"] }
|
||||||
flowy-config = { path = "../../rust-lib/flowy-config", features = ["tauri_ts"] }
|
flowy-config = { path = "../../rust-lib/flowy-config", features = ["tauri_ts"] }
|
||||||
flowy-date = { path = "../../rust-lib/flowy-date", features = ["tauri_ts"] }
|
flowy-date = { path = "../../rust-lib/flowy-date", features = ["tauri_ts"] }
|
||||||
flowy-error = { path = "../../rust-lib/flowy-error", features = ["impl_from_sqlite", "impl_from_dispatch_error", "impl_from_appflowy_cloud", "impl_from_reqwest", "impl_from_serde", "tauri_ts"] }
|
flowy-error = { path = "../../rust-lib/flowy-error", features = [
|
||||||
flowy-document = { path = "../../rust-lib/flowy-document", features = ["tauri_ts"] }
|
"impl_from_sqlite",
|
||||||
flowy-notification = { path = "../../rust-lib/flowy-notification", features = ["tauri_ts"] }
|
"impl_from_dispatch_error",
|
||||||
|
"impl_from_appflowy_cloud",
|
||||||
|
"impl_from_reqwest",
|
||||||
|
"impl_from_serde",
|
||||||
|
"tauri_ts",
|
||||||
|
] }
|
||||||
|
flowy-document = { path = "../../rust-lib/flowy-document", features = [
|
||||||
|
"tauri_ts",
|
||||||
|
] }
|
||||||
|
flowy-notification = { path = "../../rust-lib/flowy-notification", features = [
|
||||||
|
"tauri_ts",
|
||||||
|
] }
|
||||||
uuid = "1.5.0"
|
uuid = "1.5.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@ -72,10 +92,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d23
|
|||||||
# To switch to the local path, run:
|
# To switch to the local path, run:
|
||||||
# scripts/tool/update_collab_source.sh
|
# scripts/tool/update_collab_source.sh
|
||||||
# ⚠️⚠️⚠️️
|
# ⚠️⚠️⚠️️
|
||||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
|
@ -12,7 +12,7 @@ const deleteSortsFromChange = (database: Database, changeset: SortChangesetNotif
|
|||||||
|
|
||||||
const insertSortsFromChange = (database: Database, changeset: SortChangesetNotificationPB) => {
|
const insertSortsFromChange = (database: Database, changeset: SortChangesetNotificationPB) => {
|
||||||
changeset.insert_sorts.forEach(sortPB => {
|
changeset.insert_sorts.forEach(sortPB => {
|
||||||
database.sorts.push(pbToSort(sortPB));
|
database.sorts.push(pbToSort(sortPB.sort));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = ["af-wasm", "af-user", "af-persistence"]
|
||||||
"af-wasm",
|
|
||||||
"af-user",
|
|
||||||
"af-persistence",
|
|
||||||
]
|
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
@ -15,7 +11,7 @@ parking_lot = { version = "0.12.1" }
|
|||||||
tracing = { version = "0.1.22" }
|
tracing = { version = "0.1.22" }
|
||||||
serde = { version = "1.0.194", features = ["derive"] }
|
serde = { version = "1.0.194", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
collab-integrate = { path = "../../rust-lib/collab-integrate"}
|
collab-integrate = { path = "../../rust-lib/collab-integrate" }
|
||||||
flowy-notification = { path = "../../rust-lib/flowy-notification" }
|
flowy-notification = { path = "../../rust-lib/flowy-notification" }
|
||||||
flowy-user-pub = { path = "../../rust-lib/flowy-user-pub" }
|
flowy-user-pub = { path = "../../rust-lib/flowy-user-pub" }
|
||||||
flowy-server = { path = "../../rust-lib/flowy-server" }
|
flowy-server = { path = "../../rust-lib/flowy-server" }
|
||||||
@ -42,7 +38,6 @@ wasm-bindgen-futures = "0.4.40"
|
|||||||
serde-wasm-bindgen = "0.4"
|
serde-wasm-bindgen = "0.4"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 0
|
opt-level = 0
|
||||||
lto = false
|
lto = false
|
||||||
@ -70,10 +65,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d23
|
|||||||
# To switch to the local path, run:
|
# To switch to the local path, run:
|
||||||
# scripts/tool/update_collab_source.sh
|
# scripts/tool/update_collab_source.sh
|
||||||
# ⚠️⚠️⚠️️
|
# ⚠️⚠️⚠️️
|
||||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
|
14
frontend/rust-lib/Cargo.lock
generated
14
frontend/rust-lib/Cargo.lock
generated
@ -744,7 +744,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab"
|
name = "collab"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -766,7 +766,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-database"
|
name = "collab-database"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -795,7 +795,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-document"
|
name = "collab-document"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
@ -814,7 +814,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-entity"
|
name = "collab-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -829,7 +829,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-folder"
|
name = "collab-folder"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -866,7 +866,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-plugins"
|
name = "collab-plugins"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -905,7 +905,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-user"
|
name = "collab-user"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=a6b0932581b4544a0800a0451b9522e6caab5570#a6b0932581b4544a0800a0451b9522e6caab5570"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=2ce95b948accd6d14b97ee886f4416295acd9c65#2ce95b948accd6d14b97ee886f4416295acd9c65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
|
@ -115,10 +115,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "d23
|
|||||||
# To switch to the local path, run:
|
# To switch to the local path, run:
|
||||||
# scripts/tool/update_collab_source.sh
|
# scripts/tool/update_collab_source.sh
|
||||||
# ⚠️⚠️⚠️️
|
# ⚠️⚠️⚠️️
|
||||||
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "a6b0932581b4544a0800a0451b9522e6caab5570" }
|
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "2ce95b948accd6d14b97ee886f4416295acd9c65" }
|
||||||
|
@ -84,7 +84,7 @@ pub struct DeleteFilterPayloadPB {
|
|||||||
pub field_type: FieldType,
|
pub field_type: FieldType,
|
||||||
|
|
||||||
#[pb(index = 3)]
|
#[pb(index = 3)]
|
||||||
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
|
#[validate(custom = "crate::entities::utils::validate_filter_id")]
|
||||||
pub filter_id: String,
|
pub filter_id: String,
|
||||||
|
|
||||||
#[pb(index = 4)]
|
#[pb(index = 4)]
|
||||||
@ -103,7 +103,7 @@ pub struct UpdateFilterPayloadPB {
|
|||||||
|
|
||||||
/// Create a new filter if the filter_id is None
|
/// Create a new filter if the filter_id is None
|
||||||
#[pb(index = 3, one_of)]
|
#[pb(index = 3, one_of)]
|
||||||
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
|
#[validate(custom = "crate::entities::utils::validate_filter_id")]
|
||||||
pub filter_id: Option<String>,
|
pub filter_id: Option<String>,
|
||||||
|
|
||||||
#[pb(index = 4)]
|
#[pb(index = 4)]
|
||||||
|
@ -35,3 +35,25 @@ pub use share_entities::*;
|
|||||||
pub use sort_entities::*;
|
pub use sort_entities::*;
|
||||||
pub use type_option_entities::*;
|
pub use type_option_entities::*;
|
||||||
pub use view_entities::*;
|
pub use view_entities::*;
|
||||||
|
|
||||||
|
mod utils {
|
||||||
|
use fancy_regex::Regex;
|
||||||
|
use lib_infra::impl_regex_validator;
|
||||||
|
use validator::ValidationError;
|
||||||
|
|
||||||
|
impl_regex_validator!(
|
||||||
|
validate_filter_id,
|
||||||
|
Regex::new(r"^[A-Za-z0-9_-]{6}$").unwrap(),
|
||||||
|
"invalid filter_id"
|
||||||
|
);
|
||||||
|
impl_regex_validator!(
|
||||||
|
validate_sort_id,
|
||||||
|
Regex::new(r"^s:[A-Za-z0-9_-]{6}$").unwrap(),
|
||||||
|
"invalid sort_id"
|
||||||
|
);
|
||||||
|
impl_regex_validator!(
|
||||||
|
validate_group_id,
|
||||||
|
Regex::new(r"^g:[A-Za-z0-9_-]{6}$").unwrap(),
|
||||||
|
"invalid group_id"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ use crate::entities::{
|
|||||||
};
|
};
|
||||||
use crate::services::setting::{BoardLayoutSetting, CalendarLayoutSetting};
|
use crate::services::setting::{BoardLayoutSetting, CalendarLayoutSetting};
|
||||||
|
|
||||||
use super::BoardLayoutSettingPB;
|
use super::{BoardLayoutSettingPB, ReorderSortPayloadPB};
|
||||||
|
|
||||||
/// [DatabaseViewSettingPB] defines the setting options for the grid. Such as the filter, group, and sort.
|
/// [DatabaseViewSettingPB] defines the setting options for the grid. Such as the filter, group, and sort.
|
||||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||||
@ -39,9 +39,8 @@ pub struct DatabaseViewSettingPB {
|
|||||||
pub field_settings: RepeatedFieldSettingsPB,
|
pub field_settings: RepeatedFieldSettingsPB,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum, EnumIter)]
|
#[derive(Debug, Default, Clone, PartialEq, Eq, ProtoBuf_Enum, EnumIter)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Default)]
|
|
||||||
pub enum DatabaseLayoutPB {
|
pub enum DatabaseLayoutPB {
|
||||||
#[default]
|
#[default]
|
||||||
Grid = 0,
|
Grid = 0,
|
||||||
@ -96,6 +95,10 @@ pub struct DatabaseSettingChangesetPB {
|
|||||||
|
|
||||||
#[pb(index = 7, one_of)]
|
#[pb(index = 7, one_of)]
|
||||||
#[validate]
|
#[validate]
|
||||||
|
pub reorder_sort: Option<ReorderSortPayloadPB>,
|
||||||
|
|
||||||
|
#[pb(index = 8, one_of)]
|
||||||
|
#[validate]
|
||||||
pub delete_sort: Option<DeleteSortPayloadPB>,
|
pub delete_sort: Option<DeleteSortPayloadPB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,15 @@ impl std::convert::From<Sort> for SortPB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||||
|
pub struct SortWithIndexPB {
|
||||||
|
#[pb(index = 1)]
|
||||||
|
pub index: u32,
|
||||||
|
|
||||||
|
#[pb(index = 2)]
|
||||||
|
pub sort: SortPB,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
|
||||||
pub struct RepeatedSortPB {
|
pub struct RepeatedSortPB {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
@ -105,12 +114,28 @@ pub struct UpdateSortPayloadPB {
|
|||||||
|
|
||||||
/// Create a new sort if the sort_id is None
|
/// Create a new sort if the sort_id is None
|
||||||
#[pb(index = 4, one_of)]
|
#[pb(index = 4, one_of)]
|
||||||
|
#[validate(custom = "super::utils::validate_sort_id")]
|
||||||
pub sort_id: Option<String>,
|
pub sort_id: Option<String>,
|
||||||
|
|
||||||
#[pb(index = 5)]
|
#[pb(index = 5)]
|
||||||
pub condition: SortConditionPB,
|
pub condition: SortConditionPB,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Validate, ProtoBuf)]
|
||||||
|
pub struct ReorderSortPayloadPB {
|
||||||
|
#[pb(index = 1)]
|
||||||
|
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
|
||||||
|
pub view_id: String,
|
||||||
|
|
||||||
|
#[pb(index = 2)]
|
||||||
|
#[validate(custom = "super::utils::validate_sort_id")]
|
||||||
|
pub from_sort_id: String,
|
||||||
|
|
||||||
|
#[pb(index = 3)]
|
||||||
|
#[validate(custom = "super::utils::validate_sort_id")]
|
||||||
|
pub to_sort_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(ProtoBuf, Debug, Default, Clone, Validate)]
|
#[derive(ProtoBuf, Debug, Default, Clone, Validate)]
|
||||||
pub struct DeleteSortPayloadPB {
|
pub struct DeleteSortPayloadPB {
|
||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
@ -118,7 +143,7 @@ pub struct DeleteSortPayloadPB {
|
|||||||
pub view_id: String,
|
pub view_id: String,
|
||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
#[validate(custom = "lib_infra::validator_fn::required_not_empty_str")]
|
#[validate(custom = "super::utils::validate_sort_id")]
|
||||||
pub sort_id: String,
|
pub sort_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +153,7 @@ pub struct SortChangesetNotificationPB {
|
|||||||
pub view_id: String,
|
pub view_id: String,
|
||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
pub insert_sorts: Vec<SortPB>,
|
pub insert_sorts: Vec<SortWithIndexPB>,
|
||||||
|
|
||||||
#[pb(index = 3)]
|
#[pb(index = 3)]
|
||||||
pub delete_sorts: Vec<SortPB>,
|
pub delete_sorts: Vec<SortPB>,
|
||||||
|
@ -88,28 +88,32 @@ pub(crate) async fn update_database_setting_handler(
|
|||||||
) -> Result<(), FlowyError> {
|
) -> Result<(), FlowyError> {
|
||||||
let manager = upgrade_manager(manager)?;
|
let manager = upgrade_manager(manager)?;
|
||||||
let params = data.try_into_inner()?;
|
let params = data.try_into_inner()?;
|
||||||
let editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
let database_editor = manager.get_database_with_view_id(¶ms.view_id).await?;
|
||||||
|
|
||||||
if let Some(update_filter) = params.update_filter {
|
if let Some(update_filter) = params.update_filter {
|
||||||
editor
|
database_editor
|
||||||
.create_or_update_filter(update_filter.try_into()?)
|
.create_or_update_filter(update_filter.try_into()?)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(delete_filter) = params.delete_filter {
|
if let Some(delete_filter) = params.delete_filter {
|
||||||
editor.delete_filter(delete_filter).await?;
|
database_editor.delete_filter(delete_filter).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(update_sort) = params.update_sort {
|
if let Some(update_sort) = params.update_sort {
|
||||||
let _ = editor.create_or_update_sort(update_sort).await?;
|
let _ = database_editor.create_or_update_sort(update_sort).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(reorder_sort) = params.reorder_sort {
|
||||||
|
database_editor.reorder_sort(reorder_sort).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(delete_sort) = params.delete_sort {
|
if let Some(delete_sort) = params.delete_sort {
|
||||||
editor.delete_sort(delete_sort).await?;
|
database_editor.delete_sort(delete_sort).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(layout_type) = params.layout_type {
|
if let Some(layout_type) = params.layout_type {
|
||||||
editor
|
database_editor
|
||||||
.update_view_layout(¶ms.view_id, layout_type.into())
|
.update_view_layout(¶ms.view_id, layout_type.into())
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
@ -228,10 +228,16 @@ impl DatabaseEditor {
|
|||||||
|
|
||||||
pub async fn create_or_update_sort(&self, params: UpdateSortPayloadPB) -> FlowyResult<Sort> {
|
pub async fn create_or_update_sort(&self, params: UpdateSortPayloadPB) -> FlowyResult<Sort> {
|
||||||
let view_editor = self.database_views.get_view_editor(¶ms.view_id).await?;
|
let view_editor = self.database_views.get_view_editor(¶ms.view_id).await?;
|
||||||
let sort = view_editor.insert_or_update_sort(params).await?;
|
let sort = view_editor.v_create_or_update_sort(params).await?;
|
||||||
Ok(sort)
|
Ok(sort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn reorder_sort(&self, params: ReorderSortPayloadPB) -> FlowyResult<()> {
|
||||||
|
let view_editor = self.database_views.get_view_editor(¶ms.view_id).await?;
|
||||||
|
view_editor.v_reorder_sort(params).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn delete_sort(&self, params: DeleteSortPayloadPB) -> FlowyResult<()> {
|
pub async fn delete_sort(&self, params: DeleteSortPayloadPB) -> FlowyResult<()> {
|
||||||
let view_editor = self.database_views.get_view_editor(¶ms.view_id).await?;
|
let view_editor = self.database_views.get_view_editor(¶ms.view_id).await?;
|
||||||
view_editor.v_delete_sort(params).await?;
|
view_editor.v_delete_sort(params).await?;
|
||||||
@ -1459,6 +1465,13 @@ impl DatabaseViewOperation for DatabaseViewOperationImpl {
|
|||||||
self.database.lock().insert_sort(view_id, sort);
|
self.database.lock().insert_sort(view_id, sort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn move_sort(&self, view_id: &str, from_sort_id: &str, to_sort_id: &str) {
|
||||||
|
self
|
||||||
|
.database
|
||||||
|
.lock()
|
||||||
|
.move_sort(view_id, from_sort_id, to_sort_id);
|
||||||
|
}
|
||||||
|
|
||||||
fn remove_sort(&self, view_id: &str, sort_id: &str) {
|
fn remove_sort(&self, view_id: &str, sort_id: &str) {
|
||||||
self.database.lock().remove_sort(view_id, sort_id);
|
self.database.lock().remove_sort(view_id, sort_id);
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@ use lib_dispatch::prelude::af_spawn;
|
|||||||
use crate::entities::{
|
use crate::entities::{
|
||||||
CalendarEventPB, DatabaseLayoutMetaPB, DatabaseLayoutSettingPB, DeleteFilterPayloadPB,
|
CalendarEventPB, DatabaseLayoutMetaPB, DatabaseLayoutSettingPB, DeleteFilterPayloadPB,
|
||||||
DeleteSortPayloadPB, FieldType, FieldVisibility, GroupChangesPB, GroupPB, InsertedRowPB,
|
DeleteSortPayloadPB, FieldType, FieldVisibility, GroupChangesPB, GroupPB, InsertedRowPB,
|
||||||
LayoutSettingChangeset, LayoutSettingParams, RemoveCalculationChangesetPB, RowMetaPB,
|
LayoutSettingChangeset, LayoutSettingParams, RemoveCalculationChangesetPB, ReorderSortPayloadPB,
|
||||||
RowsChangePB, SortChangesetNotificationPB, SortPB, UpdateCalculationChangesetPB,
|
RowMetaPB, RowsChangePB, SortChangesetNotificationPB, SortPB, UpdateCalculationChangesetPB,
|
||||||
UpdateFilterParams, UpdateSortPayloadPB,
|
UpdateFilterParams, UpdateSortPayloadPB,
|
||||||
};
|
};
|
||||||
use crate::notification::{send_notification, DatabaseNotification};
|
use crate::notification::{send_notification, DatabaseNotification};
|
||||||
@ -499,7 +499,7 @@ impl DatabaseViewEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||||
pub async fn insert_or_update_sort(&self, params: UpdateSortPayloadPB) -> FlowyResult<Sort> {
|
pub async fn v_create_or_update_sort(&self, params: UpdateSortPayloadPB) -> FlowyResult<Sort> {
|
||||||
let is_exist = params.sort_id.is_some();
|
let is_exist = params.sort_id.is_some();
|
||||||
let sort_id = match params.sort_id {
|
let sort_id = match params.sort_id {
|
||||||
None => gen_database_sort_id(),
|
None => gen_database_sort_id(),
|
||||||
@ -513,9 +513,11 @@ impl DatabaseViewEditor {
|
|||||||
condition: params.condition.into(),
|
condition: params.condition.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut sort_controller = self.sort_controller.write().await;
|
|
||||||
self.delegate.insert_sort(&self.view_id, sort.clone());
|
self.delegate.insert_sort(&self.view_id, sort.clone());
|
||||||
let changeset = if is_exist {
|
|
||||||
|
let mut sort_controller = self.sort_controller.write().await;
|
||||||
|
|
||||||
|
let notification = if is_exist {
|
||||||
sort_controller
|
sort_controller
|
||||||
.apply_changeset(SortChangeset::from_update(sort.clone()))
|
.apply_changeset(SortChangeset::from_update(sort.clone()))
|
||||||
.await
|
.await
|
||||||
@ -525,10 +527,29 @@ impl DatabaseViewEditor {
|
|||||||
.await
|
.await
|
||||||
};
|
};
|
||||||
drop(sort_controller);
|
drop(sort_controller);
|
||||||
notify_did_update_sort(changeset).await;
|
notify_did_update_sort(notification).await;
|
||||||
Ok(sort)
|
Ok(sort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn v_reorder_sort(&self, params: ReorderSortPayloadPB) -> FlowyResult<()> {
|
||||||
|
self
|
||||||
|
.delegate
|
||||||
|
.move_sort(&self.view_id, ¶ms.from_sort_id, ¶ms.to_sort_id);
|
||||||
|
|
||||||
|
let notification = self
|
||||||
|
.sort_controller
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.apply_changeset(SortChangeset::from_reorder(
|
||||||
|
params.from_sort_id,
|
||||||
|
params.to_sort_id,
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
notify_did_update_sort(notification).await;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn v_delete_sort(&self, params: DeleteSortPayloadPB) -> FlowyResult<()> {
|
pub async fn v_delete_sort(&self, params: DeleteSortPayloadPB) -> FlowyResult<()> {
|
||||||
let notification = self
|
let notification = self
|
||||||
.sort_controller
|
.sort_controller
|
||||||
|
@ -75,6 +75,8 @@ pub trait DatabaseViewOperation: Send + Sync + 'static {
|
|||||||
|
|
||||||
fn insert_sort(&self, view_id: &str, sort: Sort);
|
fn insert_sort(&self, view_id: &str, sort: Sort);
|
||||||
|
|
||||||
|
fn move_sort(&self, view_id: &str, from_sort_id: &str, to_sort_id: &str);
|
||||||
|
|
||||||
fn remove_sort(&self, view_id: &str, sort_id: &str);
|
fn remove_sort(&self, view_id: &str, sort_id: &str);
|
||||||
|
|
||||||
fn get_all_sorts(&self, view_id: &str) -> Vec<Sort>;
|
fn get_all_sorts(&self, view_id: &str) -> Vec<Sort>;
|
||||||
|
@ -13,8 +13,8 @@ use flowy_error::FlowyResult;
|
|||||||
use lib_infra::future::Fut;
|
use lib_infra::future::Fut;
|
||||||
use lib_infra::priority_task::{QualityOfService, Task, TaskContent, TaskDispatcher};
|
use lib_infra::priority_task::{QualityOfService, Task, TaskContent, TaskDispatcher};
|
||||||
|
|
||||||
use crate::entities::FieldType;
|
|
||||||
use crate::entities::SortChangesetNotificationPB;
|
use crate::entities::SortChangesetNotificationPB;
|
||||||
|
use crate::entities::{FieldType, SortWithIndexPB};
|
||||||
use crate::services::cell::CellCache;
|
use crate::services::cell::CellCache;
|
||||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewChangedNotifier};
|
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewChangedNotifier};
|
||||||
use crate::services::field::{default_order, TypeOptionCellExt};
|
use crate::services::field::{default_order, TypeOptionCellExt};
|
||||||
@ -184,7 +184,10 @@ impl SortController {
|
|||||||
|
|
||||||
if let Some(insert_sort) = changeset.insert_sort {
|
if let Some(insert_sort) = changeset.insert_sort {
|
||||||
if let Some(sort) = self.delegate.get_sort(&self.view_id, &insert_sort.id).await {
|
if let Some(sort) = self.delegate.get_sort(&self.view_id, &insert_sort.id).await {
|
||||||
notification.insert_sorts.push(sort.as_ref().into());
|
notification.insert_sorts.push(SortWithIndexPB {
|
||||||
|
index: self.sorts.len() as u32,
|
||||||
|
sort: sort.as_ref().into(),
|
||||||
|
});
|
||||||
self.sorts.push(sort);
|
self.sorts.push(sort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,6 +212,23 @@ impl SortController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some((from_id, to_id)) = changeset.reorder_sort {
|
||||||
|
let moved_sort = self.delegate.get_sort(&self.view_id, &from_id).await;
|
||||||
|
let from_index = self.sorts.iter().position(|sort| sort.id == from_id);
|
||||||
|
let to_index = self.sorts.iter().position(|sort| sort.id == to_id);
|
||||||
|
|
||||||
|
if let (Some(sort), Some(from_index), Some(to_index)) = (moved_sort, from_index, to_index) {
|
||||||
|
self.sorts.remove(from_index);
|
||||||
|
self.sorts.insert(to_index, sort.clone());
|
||||||
|
|
||||||
|
notification.delete_sorts.push(sort.as_ref().into());
|
||||||
|
notification.insert_sorts.push(SortWithIndexPB {
|
||||||
|
index: to_index as u32,
|
||||||
|
sort: sort.as_ref().into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !notification.is_empty() {
|
if !notification.is_empty() {
|
||||||
self
|
self
|
||||||
.gen_task(SortEvent::SortDidChanged, QualityOfService::UserInteractive)
|
.gen_task(SortEvent::SortDidChanged, QualityOfService::UserInteractive)
|
||||||
|
@ -126,6 +126,7 @@ pub struct SortChangeset {
|
|||||||
pub(crate) insert_sort: Option<Sort>,
|
pub(crate) insert_sort: Option<Sort>,
|
||||||
pub(crate) update_sort: Option<Sort>,
|
pub(crate) update_sort: Option<Sort>,
|
||||||
pub(crate) delete_sort: Option<String>,
|
pub(crate) delete_sort: Option<String>,
|
||||||
|
pub(crate) reorder_sort: Option<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SortChangeset {
|
impl SortChangeset {
|
||||||
@ -134,6 +135,7 @@ impl SortChangeset {
|
|||||||
insert_sort: Some(sort),
|
insert_sort: Some(sort),
|
||||||
update_sort: None,
|
update_sort: None,
|
||||||
delete_sort: None,
|
delete_sort: None,
|
||||||
|
reorder_sort: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +144,7 @@ impl SortChangeset {
|
|||||||
insert_sort: None,
|
insert_sort: None,
|
||||||
update_sort: Some(sort),
|
update_sort: Some(sort),
|
||||||
delete_sort: None,
|
delete_sort: None,
|
||||||
|
reorder_sort: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +153,16 @@ impl SortChangeset {
|
|||||||
insert_sort: None,
|
insert_sort: None,
|
||||||
update_sort: None,
|
update_sort: None,
|
||||||
delete_sort: Some(sort_id),
|
delete_sort: Some(sort_id),
|
||||||
|
reorder_sort: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_reorder(from_sort_id: String, to_sort_id: String) -> Self {
|
||||||
|
Self {
|
||||||
|
insert_sort: None,
|
||||||
|
update_sort: None,
|
||||||
|
delete_sort: None,
|
||||||
|
reorder_sort: Some((from_sort_id, to_sort_id)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,3 +47,55 @@ async fn sort_checkbox_and_then_text_by_descending_test() {
|
|||||||
];
|
];
|
||||||
test.run_scripts(scripts).await;
|
test.run_scripts(scripts).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn reorder_sort_test() {
|
||||||
|
let mut test = DatabaseSortTest::new().await;
|
||||||
|
let checkbox_field = test.get_first_field(FieldType::Checkbox);
|
||||||
|
let text_field = test.get_first_field(FieldType::RichText);
|
||||||
|
// Use the same sort set up as above
|
||||||
|
let scripts = vec![
|
||||||
|
AssertCellContentOrder {
|
||||||
|
field_id: checkbox_field.id.clone(),
|
||||||
|
orders: vec!["Yes", "Yes", "No", "No", "No", "Yes", ""],
|
||||||
|
},
|
||||||
|
AssertCellContentOrder {
|
||||||
|
field_id: text_field.id.clone(),
|
||||||
|
orders: vec!["A", "", "C", "DA", "AE", "AE", "CB"],
|
||||||
|
},
|
||||||
|
InsertSort {
|
||||||
|
field: checkbox_field.clone(),
|
||||||
|
condition: SortCondition::Descending,
|
||||||
|
},
|
||||||
|
InsertSort {
|
||||||
|
field: text_field.clone(),
|
||||||
|
condition: SortCondition::Ascending,
|
||||||
|
},
|
||||||
|
AssertCellContentOrder {
|
||||||
|
field_id: checkbox_field.id.clone(),
|
||||||
|
orders: vec!["Yes", "Yes", "Yes", "No", "No", "", "No"],
|
||||||
|
},
|
||||||
|
AssertCellContentOrder {
|
||||||
|
field_id: text_field.id.clone(),
|
||||||
|
orders: vec!["A", "AE", "", "AE", "C", "CB", "DA"],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
test.run_scripts(scripts).await;
|
||||||
|
|
||||||
|
let sorts = test.editor.get_all_sorts(&test.view_id).await.items;
|
||||||
|
let scripts = vec![
|
||||||
|
ReorderSort {
|
||||||
|
from_sort_id: sorts[1].id.clone(),
|
||||||
|
to_sort_id: sorts[0].id.clone(),
|
||||||
|
},
|
||||||
|
AssertCellContentOrder {
|
||||||
|
field_id: checkbox_field.id.clone(),
|
||||||
|
orders: vec!["Yes", "Yes", "No", "No", "", "No", "Yes"],
|
||||||
|
},
|
||||||
|
AssertCellContentOrder {
|
||||||
|
field_id: text_field.id.clone(),
|
||||||
|
orders: vec!["A", "AE", "AE", "C", "CB", "DA", ""],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
test.run_scripts(scripts).await;
|
||||||
|
}
|
||||||
|
@ -7,10 +7,12 @@ use collab_database::rows::RowId;
|
|||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use tokio::sync::broadcast::Receiver;
|
use tokio::sync::broadcast::Receiver;
|
||||||
|
|
||||||
use flowy_database2::entities::{DeleteSortPayloadPB, FieldType, UpdateSortPayloadPB};
|
use flowy_database2::entities::{
|
||||||
|
DeleteSortPayloadPB, FieldType, ReorderSortPayloadPB, UpdateSortPayloadPB,
|
||||||
|
};
|
||||||
use flowy_database2::services::cell::stringify_cell_data;
|
use flowy_database2::services::cell::stringify_cell_data;
|
||||||
use flowy_database2::services::database_view::DatabaseViewChanged;
|
use flowy_database2::services::database_view::DatabaseViewChanged;
|
||||||
use flowy_database2::services::sort::{Sort, SortCondition};
|
use flowy_database2::services::sort::SortCondition;
|
||||||
|
|
||||||
use crate::database::database_editor::DatabaseEditorTest;
|
use crate::database::database_editor::DatabaseEditorTest;
|
||||||
|
|
||||||
@ -19,6 +21,10 @@ pub enum SortScript {
|
|||||||
field: Field,
|
field: Field,
|
||||||
condition: SortCondition,
|
condition: SortCondition,
|
||||||
},
|
},
|
||||||
|
ReorderSort {
|
||||||
|
from_sort_id: String,
|
||||||
|
to_sort_id: String,
|
||||||
|
},
|
||||||
DeleteSort {
|
DeleteSort {
|
||||||
sort_id: String,
|
sort_id: String,
|
||||||
},
|
},
|
||||||
@ -41,7 +47,6 @@ pub enum SortScript {
|
|||||||
|
|
||||||
pub struct DatabaseSortTest {
|
pub struct DatabaseSortTest {
|
||||||
inner: DatabaseEditorTest,
|
inner: DatabaseEditorTest,
|
||||||
pub current_sort_rev: Option<Sort>,
|
|
||||||
recv: Option<Receiver<DatabaseViewChanged>>,
|
recv: Option<Receiver<DatabaseViewChanged>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +55,6 @@ impl DatabaseSortTest {
|
|||||||
let editor_test = DatabaseEditorTest::new_grid().await;
|
let editor_test = DatabaseEditorTest::new_grid().await;
|
||||||
Self {
|
Self {
|
||||||
inner: editor_test,
|
inner: editor_test,
|
||||||
current_sort_rev: None,
|
|
||||||
recv: None,
|
recv: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,8 +81,25 @@ impl DatabaseSortTest {
|
|||||||
field_type: FieldType::from(field.field_type),
|
field_type: FieldType::from(field.field_type),
|
||||||
condition: condition.into(),
|
condition: condition.into(),
|
||||||
};
|
};
|
||||||
let sort_rev = self.editor.create_or_update_sort(params).await.unwrap();
|
let _ = self.editor.create_or_update_sort(params).await.unwrap();
|
||||||
self.current_sort_rev = Some(sort_rev);
|
},
|
||||||
|
SortScript::ReorderSort {
|
||||||
|
from_sort_id,
|
||||||
|
to_sort_id,
|
||||||
|
} => {
|
||||||
|
self.recv = Some(
|
||||||
|
self
|
||||||
|
.editor
|
||||||
|
.subscribe_view_changed(&self.view_id)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
let params = ReorderSortPayloadPB {
|
||||||
|
view_id: self.view_id.clone(),
|
||||||
|
from_sort_id,
|
||||||
|
to_sort_id,
|
||||||
|
};
|
||||||
|
self.editor.reorder_sort(params).await.unwrap();
|
||||||
},
|
},
|
||||||
SortScript::DeleteSort { sort_id } => {
|
SortScript::DeleteSort { sort_id } => {
|
||||||
self.recv = Some(
|
self.recv = Some(
|
||||||
@ -93,7 +114,6 @@ impl DatabaseSortTest {
|
|||||||
sort_id,
|
sort_id,
|
||||||
};
|
};
|
||||||
self.editor.delete_sort(params).await.unwrap();
|
self.editor.delete_sort(params).await.unwrap();
|
||||||
self.current_sort_rev = None;
|
|
||||||
},
|
},
|
||||||
SortScript::AssertCellContentOrder { field_id, orders } => {
|
SortScript::AssertCellContentOrder { field_id, orders } => {
|
||||||
let mut cells = vec![];
|
let mut cells = vec![];
|
||||||
|
@ -85,16 +85,21 @@ async fn sort_change_notification_by_update_text_test() {
|
|||||||
async fn sort_text_by_ascending_and_delete_sort_test() {
|
async fn sort_text_by_ascending_and_delete_sort_test() {
|
||||||
let mut test = DatabaseSortTest::new().await;
|
let mut test = DatabaseSortTest::new().await;
|
||||||
let text_field = test.get_first_field(FieldType::RichText).clone();
|
let text_field = test.get_first_field(FieldType::RichText).clone();
|
||||||
let scripts = vec![InsertSort {
|
|
||||||
field: text_field.clone(),
|
|
||||||
condition: SortCondition::Ascending,
|
|
||||||
}];
|
|
||||||
test.run_scripts(scripts).await;
|
|
||||||
let sort = test.current_sort_rev.as_ref().unwrap();
|
|
||||||
let scripts = vec![
|
let scripts = vec![
|
||||||
DeleteSort {
|
InsertSort {
|
||||||
sort_id: sort.id.clone(),
|
field: text_field.clone(),
|
||||||
|
condition: SortCondition::Ascending,
|
||||||
},
|
},
|
||||||
|
AssertCellContentOrder {
|
||||||
|
field_id: text_field.id.clone(),
|
||||||
|
orders: vec!["A", "AE", "AE", "C", "CB", "DA", ""],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
test.run_scripts(scripts).await;
|
||||||
|
|
||||||
|
let sort = test.editor.get_all_sorts(&test.view_id).await.items[0].clone();
|
||||||
|
let scripts = vec![
|
||||||
|
DeleteSort { sort_id: sort.id },
|
||||||
AssertCellContentOrder {
|
AssertCellContentOrder {
|
||||||
field_id: text_field.id.clone(),
|
field_id: text_field.id.clone(),
|
||||||
orders: vec!["A", "", "C", "DA", "AE", "AE", "CB"],
|
orders: vec!["A", "", "C", "DA", "AE", "AE", "CB"],
|
||||||
|
@ -15,3 +15,28 @@ pub fn required_valid_path(s: &str) -> Result<(), ValidationError> {
|
|||||||
(_, _) => Err(ValidationError::new("invalid_path")),
|
(_, _) => Err(ValidationError::new("invalid_path")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
/// Macro to implement a custom validator function for a regex expression.
|
||||||
|
/// This is intended to replace `validator` crate's own regex validator, which
|
||||||
|
/// isn't compatible with `fancy_regex`.
|
||||||
|
///
|
||||||
|
/// # Arguments:
|
||||||
|
///
|
||||||
|
/// - name of the validator function
|
||||||
|
/// - the `fancy_regex::Regex` object
|
||||||
|
/// - error message of the `ValidationError`
|
||||||
|
///
|
||||||
|
macro_rules! impl_regex_validator {
|
||||||
|
($validator: ident, $regex: expr, $error: expr) => {
|
||||||
|
pub(crate) fn $validator(arg: &str) -> Result<(), ValidationError> {
|
||||||
|
let check = $regex.is_match(arg).unwrap();
|
||||||
|
|
||||||
|
if check {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ValidationError::new($error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user