From 8726df703ec4e733be462b1c9d98253c143ac10f Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 9 Dec 2024 16:19:37 +0800 Subject: [PATCH] fix: hotfix issues for v0.7.7 (#6948) * fix: include link preview block and file block in exported markdown * test: include link preview block and file block in exported markdown * chore: remove unused logs * chore: update editor version * fix: "+" menu should be close after pressing space * test: cancel inline page reference menu by space * chore: update editor version * chore: remove unused logs --- .../document_inline_sub_page_test.dart | 21 ++++++++++- .../base/page_reference_commands.dart | 30 +++++++++++++++ .../parsers/document_markdown_parsers.dart | 3 ++ .../parsers/file_block_node_parser.dart | 19 ++++++++++ .../parsers/link_preview_node_parser.dart | 18 +++++++++ .../parsers/markdown_parsers.dart | 6 +-- ...ser.dart => simple_table_node_parser.dart} | 0 .../presentation/editor_plugins/plugins.dart | 1 + .../inline_actions/inline_actions_menu.dart | 3 ++ .../widgets/inline_actions_handler.dart | 13 +++++-- .../lib/plugins/shared/share/share_bloc.dart | 19 +++++++++- .../lib/shared/markdown_to_document.dart | 2 + .../sidebar/billing/sidebar_plan_bloc.dart | 12 +++--- .../application/sidebar/space/space_bloc.dart | 9 +++-- frontend/appflowy_flutter/pubspec.lock | 4 +- frontend/appflowy_flutter/pubspec.yaml | 2 +- .../markdown/markdown_parser_test.dart | 37 +++++++++++++++++++ 17 files changed, 174 insertions(+), 25 deletions(-) create mode 100644 frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/file_block_node_parser.dart create mode 100644 frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/link_preview_node_parser.dart rename frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/{simple_table_parser.dart => simple_table_node_parser.dart} (100%) create mode 100644 frontend/appflowy_flutter/test/unit_test/markdown/markdown_parser_test.dart diff --git a/frontend/appflowy_flutter/integration_test/desktop/document/document_inline_sub_page_test.dart b/frontend/appflowy_flutter/integration_test/desktop/document/document_inline_sub_page_test.dart index ef9ef73b3c..30e115774a 100644 --- a/frontend/appflowy_flutter/integration_test/desktop/document/document_inline_sub_page_test.dart +++ b/frontend/appflowy_flutter/integration_test/desktop/document/document_inline_sub_page_test.dart @@ -2,12 +2,12 @@ import 'dart:io'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart'; +import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart'; import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/services.dart'; - -import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; @@ -330,6 +330,23 @@ void main() { expect(find.text("$_createdPageName (copy)"), findsNWidgets(2)); expect(find.text("$_createdPageName (copy) (copy)"), findsOneWidget); }); + + testWidgets('Cancel inline page reference menu by space', (tester) async { + await tester.initializeAppFlowy(); + await tester.tapAnonymousSignInButton(); + await tester.createOpenRenameDocumentUnderParent(name: _firstDocName); + + await tester.editor.tapLineOfEditorAt(0); + await tester.editor.showPlusMenu(); + + // Cancel by space + await tester.simulateKeyEvent( + LogicalKeyboardKey.space, + ); + await tester.pumpAndSettle(); + + expect(find.byType(InlineActionsMenu), findsNothing); + }); }); } diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/page_reference_commands.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/page_reference_commands.dart index e42bb3a2bf..079a062837 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/page_reference_commands.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/page_reference_commands.dart @@ -117,6 +117,22 @@ Future inlinePageReferenceCommandHandler( initialResults: initialResults, style: style, startCharAmount: previousChar != null ? 2 : 1, + cancelBySpaceHandler: () { + if (character == _plusChar) { + final currentSelection = editorState.selection; + if (currentSelection == null) { + return false; + } + // check if the space is after the character + if (currentSelection.isCollapsed && + currentSelection.start.offset == + selection.start.offset + character.length) { + _cancelInlinePageReferenceMenu(editorState); + return true; + } + } + return false; + }, ); selectionMenuService?.show(); @@ -124,3 +140,17 @@ Future inlinePageReferenceCommandHandler( return true; } + +void _cancelInlinePageReferenceMenu(EditorState editorState) { + selectionMenuService?.dismiss(); + selectionMenuService = null; + + // re-focus the selection + final selection = editorState.selection; + if (selection != null) { + editorState.updateSelectionWithReason( + selection, + reason: SelectionUpdateReason.uiEvent, + ); + } +} diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/document_markdown_parsers.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/document_markdown_parsers.dart index 0b694f396e..3f2895d57e 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/document_markdown_parsers.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/document_markdown_parsers.dart @@ -1,4 +1,7 @@ export 'callout_node_parser.dart'; export 'custom_image_node_parser.dart'; +export 'file_block_node_parser.dart'; +export 'link_preview_node_parser.dart'; export 'math_equation_node_parser.dart'; +export 'simple_table_node_parser.dart'; export 'toggle_list_node_parser.dart'; diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/file_block_node_parser.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/file_block_node_parser.dart new file mode 100644 index 0000000000..e57ededcec --- /dev/null +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/file_block_node_parser.dart @@ -0,0 +1,19 @@ +import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; +import 'package:appflowy_editor/appflowy_editor.dart'; + +class FileBlockNodeParser extends NodeParser { + const FileBlockNodeParser(); + + @override + String get id => FileBlockKeys.type; + + @override + String transform(Node node, DocumentMarkdownEncoder? encoder) { + final name = node.attributes[FileBlockKeys.name]; + final url = node.attributes[FileBlockKeys.url]; + if (name == null || url == null) { + return ''; + } + return '[$name]($url)\n'; + } +} diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/link_preview_node_parser.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/link_preview_node_parser.dart new file mode 100644 index 0000000000..c7ce69d221 --- /dev/null +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/link_preview_node_parser.dart @@ -0,0 +1,18 @@ +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart'; + +class LinkPreviewNodeParser extends NodeParser { + const LinkPreviewNodeParser(); + + @override + String get id => LinkPreviewBlockKeys.type; + + @override + String transform(Node node, DocumentMarkdownEncoder? encoder) { + final href = node.attributes[LinkPreviewBlockKeys.url]; + if (href == null) { + return ''; + } + return '[$href]($href)\n'; + } +} diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/markdown_parsers.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/markdown_parsers.dart index 568baeaac0..4ad7734643 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/markdown_parsers.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/markdown_parsers.dart @@ -1,6 +1,2 @@ -export 'callout_node_parser.dart'; -export 'custom_image_node_parser.dart'; export 'markdown_code_parser.dart'; -export 'math_equation_node_parser.dart'; -export 'toggle_list_node_parser.dart'; -export 'simple_table_parser.dart'; +export 'markdown_simple_table_parser.dart'; diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/simple_table_parser.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/simple_table_node_parser.dart similarity index 100% rename from frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/simple_table_parser.dart rename to frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/parsers/simple_table_node_parser.dart diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/plugins.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/plugins.dart index da28f7f720..4d1fd95558 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/plugins.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/plugins.dart @@ -57,6 +57,7 @@ export 'openai/widgets/ai_writer_block_component.dart'; export 'openai/widgets/ask_ai_block_component.dart'; export 'openai/widgets/ask_ai_toolbar_item.dart'; export 'outline/outline_block_component.dart'; +export 'parsers/document_markdown_parsers.dart'; export 'parsers/markdown_parsers.dart'; export 'parsers/markdown_simple_table_parser.dart'; export 'quote/quote_block_shortcuts.dart'; diff --git a/frontend/appflowy_flutter/lib/plugins/inline_actions/inline_actions_menu.dart b/frontend/appflowy_flutter/lib/plugins/inline_actions/inline_actions_menu.dart index e31d7c2ef0..dadc4ebf6f 100644 --- a/frontend/appflowy_flutter/lib/plugins/inline_actions/inline_actions_menu.dart +++ b/frontend/appflowy_flutter/lib/plugins/inline_actions/inline_actions_menu.dart @@ -19,12 +19,14 @@ class InlineActionsMenu extends InlineActionsMenuService { required this.initialResults, required this.style, this.startCharAmount = 1, + this.cancelBySpaceHandler, }); final BuildContext context; final EditorState editorState; final InlineActionsService service; final List initialResults; + final bool Function()? cancelBySpaceHandler; @override final InlineActionsMenuStyle style; @@ -137,6 +139,7 @@ class InlineActionsMenu extends InlineActionsMenuService { onSelectionUpdate: _onSelectionUpdate, style: style, startCharAmount: startCharAmount, + cancelBySpaceHandler: cancelBySpaceHandler, ), ), ), diff --git a/frontend/appflowy_flutter/lib/plugins/inline_actions/widgets/inline_actions_handler.dart b/frontend/appflowy_flutter/lib/plugins/inline_actions/widgets/inline_actions_handler.dart index edf34a3dc1..be9a6c2f5f 100644 --- a/frontend/appflowy_flutter/lib/plugins/inline_actions/widgets/inline_actions_handler.dart +++ b/frontend/appflowy_flutter/lib/plugins/inline_actions/widgets/inline_actions_handler.dart @@ -62,6 +62,7 @@ class InlineActionsHandler extends StatefulWidget { required this.onSelectionUpdate, required this.style, this.startCharAmount = 1, + this.cancelBySpaceHandler, }); final InlineActionsService service; @@ -72,6 +73,7 @@ class InlineActionsHandler extends StatefulWidget { final VoidCallback onSelectionUpdate; final InlineActionsMenuStyle style; final int startCharAmount; + final bool Function()? cancelBySpaceHandler; @override State createState() => _InlineActionsHandlerState(); @@ -288,12 +290,17 @@ class _InlineActionsHandlerState extends State { /// that the selection change occurred from the handler. widget.onSelectionUpdate(); + if (event.logicalKey == LogicalKeyboardKey.space) { + final cancelBySpaceHandler = widget.cancelBySpaceHandler; + if (cancelBySpaceHandler != null && cancelBySpaceHandler()) { + return KeyEventResult.handled; + } + } + // Interpolation to avoid having a getter for private variable _insertCharacter(event.character!); return KeyEventResult.handled; - } - - if (moveKeys.contains(event.logicalKey)) { + } else if (moveKeys.contains(event.logicalKey)) { _moveSelection(event.logicalKey); return KeyEventResult.handled; } diff --git a/frontend/appflowy_flutter/lib/plugins/shared/share/share_bloc.dart b/frontend/appflowy_flutter/lib/plugins/shared/share/share_bloc.dart index c533f67ed8..c42bbda5a0 100644 --- a/frontend/appflowy_flutter/lib/plugins/shared/share/share_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/shared/share/share_bloc.dart @@ -197,8 +197,23 @@ class ShareBloc extends Bloc { (p) => false, ); - Log.info( - 'get publish info: $publishInfo for view: ${view.name}(${view.id})', + // skip the "Record not found" error, it's because the view is not published yet + publishInfo.fold( + (s) { + Log.info( + 'get publish info success: $publishInfo for view: ${view.name}(${view.id})', + ); + }, + (f) { + if (![ + ErrorCode.RecordNotFound, + ErrorCode.LocalVersionNotSupport, + ].contains(f.code)) { + Log.info( + 'get publish info failed: $f for view: ${view.name}(${view.id})', + ); + } + }, ); String workspaceId = state.workspaceId; diff --git a/frontend/appflowy_flutter/lib/shared/markdown_to_document.dart b/frontend/appflowy_flutter/lib/shared/markdown_to_document.dart index 328c66eca9..b3e2034602 100644 --- a/frontend/appflowy_flutter/lib/shared/markdown_to_document.dart +++ b/frontend/appflowy_flutter/lib/shared/markdown_to_document.dart @@ -20,6 +20,8 @@ String customDocumentToMarkdown(Document document) { const ToggleListNodeParser(), const CustomImageNodeParser(), const SimpleTableNodeParser(), + const LinkPreviewNodeParser(), + const FileBlockNodeParser(), ], ); } diff --git a/frontend/appflowy_flutter/lib/workspace/application/sidebar/billing/sidebar_plan_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/sidebar/billing/sidebar_plan_bloc.dart index 7af2a547dd..1737494530 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/sidebar/billing/sidebar_plan_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/sidebar/billing/sidebar_plan_bloc.dart @@ -12,6 +12,7 @@ import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/workspace.pb.dart'; import 'package:bloc/bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; + part 'sidebar_plan_bloc.freezed.dart'; class SidebarPlanBloc extends Bloc { @@ -113,7 +114,8 @@ class SidebarPlanBloc extends Bloc { } else if (error.code == ErrorCode.SingleUploadLimitExceeded) { emit( state.copyWith( - tierIndicator: const SidebarToastTierIndicator.singleFileLimitHit(), + tierIndicator: + const SidebarToastTierIndicator.singleFileLimitHit(), ), ); } else { @@ -184,13 +186,10 @@ class SidebarPlanBloc extends Bloc { if (state.workspaceId != null) { final payload = UserWorkspaceIdPB(workspaceId: state.workspaceId!); UserEventGetWorkspaceUsage(payload).send().then((result) { - result.fold( + result.onSuccess( (usage) { add(SidebarPlanEvent.updateWorkspaceUsage(usage)); }, - (error) { - Log.error("Failed to get workspace usage, error: $error"); - }, ); }); } @@ -231,7 +230,8 @@ class SidebarPlanState with _$SidebarPlanState { @freezed class SidebarToastTierIndicator with _$SidebarToastTierIndicator { const factory SidebarToastTierIndicator.storageLimitHit() = _StorageLimitHit; - const factory SidebarToastTierIndicator.singleFileLimitHit() = _SingleFileLimitHit; + const factory SidebarToastTierIndicator.singleFileLimitHit() = + _SingleFileLimitHit; const factory SidebarToastTierIndicator.aiMaxiLimitHit() = _aiMaxLimitHit; const factory SidebarToastTierIndicator.loading() = _Loading; } diff --git a/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart b/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart index 46d4943ddf..e1a825d631 100644 --- a/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart +++ b/frontend/appflowy_flutter/lib/workspace/application/sidebar/space/space_bloc.dart @@ -329,14 +329,15 @@ class SpaceBloc extends Bloc { final (spaces, _, _) = await _getSpaces(); final currentSpace = await _getLastOpenedSpace(spaces); + Log.info( + 'receive space update, current space: ${currentSpace?.name}(${currentSpace?.id})', + ); + for (var i = 0; i < spaces.length; i++) { Log.info( - 'did receive space update[$i]: ${spaces[i].name}(${spaces[i].id})', + 'receive space update[$i]: ${spaces[i].name}(${spaces[i].id})', ); } - Log.info( - 'did receive space update, current space: ${currentSpace?.name}(${currentSpace?.id})', - ); emit( state.copyWith( diff --git a/frontend/appflowy_flutter/pubspec.lock b/frontend/appflowy_flutter/pubspec.lock index 71bc08bf67..c8dc56a973 100644 --- a/frontend/appflowy_flutter/pubspec.lock +++ b/frontend/appflowy_flutter/pubspec.lock @@ -61,8 +61,8 @@ packages: dependency: "direct main" description: path: "." - ref: ac3b090 - resolved-ref: ac3b0906ea2e7f2e7e3c2c7852e9ec3529e07512 + ref: "157ded3" + resolved-ref: "157ded3cd321b9a54d011c0cc27e270ded35d3aa" url: "https://github.com/AppFlowy-IO/appflowy-editor.git" source: git version: "4.0.0" diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml index 29a3d57cf7..f02b420acb 100644 --- a/frontend/appflowy_flutter/pubspec.yaml +++ b/frontend/appflowy_flutter/pubspec.yaml @@ -173,7 +173,7 @@ dependency_overrides: appflowy_editor: git: url: https://github.com/AppFlowy-IO/appflowy-editor.git - ref: "ac3b090" + ref: "157ded3" appflowy_editor_plugins: git: diff --git a/frontend/appflowy_flutter/test/unit_test/markdown/markdown_parser_test.dart b/frontend/appflowy_flutter/test/unit_test/markdown/markdown_parser_test.dart new file mode 100644 index 0000000000..70775612e2 --- /dev/null +++ b/frontend/appflowy_flutter/test/unit_test/markdown/markdown_parser_test.dart @@ -0,0 +1,37 @@ +import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; +import 'package:appflowy/shared/markdown_to_document.dart'; +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('export markdown to document', () { + test('file block', () async { + final document = Document.blank() + ..insert( + [0], + [ + fileNode( + name: 'file.txt', + url: 'https://file.com', + ), + ], + ); + final markdown = customDocumentToMarkdown(document); + expect(markdown, '[file.txt](https://file.com)\n'); + }); + + test('link preview', () { + final document = Document.blank() + ..insert( + [0], + [linkPreviewNode(url: 'https://www.link_preview.com')], + ); + final markdown = customDocumentToMarkdown(document); + expect( + markdown, + '[https://www.link_preview.com](https://www.link_preview.com)\n', + ); + }); + }); +}