mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-13 00:48:20 +00:00
fix: launch 0.7.4 review issues on desktop (#6792)
* chore: enable document test runner * fix: double menu showing in workspace menu * feat: only display copy in ai message * test: add test * test: fix integration test * fix: rust ci
This commit is contained in:
parent
bced9327b1
commit
6ffb9e4d0f
@ -1,6 +1,8 @@
|
|||||||
import 'package:appflowy/env/cloud_env.dart';
|
import 'package:appflowy/env/cloud_env.dart';
|
||||||
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/shared/feature_flags.dart';
|
import 'package:appflowy/shared/feature_flags.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/uuid.dart';
|
import 'package:flowy_infra/uuid.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
@ -38,6 +40,10 @@ void main() {
|
|||||||
await tester.changeWorkspaceIcon(icon);
|
await tester.changeWorkspaceIcon(icon);
|
||||||
await tester.changeWorkspaceName(name);
|
await tester.changeWorkspaceName(name);
|
||||||
|
|
||||||
|
await tester.pumpUntilNotFound(
|
||||||
|
find.text(LocaleKeys.workspace_renameSuccess.tr()),
|
||||||
|
);
|
||||||
|
|
||||||
workspaceIcon = tester.widget<WorkspaceIcon>(
|
workspaceIcon = tester.widget<WorkspaceIcon>(
|
||||||
find.byType(WorkspaceIcon),
|
find.byType(WorkspaceIcon),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -101,5 +101,52 @@ void main() {
|
|||||||
final memberCount = find.text('1 member');
|
final memberCount = find.text('1 member');
|
||||||
expect(memberCount, findsNWidgets(2));
|
expect(memberCount, findsNWidgets(2));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('only display one menu item in the workspace menu',
|
||||||
|
(tester) async {
|
||||||
|
// only run the test when the feature flag is on
|
||||||
|
if (!FeatureFlag.collaborativeWorkspace.isOn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await tester.initializeAppFlowy(
|
||||||
|
cloudType: AuthenticatorType.appflowyCloudSelfHost,
|
||||||
|
);
|
||||||
|
await tester.tapGoogleLoginInButton();
|
||||||
|
await tester.expectToSeeHomePageWithGetStartedPage();
|
||||||
|
|
||||||
|
const name = 'AppFlowy.IO';
|
||||||
|
// the workspace will be opened after created
|
||||||
|
await tester.createCollaborativeWorkspace(name);
|
||||||
|
|
||||||
|
final loading = find.byType(Loading);
|
||||||
|
await tester.pumpUntilNotFound(loading);
|
||||||
|
|
||||||
|
await tester.openCollaborativeWorkspaceMenu();
|
||||||
|
|
||||||
|
// hover on the workspace and click the more button
|
||||||
|
final workspaceItem = find.byWidgetPredicate(
|
||||||
|
(w) => w is WorkspaceMenuItem && w.workspace.name == name,
|
||||||
|
);
|
||||||
|
await tester.hoverOnWidget(
|
||||||
|
workspaceItem,
|
||||||
|
onHover: () async {
|
||||||
|
final moreButton = find.byWidgetPredicate(
|
||||||
|
(w) => w is WorkspaceMoreActionList && w.workspace.name == name,
|
||||||
|
);
|
||||||
|
expect(moreButton, findsOneWidget);
|
||||||
|
await tester.tapButton(moreButton);
|
||||||
|
|
||||||
|
// click it again
|
||||||
|
await tester.tapButton(moreButton);
|
||||||
|
|
||||||
|
// nothing should happen
|
||||||
|
expect(
|
||||||
|
find.text(LocaleKeys.button_rename.tr()),
|
||||||
|
findsOneWidget,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'mobile/document/page_style_test.dart' as page_style_test;
|
import 'mobile/document/document_test_runner.dart' as document_test_runner;
|
||||||
import 'mobile/home_page/create_new_page_test.dart' as create_new_page_test;
|
import 'mobile/home_page/create_new_page_test.dart' as create_new_page_test;
|
||||||
import 'mobile/sign_in/anonymous_sign_in_test.dart' as anonymous_sign_in_test;
|
import 'mobile/sign_in/anonymous_sign_in_test.dart' as anonymous_sign_in_test;
|
||||||
|
|
||||||
@ -16,5 +16,5 @@ Future<void> runIntegration1OnMobile() async {
|
|||||||
|
|
||||||
anonymous_sign_in_test.main();
|
anonymous_sign_in_test.main();
|
||||||
create_new_page_test.main();
|
create_new_page_test.main();
|
||||||
page_style_test.main();
|
document_test_runner.main();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,9 +40,13 @@ extension AppFlowyWorkspace on WidgetTester {
|
|||||||
moreButton,
|
moreButton,
|
||||||
onHover: () async {
|
onHover: () async {
|
||||||
await tapButton(moreButton);
|
await tapButton(moreButton);
|
||||||
await tapButton(
|
// wait for the menu to open
|
||||||
find.findTextInFlowyText(LocaleKeys.button_rename.tr()),
|
final renameButton = find.findTextInFlowyText(
|
||||||
|
LocaleKeys.button_rename.tr(),
|
||||||
);
|
);
|
||||||
|
await pumpUntilFound(renameButton);
|
||||||
|
expect(renameButton, findsOneWidget);
|
||||||
|
await tapButton(renameButton);
|
||||||
final input = find.byType(TextFormField);
|
final input = find.byType(TextFormField);
|
||||||
expect(input, findsOneWidget);
|
expect(input, findsOneWidget);
|
||||||
await enterText(input, name);
|
await enterText(input, name);
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
|
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||||
@ -5,6 +6,7 @@ import 'package:appflowy/shared/markdown_to_document.dart';
|
|||||||
import 'package:appflowy/util/theme_extension.dart';
|
import 'package:appflowy/util/theme_extension.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
@ -126,6 +128,15 @@ class _AppFlowyEditorMarkdownState extends State<_AppFlowyEditorMarkdown> {
|
|||||||
commandShortcutEvents: [customCopyCommand],
|
commandShortcutEvents: [customCopyCommand],
|
||||||
disableAutoScroll: true,
|
disableAutoScroll: true,
|
||||||
editorState: editorState,
|
editorState: editorState,
|
||||||
|
contextMenuItems: [
|
||||||
|
[
|
||||||
|
ContextMenuItem(
|
||||||
|
getName: LocaleKeys.document_plugins_contextMenu_copy.tr,
|
||||||
|
onPressed: (editorState) =>
|
||||||
|
customCopyCommand.execute(editorState),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,9 +22,11 @@ class WorkspaceMoreActionList extends StatelessWidget {
|
|||||||
const WorkspaceMoreActionList({
|
const WorkspaceMoreActionList({
|
||||||
super.key,
|
super.key,
|
||||||
required this.workspace,
|
required this.workspace,
|
||||||
|
required this.isShowingMoreActions,
|
||||||
});
|
});
|
||||||
|
|
||||||
final UserWorkspacePB workspace;
|
final UserWorkspacePB workspace;
|
||||||
|
final ValueNotifier<bool> isShowingMoreActions;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -46,6 +48,13 @@ class WorkspaceMoreActionList extends StatelessWidget {
|
|||||||
.map((e) => _WorkspaceMoreActionWrapper(e, workspace))
|
.map((e) => _WorkspaceMoreActionWrapper(e, workspace))
|
||||||
.toList(),
|
.toList(),
|
||||||
constraints: const BoxConstraints(minWidth: 220),
|
constraints: const BoxConstraints(minWidth: 220),
|
||||||
|
animationDuration: Durations.short3,
|
||||||
|
slideDistance: 2,
|
||||||
|
beginScaleFactor: 1.0,
|
||||||
|
beginOpacity: 0.8,
|
||||||
|
onClosed: () {
|
||||||
|
isShowingMoreActions.value = false;
|
||||||
|
},
|
||||||
buildChild: (controller) {
|
buildChild: (controller) {
|
||||||
return SizedBox.square(
|
return SizedBox.square(
|
||||||
dimension: 24.0,
|
dimension: 24.0,
|
||||||
@ -55,7 +64,11 @@ class WorkspaceMoreActionList extends StatelessWidget {
|
|||||||
FlowySvgs.workspace_three_dots_s,
|
FlowySvgs.workspace_three_dots_s,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
controller.show();
|
if (!isShowingMoreActions.value) {
|
||||||
|
controller.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
isShowingMoreActions.value = true;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -25,7 +25,7 @@ const createWorkspaceButtonKey = ValueKey('createWorkspaceButton');
|
|||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
const importNotionButtonKey = ValueKey('importNotinoButton');
|
const importNotionButtonKey = ValueKey('importNotinoButton');
|
||||||
|
|
||||||
class WorkspacesMenu extends StatelessWidget {
|
class WorkspacesMenu extends StatefulWidget {
|
||||||
const WorkspacesMenu({
|
const WorkspacesMenu({
|
||||||
super.key,
|
super.key,
|
||||||
required this.userProfile,
|
required this.userProfile,
|
||||||
@ -37,6 +37,19 @@ class WorkspacesMenu extends StatelessWidget {
|
|||||||
final UserWorkspacePB currentWorkspace;
|
final UserWorkspacePB currentWorkspace;
|
||||||
final List<UserWorkspacePB> workspaces;
|
final List<UserWorkspacePB> workspaces;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<WorkspacesMenu> createState() => _WorkspacesMenuState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WorkspacesMenuState extends State<WorkspacesMenu> {
|
||||||
|
final ValueNotifier<bool> isShowingMoreActions = ValueNotifier(false);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
isShowingMoreActions.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
@ -72,13 +85,14 @@ class WorkspacesMenu extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
for (final workspace in workspaces) ...[
|
for (final workspace in widget.workspaces) ...[
|
||||||
WorkspaceMenuItem(
|
WorkspaceMenuItem(
|
||||||
key: ValueKey(workspace.workspaceId),
|
key: ValueKey(workspace.workspaceId),
|
||||||
workspace: workspace,
|
workspace: workspace,
|
||||||
userProfile: userProfile,
|
userProfile: widget.userProfile,
|
||||||
isSelected:
|
isSelected: workspace.workspaceId ==
|
||||||
workspace.workspaceId == currentWorkspace.workspaceId,
|
widget.currentWorkspace.workspaceId,
|
||||||
|
isShowingMoreActions: isShowingMoreActions,
|
||||||
),
|
),
|
||||||
const VSpace(6.0),
|
const VSpace(6.0),
|
||||||
],
|
],
|
||||||
@ -99,12 +113,12 @@ class WorkspacesMenu extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _getUserInfo() {
|
String _getUserInfo() {
|
||||||
if (userProfile.email.isNotEmpty) {
|
if (widget.userProfile.email.isNotEmpty) {
|
||||||
return userProfile.email;
|
return widget.userProfile.email;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userProfile.name.isNotEmpty) {
|
if (widget.userProfile.name.isNotEmpty) {
|
||||||
return userProfile.name;
|
return widget.userProfile.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LocaleKeys.defaultUsername.tr();
|
return LocaleKeys.defaultUsername.tr();
|
||||||
@ -117,11 +131,13 @@ class WorkspaceMenuItem extends StatefulWidget {
|
|||||||
required this.workspace,
|
required this.workspace,
|
||||||
required this.userProfile,
|
required this.userProfile,
|
||||||
required this.isSelected,
|
required this.isSelected,
|
||||||
|
required this.isShowingMoreActions,
|
||||||
});
|
});
|
||||||
|
|
||||||
final UserProfilePB userProfile;
|
final UserProfilePB userProfile;
|
||||||
final UserWorkspacePB workspace;
|
final UserWorkspacePB workspace;
|
||||||
final bool isSelected;
|
final bool isSelected;
|
||||||
|
final ValueNotifier<bool> isShowingMoreActions;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<WorkspaceMenuItem> createState() => _WorkspaceMenuItemState();
|
State<WorkspaceMenuItem> createState() => _WorkspaceMenuItemState();
|
||||||
@ -211,7 +227,10 @@ class _WorkspaceMenuItemState extends State<WorkspaceMenuItem> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: WorkspaceMoreActionList(workspace: widget.workspace),
|
child: WorkspaceMoreActionList(
|
||||||
|
workspace: widget.workspace,
|
||||||
|
isShowingMoreActions: widget.isShowingMoreActions,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const HSpace(8.0),
|
const HSpace(8.0),
|
||||||
if (widget.isSelected) ...[
|
if (widget.isSelected) ...[
|
||||||
|
|||||||
@ -5,13 +5,14 @@ use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
|
|||||||
use tracing::{error, trace};
|
use tracing::{error, trace};
|
||||||
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
|
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct WatchContext {
|
pub struct WatchContext {
|
||||||
#[allow(dead_code)]
|
|
||||||
watcher: notify::RecommendedWatcher,
|
watcher: notify::RecommendedWatcher,
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
|
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn watch_offline_app() -> FlowyResult<(WatchContext, UnboundedReceiver<WatchDiskEvent>)> {
|
pub fn watch_offline_app() -> FlowyResult<(WatchContext, UnboundedReceiver<WatchDiskEvent>)> {
|
||||||
use notify::{Event, Watcher};
|
use notify::{Event, Watcher};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user