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
This commit is contained in:
Lucas 2024-12-09 16:19:37 +08:00 committed by Lucas.Xu
parent 3fdd19f7a2
commit 8726df703e
17 changed files with 174 additions and 25 deletions

View file

@ -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);
});
});
}

View file

@ -117,6 +117,22 @@ Future<bool> 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<bool> 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,
);
}
}

View file

@ -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';

View file

@ -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';
}
}

View file

@ -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';
}
}

View file

@ -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';

View file

@ -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';

View file

@ -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<InlineActionsResult> 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,
),
),
),

View file

@ -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<InlineActionsHandler> createState() => _InlineActionsHandlerState();
@ -288,12 +290,17 @@ class _InlineActionsHandlerState extends State<InlineActionsHandler> {
/// 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;
}

View file

@ -197,8 +197,23 @@ class ShareBloc extends Bloc<ShareEvent, ShareState> {
(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;

View file

@ -20,6 +20,8 @@ String customDocumentToMarkdown(Document document) {
const ToggleListNodeParser(),
const CustomImageNodeParser(),
const SimpleTableNodeParser(),
const LinkPreviewNodeParser(),
const FileBlockNodeParser(),
],
);
}

View file

@ -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<SidebarPlanEvent, SidebarPlanState> {
@ -113,7 +114,8 @@ class SidebarPlanBloc extends Bloc<SidebarPlanEvent, SidebarPlanState> {
} 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<SidebarPlanEvent, SidebarPlanState> {
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;
}

View file

@ -329,14 +329,15 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
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(

View file

@ -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"

View file

@ -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:

View file

@ -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',
);
});
});
}