mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 14:47:13 -04:00
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:
parent
3fdd19f7a2
commit
8726df703e
17 changed files with 174 additions and 25 deletions
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -20,6 +20,8 @@ String customDocumentToMarkdown(Document document) {
|
|||
const ToggleListNodeParser(),
|
||||
const CustomImageNodeParser(),
|
||||
const SimpleTableNodeParser(),
|
||||
const LinkPreviewNodeParser(),
|
||||
const FileBlockNodeParser(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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',
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue