Skip to content

Commit fb9bc35

Browse files
authored
feat: disable moving page into the database (#3107)
1 parent 135d8a8 commit fb9bc35

File tree

9 files changed

+182
-28
lines changed

9 files changed

+182
-28
lines changed

frontend/appflowy_flutter/integration_test/sidebar/sidebar_test.dart

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import 'package:appflowy/plugins/database_view/board/presentation/board_page.dar
22
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
33
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';
44
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
5+
import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.dart';
56
import 'package:appflowy/workspace/presentation/home/menu/view/view_item.dart';
7+
import 'package:appflowy/workspace/presentation/home/menu/view/view_more_action_button.dart';
68
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
79
import 'package:appflowy_editor/appflowy_editor.dart';
810
import 'package:flutter/material.dart';
@@ -138,5 +140,70 @@ void main() {
138140
.id,
139141
);
140142
});
143+
144+
testWidgets('unable to move a document into a database', (tester) async {
145+
await tester.initializeAppFlowy();
146+
await tester.tapGoButton();
147+
148+
const document = 'document';
149+
await tester.createNewPageWithName(
150+
name: document,
151+
openAfterCreated: false,
152+
);
153+
tester.expectToSeePageName(document, layout: ViewLayoutPB.Document);
154+
155+
const grid = 'grid';
156+
await tester.createNewPageWithName(
157+
name: grid,
158+
layout: ViewLayoutPB.Grid,
159+
openAfterCreated: false,
160+
);
161+
tester.expectToSeePageName(grid, layout: ViewLayoutPB.Grid);
162+
163+
// move the document to the grid page
164+
await tester.movePageToOtherPage(
165+
name: document,
166+
parentName: grid,
167+
layout: ViewLayoutPB.Document,
168+
parentLayout: ViewLayoutPB.Grid,
169+
);
170+
171+
// it should not be moved
172+
final childViews = tester
173+
.widget<SingleInnerViewItem>(tester.findPageName(gettingStated))
174+
.view
175+
.childViews;
176+
expect(
177+
childViews[0].name,
178+
document,
179+
);
180+
expect(
181+
childViews[1].name,
182+
grid,
183+
);
184+
});
185+
186+
testWidgets('unable to create a new database inside the existing one',
187+
(tester) async {
188+
await tester.initializeAppFlowy();
189+
await tester.tapGoButton();
190+
191+
const grid = 'grid';
192+
await tester.createNewPageWithName(
193+
name: grid,
194+
layout: ViewLayoutPB.Grid,
195+
openAfterCreated: true,
196+
);
197+
tester.expectToSeePageName(grid, layout: ViewLayoutPB.Grid);
198+
199+
await tester.hoverOnPageName(
200+
grid,
201+
layout: ViewLayoutPB.Grid,
202+
onHover: () async {
203+
expect(find.byType(ViewAddButton), findsNothing);
204+
expect(find.byType(ViewMoreActionButton), findsOneWidget);
205+
},
206+
);
207+
});
141208
});
142209
}

frontend/appflowy_flutter/integration_test/util/common_operations.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ extension CommonOperations on WidgetTester {
351351
await hoverOnPageName(
352352
name,
353353
layout: layout,
354-
useLast: false,
354+
useLast: true,
355355
onHover: () async {
356356
await tapFavoritePageButton();
357357
await pumpAndSettle();
@@ -366,7 +366,7 @@ extension CommonOperations on WidgetTester {
366366
await hoverOnPageName(
367367
name,
368368
layout: layout,
369-
useLast: false,
369+
useLast: true,
370370
onHover: () async {
371371
await tapUnfavoritePageButton();
372372
await pumpAndSettle();
@@ -397,7 +397,7 @@ extension CommonOperations on WidgetTester {
397397
break;
398398
default:
399399
}
400-
await gesture.moveTo(offset);
400+
await gesture.moveTo(offset, timeStamp: const Duration(milliseconds: 400));
401401
await gesture.up();
402402
await pumpAndSettle();
403403
}

frontend/appflowy_flutter/lib/workspace/application/menu/menu_bloc.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
4242
final result = await _workspaceService.createApp(
4343
name: event.name,
4444
desc: event.desc,
45-
index: 0, // default to the first index
45+
index: event.index,
4646
);
4747
result.fold(
4848
(app) => emit(state.copyWith(plugin: app.plugin())),
@@ -111,7 +111,8 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
111111
class MenuEvent with _$MenuEvent {
112112
const factory MenuEvent.initial() = _Initial;
113113
const factory MenuEvent.openPage(Plugin plugin) = _OpenPage;
114-
const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp;
114+
const factory MenuEvent.createApp(String name, {String? desc, int? index}) =
115+
_CreateApp;
115116
const factory MenuEvent.moveApp(int fromIndex, int toIndex) = _MoveApp;
116117
const factory MenuEvent.didReceiveApps(
117118
Either<List<ViewPB>, FlowyError> appsOrFail,

frontend/appflowy_flutter/lib/workspace/application/view/view_ext.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,17 @@ extension ViewLayoutExtension on ViewLayoutPB {
125125
throw Exception('Unknown layout type');
126126
}
127127
}
128+
129+
bool get isDatabaseView {
130+
switch (this) {
131+
case ViewLayoutPB.Grid:
132+
case ViewLayoutPB.Board:
133+
case ViewLayoutPB.Calendar:
134+
return true;
135+
case ViewLayoutPB.Document:
136+
return false;
137+
default:
138+
throw Exception('Unknown layout type');
139+
}
140+
}
128141
}

frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/folder/personal_folder.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class PersonalFolder extends StatelessWidget {
4949
isFirstChild: view.id == views.first.id,
5050
view: view,
5151
level: 0,
52+
leftPadding: 16,
5253
onSelected: (view) {
5354
getIt<TabsBloc>().add(
5455
TabsEvent.openPlugin(
@@ -114,6 +115,7 @@ class _PersonalFolderHeaderState extends State<PersonalFolderHeader> {
114115
context.read<MenuBloc>().add(
115116
MenuEvent.createApp(
116117
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
118+
index: 0,
117119
),
118120
);
119121
widget.onAdded();

frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ class SidebarNewPageButton extends StatelessWidget {
4848
value: '',
4949
confirm: (value) {
5050
if (value.isNotEmpty) {
51-
context.read<MenuBloc>().add(MenuEvent.createApp(value, desc: ''));
51+
context.read<MenuBloc>().add(
52+
MenuEvent.createApp(
53+
value,
54+
desc: '',
55+
),
56+
);
5257
}
5358
},
5459
).show(context);

frontend/appflowy_flutter/lib/workspace/presentation/home/menu/view/draggable_view_item.dart

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:appflowy/workspace/application/view/view_bloc.dart';
2+
import 'package:appflowy/workspace/application/view/view_ext.dart';
23
import 'package:appflowy/workspace/presentation/widgets/draggable_item/draggable_item.dart';
34
import 'package:appflowy_backend/log.dart';
45
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
@@ -70,16 +71,17 @@ class _DraggableViewItemState extends State<DraggableViewItem> {
7071
data: widget.view,
7172
onWillAccept: (data) => true,
7273
onMove: (data) {
73-
if (!_shouldAccept(data.data)) {
74-
return;
75-
}
7674
final renderBox = context.findRenderObject() as RenderBox;
7775
final offset = renderBox.globalToLocal(data.offset);
76+
final position = _computeHoverPosition(offset, renderBox.size);
77+
if (!_shouldAccept(data.data, position)) {
78+
return;
79+
}
7880
setState(() {
79-
position = _computeHoverPosition(offset, renderBox.size);
8081
Log.debug(
8182
'offset: $offset, position: $position, size: ${renderBox.size}',
8283
);
84+
this.position = position;
8385
});
8486
},
8587
onLeave: (_) => setState(
@@ -102,6 +104,12 @@ class _DraggableViewItemState extends State<DraggableViewItem> {
102104
}
103105

104106
void _move(ViewPB from, ViewPB to) {
107+
if (position == DraggableHoverPosition.center &&
108+
to.layout != ViewLayoutPB.Document) {
109+
// not support moving into a database
110+
return;
111+
}
112+
105113
switch (position) {
106114
case DraggableHoverPosition.top:
107115
context.read<ViewBloc>().add(
@@ -136,7 +144,7 @@ class _DraggableViewItemState extends State<DraggableViewItem> {
136144
}
137145

138146
DraggableHoverPosition _computeHoverPosition(Offset offset, Size size) {
139-
final threshold = size.height / 4.0;
147+
final threshold = size.height / 3.0;
140148
if (widget.isFirstChild && offset.dy < -5.0) {
141149
return DraggableHoverPosition.top;
142150
}
@@ -146,7 +154,13 @@ class _DraggableViewItemState extends State<DraggableViewItem> {
146154
return DraggableHoverPosition.center;
147155
}
148156

149-
bool _shouldAccept(ViewPB data) {
157+
bool _shouldAccept(ViewPB data, DraggableHoverPosition position) {
158+
// could not move the view to a database
159+
if (widget.view.layout.isDatabaseView &&
160+
position == DraggableHoverPosition.center) {
161+
return false;
162+
}
163+
150164
// ignore moving the view to itself
151165
if (data.id == widget.view.id) {
152166
return false;

0 commit comments

Comments
 (0)