From d3d929b68e497d1dae5e63b0fe87d861fa679884 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Fri, 16 Aug 2024 11:58:48 +0800 Subject: [PATCH] fix: unable to insert todo list via slash menu (#5980) * fix: unable to insert todo list via slash menu * fix: unable to insert divider via slash menu * chore: update editor version * chore: update translations * chore: decrease sentry sample rate to 0.1 * fix: integration test --- .../document/document_with_database_test.dart | 1 + .../document/presentation/editor_page.dart | 4 + .../slash_menu/slash_menu_items.dart | 105 +++++++++++++++++- .../lib/startup/tasks/sentry.dart | 4 +- frontend/appflowy_flutter/pubspec.lock | 36 +----- frontend/appflowy_flutter/pubspec.yaml | 5 +- frontend/resources/translations/en.json | 4 +- 7 files changed, 116 insertions(+), 43 deletions(-) diff --git a/frontend/appflowy_flutter/integration_test/desktop/document/document_with_database_test.dart b/frontend/appflowy_flutter/integration_test/desktop/document/document_with_database_test.dart index 0ee7610b93..eb07a2e7a8 100644 --- a/frontend/appflowy_flutter/integration_test/desktop/document/document_with_database_test.dart +++ b/frontend/appflowy_flutter/integration_test/desktop/document/document_with_database_test.dart @@ -176,6 +176,7 @@ Future createInlineDatabase( await tester.editor.showSlashMenu(); await tester.editor.tapSlashMenuItemWithName( layout.slashMenuName, + offset: 100, ); await tester.pumpAndSettle(); diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart index 87eec5b47c..d4e767bb43 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_page.dart @@ -410,6 +410,7 @@ class _AppFlowyEditorPageState extends State { } List _customSlashMenuItems() { + return [ aiWriterSlashMenuItem, textSlashMenuItem, @@ -419,7 +420,10 @@ class _AppFlowyEditorPageState extends State { imageSlashMenuItem, bulletedListSlashMenuItem, numberedListSlashMenuItem, + todoListSlashMenuItem, + dividerSlashMenuItem, quoteSlashMenuItem, + tableSlashMenuItem, referencedDocSlashMenuItem, gridSlashMenuItem(documentBloc), referencedGridSlashMenuItem, diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/slash_menu/slash_menu_items.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/slash_menu/slash_menu_items.dart index 8b92d51ab2..0c3868a50a 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/slash_menu/slash_menu_items.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/slash_menu/slash_menu_items.dart @@ -125,6 +125,21 @@ final numberedListSlashMenuItem = SelectionMenuItem( }, ); +// todo list menu item +final todoListSlashMenuItem = SelectionMenuItem( + getName: () => LocaleKeys.document_slashMenu_name_todoList.tr(), + nameBuilder: _slashMenuItemNameBuilder, + icon: (editorState, isSelected, style) => SelectableSvgWidget( + data: FlowySvgs.slash_menu_icon_checkbox_s, + isSelected: isSelected, + style: style, + ), + keywords: ['checkbox', 'todo', 'list', 'to-do', 'task'], + handler: (editorState, _, __) { + insertCheckboxAfterSelection(editorState); + }, +); + // quote menu item final quoteSlashMenuItem = SelectionMenuItem( getName: () => LocaleKeys.document_slashMenu_name_quote.tr(), @@ -134,12 +149,42 @@ final quoteSlashMenuItem = SelectionMenuItem( isSelected: isSelected, style: style, ), - keywords: ['quote', 'refer'], + keywords: ['quote', 'refer', 'blockquote', 'citation'], handler: (editorState, _, __) { insertQuoteAfterSelection(editorState); }, ); +// divider menu item +final dividerSlashMenuItem = SelectionMenuItem( + getName: () => LocaleKeys.document_slashMenu_name_divider.tr(), + nameBuilder: _slashMenuItemNameBuilder, + icon: (editorState, isSelected, style) => SelectableSvgWidget( + data: FlowySvgs.slash_menu_icon_divider_s, + isSelected: isSelected, + style: style, + ), + keywords: ['divider', 'separator', 'line', 'break', 'horizontal line'], + handler: (editorState, _, __) { + final selection = editorState.selection; + if (selection == null || !selection.isCollapsed) { + return; + } + final path = selection.end.path; + final node = editorState.getNodeAtPath(path); + final delta = node?.delta; + if (node == null || delta == null) { + return; + } + final insertedPath = delta.isEmpty ? path : path.next; + final transaction = editorState.transaction + ..insertNode(insertedPath, dividerNode()) + ..insertNode(insertedPath, paragraphNode()) + ..afterSelection = Selection.collapsed(Position(path: insertedPath.next)); + editorState.apply(transaction); + }, +); + // grid & board & calendar menu item SelectionMenuItem gridSlashMenuItem(DocumentBloc documentBloc) { return SelectionMenuItem( @@ -347,7 +392,7 @@ SelectionMenuItem toggleListSlashMenuItem = SelectionMenuItem.node( isSelected: isSelected, style: style, ), - keywords: ['collapsed list', 'toggle list', 'list'], + keywords: ['collapsed list', 'toggle list', 'list', 'dropdown'], nodeBuilder: (editorState, _) => toggleListBlockNode(), replace: (_, node) => node.delta?.isEmpty ?? false, ); @@ -361,7 +406,7 @@ SelectionMenuItem emojiSlashMenuItem = SelectionMenuItem( isSelected: isSelected, style: style, ), - keywords: ['emoji'], + keywords: ['emoji', 'reaction', 'emoticon'], handler: (editorState, menuService, context) { final container = Overlay.of(context); menuService.dismiss(); @@ -391,6 +436,56 @@ SelectionMenuItem aiWriterSlashMenuItem = SelectionMenuItem.node( replace: (_, node) => false, ); +// table menu item +SelectionMenuItem tableSlashMenuItem = SelectionMenuItem( + getName: () => LocaleKeys.document_slashMenu_name_table.tr(), + nameBuilder: _slashMenuItemNameBuilder, + icon: (editorState, isSelected, style) => SelectableSvgWidget( + data: FlowySvgs.slash_menu_icon_simple_table_s, + isSelected: isSelected, + style: style, + ), + keywords: ['table', 'rows', 'columns', 'data'], + handler: (editorState, _, __) async { + final selection = editorState.selection; + if (selection == null || !selection.isCollapsed) { + return; + } + + final currentNode = editorState.getNodeAtPath(selection.end.path); + if (currentNode == null) { + return; + } + + final tableNode = TableNode.fromList([ + ['', ''], + ['', ''], + ]); + + final transaction = editorState.transaction; + final delta = currentNode.delta; + if (delta != null && delta.isEmpty) { + transaction + ..insertNode(selection.end.path, tableNode.node) + ..deleteNode(currentNode); + transaction.afterSelection = Selection.collapsed( + Position( + path: selection.end.path + [0, 0], + ), + ); + } else { + transaction.insertNode(selection.end.path.next, tableNode.node); + transaction.afterSelection = Selection.collapsed( + Position( + path: selection.end.path.next + [0, 0], + ), + ); + } + + await editorState.apply(transaction); + }, +); + // date or reminder menu item SelectionMenuItem dateOrReminderSlashMenuItem = SelectionMenuItem( getName: () => LocaleKeys.document_slashMenu_name_dateOrReminder.tr(), @@ -400,7 +495,7 @@ SelectionMenuItem dateOrReminderSlashMenuItem = SelectionMenuItem( isSelected: isSelected, style: style, ), - keywords: ['insert date', 'date', 'time', 'reminder'], + keywords: ['insert date', 'date', 'time', 'reminder', 'schedule'], handler: (editorState, menuService, context) => insertDateReference(editorState), ); @@ -439,7 +534,7 @@ SelectionMenuItem fileSlashMenuItem = SelectionMenuItem( isSelected: isSelected, style: style, ), - keywords: ['file upload', 'pdf', 'zip', 'archive', 'upload'], + keywords: ['file upload', 'pdf', 'zip', 'archive', 'upload', 'attachment'], handler: (editorState, _, __) async => editorState.insertEmptyFileBlock(), ); diff --git a/frontend/appflowy_flutter/lib/startup/tasks/sentry.dart b/frontend/appflowy_flutter/lib/startup/tasks/sentry.dart index 13a280fdf1..9076569a9c 100644 --- a/frontend/appflowy_flutter/lib/startup/tasks/sentry.dart +++ b/frontend/appflowy_flutter/lib/startup/tasks/sentry.dart @@ -20,8 +20,8 @@ class InitSentryTask extends LaunchTask { await SentryFlutter.init( (options) { options.dsn = dsn; - options.tracesSampleRate = 1.0; - options.profilesSampleRate = 1.0; + options.tracesSampleRate = 0.1; + options.profilesSampleRate = 0.1; }, ); } diff --git a/frontend/appflowy_flutter/pubspec.lock b/frontend/appflowy_flutter/pubspec.lock index c39019f2ff..267fb80c21 100644 --- a/frontend/appflowy_flutter/pubspec.lock +++ b/frontend/appflowy_flutter/pubspec.lock @@ -53,11 +53,11 @@ packages: dependency: "direct main" description: path: "." - ref: "9d3e854" - resolved-ref: "9d3e854f11fd9d732535ce5f5b1c8f41517479a1" + ref: "8e17d14" + resolved-ref: "8e17d1447eea0b57ff92e31dbe88796ce759fb37" url: "https://github.com/AppFlowy-IO/appflowy-editor.git" source: git - version: "3.1.0" + version: "3.2.0" appflowy_editor_plugins: dependency: "direct main" description: @@ -808,7 +808,7 @@ packages: source: hosted version: "0.6.5" flutter_svg: - dependency: "direct main" + dependency: transitive description: name: flutter_svg sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c @@ -1083,14 +1083,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.19.0" - intl_utils: - dependency: transitive - description: - name: intl_utils - sha256: c2b1f5c72c25512cbeef5ab015c008fc50fe7e04813ba5541c25272300484bf4 - url: "https://pub.dev" - source: hosted - version: "2.8.7" io: dependency: transitive description: @@ -1116,7 +1108,7 @@ packages: source: hosted version: "0.7.0" isolates: - dependency: "direct main" + dependency: transitive description: name: isolates sha256: ce89e4141b27b877326d3715be2dceac7a7ba89f3229785816d2d318a75ddf28 @@ -1236,7 +1228,7 @@ packages: source: hosted version: "0.1.5" logger: - dependency: "direct main" + dependency: transitive description: name: logger sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32" @@ -1475,14 +1467,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.11.1" - pdf_widget_wrapper: - dependency: transitive - description: - name: pdf_widget_wrapper - sha256: c930860d987213a3d58c7ec3b7ecf8085c3897f773e8dc23da9cae60a5d6d0f5 - url: "https://pub.dev" - source: hosted - version: "1.0.4" percent_indicator: dependency: "direct main" description: @@ -1603,14 +1587,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" - printing: - dependency: transitive - description: - name: printing - sha256: cc4b256a5a89d5345488e3318897b595867f5181b8c5ed6fc63bfa5f2044aec3 - url: "https://pub.dev" - source: hosted - version: "5.13.1" process: dependency: transitive description: diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml index a93fa0c511..d6a7f61930 100644 --- a/frontend/appflowy_flutter/pubspec.yaml +++ b/frontend/appflowy_flutter/pubspec.yaml @@ -77,7 +77,6 @@ dependencies: linked_scroll_controller: ^0.2.0 hotkey_manager: ^0.1.7 fixnum: ^1.1.0 - flutter_svg: ^2.0.7 protobuf: ^3.1.0 collection: ^1.17.1 bloc: ^8.1.2 @@ -133,10 +132,8 @@ dependencies: auto_size_text_field: ^2.2.3 reorderable_tabbar: ^1.0.6 shimmer: ^3.0.0 - isolates: ^3.0.3+8 markdown_widget: ^2.3.2+6 markdown: - logger: ^2.4.0 # Desktop Drop uses Cross File (XFile) data type desktop_drop: ^0.4.4 @@ -193,7 +190,7 @@ dependency_overrides: appflowy_editor: git: url: https://github.com/AppFlowy-IO/appflowy-editor.git - ref: "9d3e854" + ref: "8e17d14" appflowy_editor_plugins: git: diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index 8e5bbb8dc6..b5c76c4f50 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -1327,7 +1327,7 @@ "addOption": "Add option", "editProperty": "Edit property", "newProperty": "New property", - "openRowDocument": "Open document", + "openRowDocument": "Open as a page", "deleteFieldPromptMessage": "Are you sure? This property will be deleted", "clearFieldPromptMessage": "Are you sure? All cells in this column will be emptied", "newColumn": "New Column", @@ -1471,7 +1471,7 @@ "image": "Image", "bulletedList": "Bulleted List", "numberedList": "Numbered List", - "checkbox": "Checkbox", + "todoList": "To-do List", "doc": "Doc", "linkedDoc": "Link to page", "grid": "Grid",