From 3731a25d9acd8111cc2d4bfe67926d8245f2a19c Mon Sep 17 00:00:00 2001 From: squidrye Date: Sat, 25 Mar 2023 15:10:38 +0530 Subject: [PATCH 01/13] feat: insert below and replace in smart-edit highlights text --- .../widgets/smart_edit_node_widget.dart | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart index 151ccc60d2147..72699c1c453dc 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart @@ -298,7 +298,26 @@ class _SmartEditInputState extends State<_SmartEditInput> { selection, texts, ); - return widget.editorState.apply(transaction); + widget.editorState.apply(transaction).then( + (_) { + int endOffset = texts.last.length; + if (texts.length == 1) { + endOffset += selection.start.offset; + } + widget.editorState.updateCursorSelection( + Selection( + start: Position( + path: selection.start.path, + offset: selection.start.offset, + ), + end: Position( + path: [selection.start.path.first + texts.length - 1], + offset: endOffset, + ), + ), + ); + }, + ); } Future _onInsertBelow() async { @@ -317,7 +336,18 @@ class _SmartEditInputState extends State<_SmartEditInput> { ), ), ); - return widget.editorState.apply(transaction); + widget.editorState.apply(transaction).then( + (_) { + widget.editorState.updateCursorSelection( + Selection( + start: Position(path: selection.end.path.next, offset: 0), + end: Position( + path: [selection.end.path.next.first + texts.length], + ), + ), + ); + }, + ); } Future _onExit() async { From e4afc6473a6fee6701719b0100c00ccf24c6f6a4 Mon Sep 17 00:00:00 2001 From: squidrye Date: Tue, 28 Mar 2023 01:20:25 +0530 Subject: [PATCH 02/13] test: added integration tests to validate insert below and replace in smart-edit highlights text --- .../open_ai_smart_menu_test.dart | 129 ++++++++++++++++++ .../util/mock/mock_openai_repository.dart | 89 ++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart create mode 100644 frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart diff --git a/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart b/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart new file mode 100644 index 0000000000000..bac50f3419aac --- /dev/null +++ b/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart @@ -0,0 +1,129 @@ +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'util/base.dart'; +import 'util/mock/mock_file_picker.dart'; +import 'util/mock/mock_openai_repository.dart'; +import 'util/util.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('trying to reach setup dummy keys for open ai', () { + const location = 'test_flowy'; + setUp(() async { + await TestFolder.cleanTestLocation(location); + await TestFolder.setTestLocation(location); + }); + + tearDown(() async { + await TestFolder.cleanTestLocation(location); + }); + tearDownAll(() async { + await TestFolder.cleanTestLocation(null); + }); + + testWidgets('testing selection on open-ai smart menu replace', (tester) async { + + final appFlowyEditor = await setUpOpenAITesting(tester); + final editorState = appFlowyEditor.editorState; + const dummyText = 'Some text to test open ai'; + editorState.document.insert([0], [TextNode(delta: Delta()..insert(dummyText))]); + await tester.pumpAndSettle(); + + editorState.service.selectionService.updateSelection(Selection( + start: Position(path: [0], offset: 0), + end: Position(path: [0], offset: dummyText.length), + )); + await tester.pumpAndSettle(const Duration(milliseconds: 500)); + await tester.pumpAndSettle(); + expect(find.byType(ToolbarWidget), findsAtLeastNWidgets(1)); + + await tester.tap(find.byTooltip('AI Assistants')); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Summarize')); + await tester.pumpAndSettle(); + + await tester.tap(find.byType(FlowyRichTextButton, skipOffstage: false).first); + await tester.pumpAndSettle(); + + expect( + editorState.service.selectionService.currentSelection.value, + Selection( + start: Position(path: [0], offset: 0), + end: Position(path: [0], offset: 338), + ), + ); + }); + testWidgets('testing selection on open-ai smart menu insert', (tester) async { + + final appFlowyEditor = await setUpOpenAITesting(tester); + final editorState = appFlowyEditor.editorState; + const dummyText = 'Some text to test open ai'; + editorState.document.insert([0], [TextNode(delta: Delta()..insert(dummyText))]); + await tester.pumpAndSettle(); + + editorState.service.selectionService.updateSelection(Selection( + start: Position(path: [0], offset: 0), + end: Position(path: [0], offset: dummyText.length), + )); + await tester.pumpAndSettle(const Duration(milliseconds: 500)); + await tester.pumpAndSettle(); + expect(find.byType(ToolbarWidget), findsAtLeastNWidgets(1)); + + await tester.tap(find.byTooltip('AI Assistants')); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Summarize')); + await tester.pumpAndSettle(); + + await tester.tap(find.byType(FlowyRichTextButton, skipOffstage: false).at(1)); + await tester.pumpAndSettle(); + + expect( + editorState.service.selectionService.currentSelection.value, + Selection( + start: Position(path: [1], offset: 0), + end: Position(path: [2], offset: 0), + ), + ); + }); + }); +} + +Future setUpOpenAITesting(WidgetTester tester)async{ + const folderName = 'test_flowy'; + const dummyKey = 'dummyKey'; + await TestFolder.cleanTestLocation(folderName); + await TestFolder.setTestLocation(folderName); + + await tester.initializeAppFlowy(); + + await mockGetDirectoryPath(folderName); + + await tester.tapOpenFolderButton(); + + await tester.wait(1000); + await tester.expectToSeeWelcomePage(); + + await mockOpenAIRepository(); + + await tester.openSettings(); + await tester.openSettingsPage(SettingsPage.user); + await tester.enterDummyApiKey(dummyKey); + await tester.pumpAndSettle(); + + await simulateKeyDownEvent(LogicalKeyboardKey.escape); + await tester.pumpAndSettle(); + + + final Finder editor = find.byType(AppFlowyEditor); + await tester.tap(editor); + await tester.pumpAndSettle(); + return (tester.state(editor).widget as AppFlowyEditor); +} \ No newline at end of file diff --git a/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart b/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart new file mode 100644 index 0000000000000..4b21495800b95 --- /dev/null +++ b/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart @@ -0,0 +1,89 @@ +import 'package:appflowy/plugins/document/presentation/plugins/openai/service/openai_client.dart'; +import 'package:mocktail/mocktail.dart'; +import 'dart:convert'; +import 'package:appflowy/plugins/document/presentation/plugins/openai/service/text_completion.dart'; +import 'package:appflowy/plugins/document/presentation/plugins/openai/service/error.dart'; + +import 'package:http/http.dart' as http; +import 'package:appflowy/startup/startup.dart'; +import 'dart:async'; + +class MyMockClient extends Mock implements http.Client { + @override + Future send(http.BaseRequest request) async { + final requestType = request.method; + final requestUri = request.url; + + if (requestType == 'POST' && requestUri == OpenAIRequestType.textCompletion.uri) { + final responseHeaders = {'content-type': 'text/event-stream'}; + final responseBody = Stream.fromIterable([ + utf8.encode( + '{ "choices": [{"text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec", "index": 0, "logprobs": null, "finish_reason": null}]}'), + utf8.encode('\n'), + utf8.encode('[DONE]'), + ]); + + // Return a mocked response with the expected data + return http.StreamedResponse(responseBody, 200, headers: responseHeaders); + } + + // Return an error response for any other request + return http.StreamedResponse(const Stream.empty(), 404); + } +} + +class MockOpenAIRepository extends HttpOpenAIRepository { + MockOpenAIRepository() : super(apiKey: 'dummyKey', client: MyMockClient()); + + @override + Future getStreamedCompletions({ + required String prompt, + required Future Function() onStart, + required Future Function(TextCompletionResponse response) onProcess, + required Future Function() onEnd, + required void Function(OpenAIError error) onError, + String? suffix, + int maxTokens = 2048, + double temperature = 0.3, + bool useAction = false, + }) async { + + final request = http.Request('POST', OpenAIRequestType.textCompletion.uri); + final response = await client.send(request); + + var previousSyntax = ''; + if (response.statusCode == 200) { + await for (final chunk in response.stream.transform(const Utf8Decoder()).transform(const LineSplitter())) { + await onStart(); + final data = chunk.trim().split('data: '); + if (data[0] != '[DONE]') { + final response = TextCompletionResponse.fromJson( + json.decode(data[0]), + ); + if (response.choices.isNotEmpty) { + final text = response.choices.first.text; + if (text == previousSyntax && text == '\n') { + continue; + } + await onProcess(response); + previousSyntax = response.choices.first.text; + } + } else { + await onEnd(); + } + } + } + return; + } + +} + +Future mockOpenAIRepository() async { + await getIt.unregister(); + getIt.registerFactoryAsync( + () => Future.value( + MockOpenAIRepository(), + ), + ); + return; +} From 994b2ca37146feba13e002d8b9fcf83446aa713a Mon Sep 17 00:00:00 2001 From: squidrye Date: Tue, 28 Mar 2023 01:21:40 +0530 Subject: [PATCH 03/13] refactor: using get_it to inject OpenAiRepository to inject mock repo in test --- .../integration_test/util/settings.dart | 10 +++++++++ .../widgets/smart_edit_node_widget.dart | 7 +++---- .../lib/startup/deps_resolver.dart | 21 ++++++++++++++++++- .../settings/widgets/settings_user_view.dart | 11 +++++----- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/frontend/appflowy_flutter/integration_test/util/settings.dart b/frontend/appflowy_flutter/integration_test/util/settings.dart index 4b01c2d79123c..c1b761ee5b2b7 100644 --- a/frontend/appflowy_flutter/integration_test/util/settings.dart +++ b/frontend/appflowy_flutter/integration_test/util/settings.dart @@ -81,4 +81,14 @@ extension AppFlowySettings on WidgetTester { await testTextInput.receiveAction(TextInputAction.done); await pumpAndSettle(); } + /// Enter dummy api key + Future enterDummyApiKey(String key) async { + final uni = find.byType(OpenaiKeyInput); + expect(uni, findsOneWidget); + await tap(uni); + await enterText(uni, key); + await wait(300); // + await testTextInput.receiveAction(TextInputAction.done); + await pumpAndSettle(); + } } diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart index 72699c1c453dc..f92f73cbbedfd 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart @@ -12,6 +12,7 @@ import 'package:flowy_infra_ui/style_widget/decoration.dart'; import 'package:flutter/material.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:get_it/get_it.dart'; import 'package:http/http.dart' as http; const String kSmartEditType = 'smart_edit_input'; @@ -363,12 +364,10 @@ class _SmartEditInputState extends State<_SmartEditInput> { } Future _requestCompletions() async { + final getIt = GetIt.instance; final result = await UserBackendService.getCurrentUserProfile(); return result.fold((l) async { - final openAIRepository = HttpOpenAIRepository( - client: client, - apiKey: l.openaiKey, - ); + final openAIRepository = await getIt.getAsync() as HttpOpenAIRepository; var lines = input.split('\n\n'); if (action == SmartEditAction.summarize) { diff --git a/frontend/appflowy_flutter/lib/startup/deps_resolver.dart b/frontend/appflowy_flutter/lib/startup/deps_resolver.dart index b8e219125ecdc..55009077254ca 100644 --- a/frontend/appflowy_flutter/lib/startup/deps_resolver.dart +++ b/frontend/appflowy_flutter/lib/startup/deps_resolver.dart @@ -4,6 +4,7 @@ import 'package:appflowy/plugins/database_view/application/field/field_controlle import 'package:appflowy/plugins/database_view/application/field/field_service.dart'; import 'package:appflowy/plugins/database_view/application/setting/property_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart'; +import 'package:appflowy/plugins/document/presentation/plugins/openai/service/openai_client.dart'; import 'package:appflowy/user/application/user_listener.dart'; import 'package:appflowy/user/application/user_service.dart'; import 'package:appflowy/util/file_picker/file_picker_impl.dart'; @@ -27,6 +28,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:get_it/get_it.dart'; +import 'package:http/http.dart' as http; class DependencyResolver { static Future resolve(GetIt getIt) async { @@ -44,8 +46,25 @@ class DependencyResolver { } } -void _resolveCommonService(GetIt getIt) { +void _resolveCommonService(GetIt getIt) async { getIt.registerFactory(() => FilePicker()); + + getIt.registerFactoryAsync( + () async { + final result = await UserBackendService.getCurrentUserProfile(); + return result.fold( + (l) async { + return HttpOpenAIRepository( + client: http.Client(), + apiKey: l.openaiKey, + ); + }, + (r) async { + throw Exception('Failed to get user profile: ${r.msg}'); + }, + ); + }, + ); } void _resolveUserDeps(GetIt getIt) { diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart index 1b6f7a9a6fcc5..1a1094dcaed83 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart @@ -58,7 +58,7 @@ class SettingsUserView extends StatelessWidget { Widget _renderCurrentOpenaiKey(BuildContext context) { String openAIKey = context.read().state.userProfile.openaiKey; - return _OpenaiKeyInput(openAIKey); + return OpenaiKeyInput(openAIKey); } } @@ -86,18 +86,19 @@ class UserNameInput extends StatelessWidget { } } -class _OpenaiKeyInput extends StatefulWidget { +@visibleForTesting +class OpenaiKeyInput extends StatefulWidget { final String openAIKey; - const _OpenaiKeyInput( + const OpenaiKeyInput( this.openAIKey, { Key? key, }) : super(key: key); @override - State<_OpenaiKeyInput> createState() => _OpenaiKeyInputState(); + State createState() => OpenaiKeyInputState(); } -class _OpenaiKeyInputState extends State<_OpenaiKeyInput> { +class OpenaiKeyInputState extends State { bool visible = false; final textEditingController = TextEditingController(); final debounce = Debounce(); From eeacd872bb3e4f89d60c3775c2aebdff370cc502 Mon Sep 17 00:00:00 2001 From: Mihir <84044317+squidrye@users.noreply.github.com> Date: Wed, 29 Mar 2023 17:51:42 +0530 Subject: [PATCH 04/13] fix: delete node does not propagate non null selection --- .../appflowy_editor/lib/src/core/transform/transaction.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart b/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart index 6c369f566e7ae..a038d5364080b 100644 --- a/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart +++ b/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart @@ -68,6 +68,9 @@ class Transaction { /// Deletes the [Node] in the document. void deleteNode(Node node) { deleteNodesAtPath(node.path); + if(beforeSelection != null){ + afterSelection = beforeSelection; + } } /// Deletes the [Node]s in the document. From 69c6b2b07e114c0acbb3cd5d6da8d76b46d22aaa Mon Sep 17 00:00:00 2001 From: squidrye Date: Wed, 29 Mar 2023 17:56:50 +0530 Subject: [PATCH 05/13] refactor: suggested changes and fixed bugs causing warning in github-ci --- .../util/mock/mock_openai_repository.dart | 17 +- .../widgets/smart_edit_node_widget.dart | 149 ++++++++---------- .../lib/startup/deps_resolver.dart | 6 +- 3 files changed, 74 insertions(+), 98 deletions(-) diff --git a/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart b/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart index 4b21495800b95..18027f4fb43c6 100644 --- a/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart +++ b/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart @@ -3,9 +3,7 @@ import 'package:mocktail/mocktail.dart'; import 'dart:convert'; import 'package:appflowy/plugins/document/presentation/plugins/openai/service/text_completion.dart'; import 'package:appflowy/plugins/document/presentation/plugins/openai/service/error.dart'; - import 'package:http/http.dart' as http; -import 'package:appflowy/startup/startup.dart'; import 'dart:async'; class MyMockClient extends Mock implements http.Client { @@ -18,7 +16,7 @@ class MyMockClient extends Mock implements http.Client { final responseHeaders = {'content-type': 'text/event-stream'}; final responseBody = Stream.fromIterable([ utf8.encode( - '{ "choices": [{"text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec", "index": 0, "logprobs": null, "finish_reason": null}]}'), + '{ "choices": [{"text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula ", "index": 0, "logprobs": null, "finish_reason": null}]}'), utf8.encode('\n'), utf8.encode('[DONE]'), ]); @@ -75,15 +73,4 @@ class MockOpenAIRepository extends HttpOpenAIRepository { } return; } - -} - -Future mockOpenAIRepository() async { - await getIt.unregister(); - getIt.registerFactoryAsync( - () => Future.value( - MockOpenAIRepository(), - ), - ); - return; -} +} \ No newline at end of file diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart index f92f73cbbedfd..42873128cbcd4 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart @@ -4,7 +4,7 @@ import 'package:appflowy/plugins/document/presentation/plugins/openai/service/op import 'package:appflowy/plugins/document/presentation/plugins/openai/util/learn_more_action.dart'; import 'package:appflowy/plugins/document/presentation/plugins/openai/widgets/discard_dialog.dart'; import 'package:appflowy/plugins/document/presentation/plugins/openai/widgets/smart_edit_action.dart'; -import 'package:appflowy/user/application/user_service.dart'; +import 'package:appflowy/startup/startup.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; @@ -12,7 +12,6 @@ import 'package:flowy_infra_ui/style_widget/decoration.dart'; import 'package:flutter/material.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:easy_localization/easy_localization.dart'; -import 'package:get_it/get_it.dart'; import 'package:http/http.dart' as http; const String kSmartEditType = 'smart_edit_input'; @@ -243,7 +242,7 @@ class _SmartEditInputState extends State<_SmartEditInput> { ), onPressed: () async { await _onReplace(); - _onExit(); + await _onExit(); }, ), const Space(10, 0), @@ -258,7 +257,7 @@ class _SmartEditInputState extends State<_SmartEditInput> { ), onPressed: () async { await _onInsertBelow(); - _onExit(); + await _onExit(); }, ), const Space(10, 0), @@ -273,10 +272,13 @@ class _SmartEditInputState extends State<_SmartEditInput> { ), onPressed: () async => await _onExit(), ), - const Spacer(), - FlowyText.regular( - LocaleKeys.document_plugins_warning.tr(), - color: Theme.of(context).hintColor, + const Spacer(flex:2), + Expanded( + child: FlowyText.regular( + overflow: TextOverflow.ellipsis, + LocaleKeys.document_plugins_warning.tr(), + color: Theme.of(context).hintColor, + ), ), ], ); @@ -299,25 +301,21 @@ class _SmartEditInputState extends State<_SmartEditInput> { selection, texts, ); - widget.editorState.apply(transaction).then( - (_) { - int endOffset = texts.last.length; - if (texts.length == 1) { - endOffset += selection.start.offset; - } - widget.editorState.updateCursorSelection( - Selection( - start: Position( - path: selection.start.path, - offset: selection.start.offset, - ), - end: Position( - path: [selection.start.path.first + texts.length - 1], - offset: endOffset, - ), - ), - ); - }, + await widget.editorState.apply(transaction); + + int endOffset = texts.last.length; + if (texts.length == 1) { + endOffset += selection.start.offset; + } + + await widget.editorState.updateCursorSelection( + Selection( + start: selection.start, + end: Position( + path: [selection.start.path.first + texts.length - 1], + offset: endOffset, + ), + ), ); } @@ -337,17 +335,15 @@ class _SmartEditInputState extends State<_SmartEditInput> { ), ), ); - widget.editorState.apply(transaction).then( - (_) { - widget.editorState.updateCursorSelection( - Selection( - start: Position(path: selection.end.path.next, offset: 0), - end: Position( - path: [selection.end.path.next.first + texts.length], - ), - ), - ); - }, + await widget.editorState.apply(transaction); + + await widget.editorState.updateCursorSelection( + Selection( + start: Position(path: selection.end.path.next, offset: 0), + end: Position( + path: [selection.end.path.next.first + texts.length], + ), + ), ); } @@ -364,47 +360,40 @@ class _SmartEditInputState extends State<_SmartEditInput> { } Future _requestCompletions() async { - final getIt = GetIt.instance; - final result = await UserBackendService.getCurrentUserProfile(); - return result.fold((l) async { - final openAIRepository = await getIt.getAsync() as HttpOpenAIRepository; - - var lines = input.split('\n\n'); - if (action == SmartEditAction.summarize) { - lines = [lines.join('\n')]; - } - for (var i = 0; i < lines.length; i++) { - final element = lines[i]; - await openAIRepository.getStreamedCompletions( - useAction: true, - prompt: action.prompt(element), - onStart: () async { - setState(() { - loading = false; - }); - }, - onProcess: (response) async { - setState(() { - this.result += response.choices.first.text; - }); - }, - onEnd: () async { - setState(() { - if (i != lines.length - 1) { - this.result += '\n'; - } - }); - }, - onError: (error) async { - await _showError(error.message); - await _onExit(); - }, - ); - } - }, (r) async { - await _showError(r.msg); - await _onExit(); - }); + final openAIRepository = await getIt.getAsync() as HttpOpenAIRepository; + + var lines = input.split('\n\n'); + if (action == SmartEditAction.summarize) { + lines = [lines.join('\n')]; + } + for (var i = 0; i < lines.length; i++) { + final element = lines[i]; + await openAIRepository.getStreamedCompletions( + useAction: true, + prompt: action.prompt(element), + onStart: () async { + setState(() { + loading = false; + }); + }, + onProcess: (response) async { + setState(() { + result += response.choices.first.text; + }); + }, + onEnd: () async { + setState(() { + if (i != lines.length - 1) { + result += '\n'; + } + }); + }, + onError: (error) async { + await _showError(error.message); + await _onExit(); + }, + ); + } } Future _showError(String message) async { @@ -420,4 +409,4 @@ class _SmartEditInputState extends State<_SmartEditInput> { ), ); } -} +} \ No newline at end of file diff --git a/frontend/appflowy_flutter/lib/startup/deps_resolver.dart b/frontend/appflowy_flutter/lib/startup/deps_resolver.dart index 55009077254ca..9333a16786ba5 100644 --- a/frontend/appflowy_flutter/lib/startup/deps_resolver.dart +++ b/frontend/appflowy_flutter/lib/startup/deps_resolver.dart @@ -53,13 +53,13 @@ void _resolveCommonService(GetIt getIt) async { () async { final result = await UserBackendService.getCurrentUserProfile(); return result.fold( - (l) async { + (l) { return HttpOpenAIRepository( client: http.Client(), apiKey: l.openaiKey, ); }, - (r) async { + (r) { throw Exception('Failed to get user profile: ${r.msg}'); }, ); @@ -177,4 +177,4 @@ void _resolveGridDeps(GetIt getIt) { (viewId, cache) => DatabasePropertyBloc(viewId: viewId, fieldController: cache), ); -} +} \ No newline at end of file From 1fa55620db9854c423cf7ad7ac1587d4d9cda80b Mon Sep 17 00:00:00 2001 From: squidrye Date: Wed, 29 Mar 2023 18:00:43 +0530 Subject: [PATCH 06/13] fix: integration tests causing error in github-ci --- .../integration_test/app_test.dart | 14 ++++++ .../open_ai_smart_menu_test.dart | 43 +++++++++++-------- .../integration_test/switch_folder_test.dart | 2 +- frontend/appflowy_flutter/pubspec.yaml | 1 + 4 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 frontend/appflowy_flutter/integration_test/app_test.dart diff --git a/frontend/appflowy_flutter/integration_test/app_test.dart b/frontend/appflowy_flutter/integration_test/app_test.dart new file mode 100644 index 0000000000000..b077c85bea511 --- /dev/null +++ b/frontend/appflowy_flutter/integration_test/app_test.dart @@ -0,0 +1,14 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'open_ai_smart_menu_test.dart' as smart_menu_test; +import 'switch_folder_test.dart' as switch_folder_test; + +void main() async{ + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('run all tests',(){ + switch_folder_test.run(); + smart_menu_test.run(); + }); +} \ No newline at end of file diff --git a/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart b/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart index bac50f3419aac..3e2ace4cd312d 100644 --- a/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart +++ b/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart @@ -1,19 +1,18 @@ +import 'package:appflowy/plugins/document/presentation/plugins/openai/service/openai_client.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; - -import 'util/base.dart'; import 'util/mock/mock_file_picker.dart'; import 'util/mock/mock_openai_repository.dart'; import 'util/util.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart'; +import 'package:appflowy/startup/startup.dart'; -void main() { +void run() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - group('trying to reach setup dummy keys for open ai', () { + group('integration tests for open-ai smart menu', () { const location = 'test_flowy'; setUp(() async { await TestFolder.cleanTestLocation(location); @@ -28,7 +27,6 @@ void main() { }); testWidgets('testing selection on open-ai smart menu replace', (tester) async { - final appFlowyEditor = await setUpOpenAITesting(tester); final editorState = appFlowyEditor.editorState; const dummyText = 'Some text to test open ai'; @@ -36,15 +34,15 @@ void main() { await tester.pumpAndSettle(); editorState.service.selectionService.updateSelection(Selection( - start: Position(path: [0], offset: 0), - end: Position(path: [0], offset: dummyText.length), + start: Position(path: [0], offset: 4), + end: Position(path: [0], offset: dummyText.length - 2), )); await tester.pumpAndSettle(const Duration(milliseconds: 500)); await tester.pumpAndSettle(); expect(find.byType(ToolbarWidget), findsAtLeastNWidgets(1)); await tester.tap(find.byTooltip('AI Assistants')); - await tester.pumpAndSettle(); + await tester.pumpAndSettle(const Duration(milliseconds: 500)); await tester.tap(find.text('Summarize')); await tester.pumpAndSettle(); @@ -55,13 +53,12 @@ void main() { expect( editorState.service.selectionService.currentSelection.value, Selection( - start: Position(path: [0], offset: 0), - end: Position(path: [0], offset: 338), + start: Position(path: [0], offset: 4), + end: Position(path: [0], offset: 84), ), ); }); testWidgets('testing selection on open-ai smart menu insert', (tester) async { - final appFlowyEditor = await setUpOpenAITesting(tester); final editorState = appFlowyEditor.editorState; const dummyText = 'Some text to test open ai'; @@ -77,7 +74,7 @@ void main() { expect(find.byType(ToolbarWidget), findsAtLeastNWidgets(1)); await tester.tap(find.byTooltip('AI Assistants')); - await tester.pumpAndSettle(); + await tester.pumpAndSettle(const Duration(milliseconds: 500)); await tester.tap(find.text('Summarize')); await tester.pumpAndSettle(); @@ -96,7 +93,7 @@ void main() { }); } -Future setUpOpenAITesting(WidgetTester tester)async{ +Future setUpOpenAITesting(WidgetTester tester) async { const folderName = 'test_flowy'; const dummyKey = 'dummyKey'; await TestFolder.cleanTestLocation(folderName); @@ -107,8 +104,6 @@ Future setUpOpenAITesting(WidgetTester tester)async{ await mockGetDirectoryPath(folderName); await tester.tapOpenFolderButton(); - - await tester.wait(1000); await tester.expectToSeeWelcomePage(); await mockOpenAIRepository(); @@ -119,6 +114,10 @@ Future setUpOpenAITesting(WidgetTester tester)async{ await tester.pumpAndSettle(); await simulateKeyDownEvent(LogicalKeyboardKey.escape); + await tester.pumpAndSettle(const Duration(milliseconds: 500)); + + await simulateKeyDownEvent(LogicalKeyboardKey.controlLeft); + await simulateKeyDownEvent(LogicalKeyboardKey.backslash); await tester.pumpAndSettle(); @@ -126,4 +125,14 @@ Future setUpOpenAITesting(WidgetTester tester)async{ await tester.tap(editor); await tester.pumpAndSettle(); return (tester.state(editor).widget as AppFlowyEditor); -} \ No newline at end of file +} + +Future mockOpenAIRepository() async { + await getIt.unregister(); + getIt.registerFactoryAsync( + () => Future.value( + MockOpenAIRepository(), + ), + ); + return; +} diff --git a/frontend/appflowy_flutter/integration_test/switch_folder_test.dart b/frontend/appflowy_flutter/integration_test/switch_folder_test.dart index 555a5e41b1b37..110a46549dfc8 100644 --- a/frontend/appflowy_flutter/integration_test/switch_folder_test.dart +++ b/frontend/appflowy_flutter/integration_test/switch_folder_test.dart @@ -11,7 +11,7 @@ import 'package:integration_test/integration_test.dart'; import 'util/mock/mock_file_picker.dart'; import 'util/util.dart'; -void main() { +void run() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('customize the folder path', () { diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml index b9d5b4a87557e..5adac56ce6cdc 100644 --- a/frontend/appflowy_flutter/pubspec.yaml +++ b/frontend/appflowy_flutter/pubspec.yaml @@ -97,6 +97,7 @@ dependencies: http: ^0.13.5 json_annotation: ^4.7.0 path: ^1.8.2 + mocktail: ^0.3.0 dev_dependencies: flutter_lints: ^2.0.1 From 419deb4dc76996e9ef5be832c28bead8d3fa8747 Mon Sep 17 00:00:00 2001 From: squidrye Date: Fri, 7 Apr 2023 03:38:58 +0530 Subject: [PATCH 07/13] refactor: reverting redundant changes due to recent changes in repo --- .../integration_test/util/settings.dart | 10 ---------- .../settings/widgets/settings_user_view.dart | 11 +++++------ 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/frontend/appflowy_flutter/integration_test/util/settings.dart b/frontend/appflowy_flutter/integration_test/util/settings.dart index c1b761ee5b2b7..4b01c2d79123c 100644 --- a/frontend/appflowy_flutter/integration_test/util/settings.dart +++ b/frontend/appflowy_flutter/integration_test/util/settings.dart @@ -81,14 +81,4 @@ extension AppFlowySettings on WidgetTester { await testTextInput.receiveAction(TextInputAction.done); await pumpAndSettle(); } - /// Enter dummy api key - Future enterDummyApiKey(String key) async { - final uni = find.byType(OpenaiKeyInput); - expect(uni, findsOneWidget); - await tap(uni); - await enterText(uni, key); - await wait(300); // - await testTextInput.receiveAction(TextInputAction.done); - await pumpAndSettle(); - } } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart index 1a1094dcaed83..29f1fe2625b63 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart @@ -58,7 +58,7 @@ class SettingsUserView extends StatelessWidget { Widget _renderCurrentOpenaiKey(BuildContext context) { String openAIKey = context.read().state.userProfile.openaiKey; - return OpenaiKeyInput(openAIKey); + return _OpenaiKeyInput(openAIKey); } } @@ -86,19 +86,18 @@ class UserNameInput extends StatelessWidget { } } -@visibleForTesting -class OpenaiKeyInput extends StatefulWidget { +class _OpenaiKeyInput extends StatefulWidget { final String openAIKey; - const OpenaiKeyInput( + const _OpenaiKeyInput( this.openAIKey, { Key? key, }) : super(key: key); @override - State createState() => OpenaiKeyInputState(); + State<_OpenaiKeyInput> createState() => OpenaiKeyInputState(); } -class OpenaiKeyInputState extends State { +class OpenaiKeyInputState extends State<_OpenaiKeyInput> { bool visible = false; final textEditingController = TextEditingController(); final debounce = Debounce(); From 8048d089d849c9f7f88fedfe29965b461474ab33 Mon Sep 17 00:00:00 2001 From: squidrye Date: Fri, 7 Apr 2023 03:39:59 +0530 Subject: [PATCH 08/13] refactor: reverting redundant changes due to recent changes in repo --- .../appflowy_editor/lib/src/core/transform/transaction.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart b/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart index a038d5364080b..6c369f566e7ae 100644 --- a/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart +++ b/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/core/transform/transaction.dart @@ -68,9 +68,6 @@ class Transaction { /// Deletes the [Node] in the document. void deleteNode(Node node) { deleteNodesAtPath(node.path); - if(beforeSelection != null){ - afterSelection = beforeSelection; - } } /// Deletes the [Node]s in the document. From 8c346455d6df99af6e11a2b9872d1910af18ea8c Mon Sep 17 00:00:00 2001 From: squidrye Date: Fri, 7 Apr 2023 03:54:08 +0530 Subject: [PATCH 09/13] refactor: refactoring to workspace based integration testing. --- .../assets/test/workspaces/ai_workspace.zip | Bin 0 -> 9501 bytes .../integration_test/app_test.dart | 14 ---- .../open_ai_smart_menu_test.dart | 62 ++++----------- .../integration_test/runner.dart | 2 + .../integration_test/switch_folder_test.dart | 2 +- .../integration_test/util/data.dart | 3 +- frontend/appflowy_flutter/pubspec.lock | 74 +++++++++--------- frontend/appflowy_flutter/pubspec.yaml | 2 +- 8 files changed, 57 insertions(+), 102 deletions(-) create mode 100644 frontend/appflowy_flutter/assets/test/workspaces/ai_workspace.zip delete mode 100644 frontend/appflowy_flutter/integration_test/app_test.dart diff --git a/frontend/appflowy_flutter/assets/test/workspaces/ai_workspace.zip b/frontend/appflowy_flutter/assets/test/workspaces/ai_workspace.zip new file mode 100644 index 0000000000000000000000000000000000000000..b523b64ed045fc0fddf32a3f8b2fdc73abd5314b GIT binary patch literal 9501 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 NgSfN!G5ycc{{vK`=SBbk literal 0 HcmV?d00001 diff --git a/frontend/appflowy_flutter/integration_test/app_test.dart b/frontend/appflowy_flutter/integration_test/app_test.dart deleted file mode 100644 index b077c85bea511..0000000000000 --- a/frontend/appflowy_flutter/integration_test/app_test.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; - -import 'open_ai_smart_menu_test.dart' as smart_menu_test; -import 'switch_folder_test.dart' as switch_folder_test; - -void main() async{ - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - group('run all tests',(){ - switch_folder_test.run(); - smart_menu_test.run(); - }); -} \ No newline at end of file diff --git a/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart b/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart index 3e2ace4cd312d..528997d0820bb 100644 --- a/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart +++ b/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart @@ -3,42 +3,31 @@ import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'util/mock/mock_file_picker.dart'; import 'util/mock/mock_openai_repository.dart'; import 'util/util.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart'; import 'package:appflowy/startup/startup.dart'; -void run() { +void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - group('integration tests for open-ai smart menu', () { - const location = 'test_flowy'; - setUp(() async { - await TestFolder.cleanTestLocation(location); - await TestFolder.setTestLocation(location); - }); + const service = TestWorkspaceService(TestWorkspace.aiWorkSpace); - tearDown(() async { - await TestFolder.cleanTestLocation(location); - }); - tearDownAll(() async { - await TestFolder.cleanTestLocation(null); - }); + group('integration tests for open-ai smart menu', () { + setUpAll(() async => await service.setUpAll()); + setUp(() async => await service.setUp()); testWidgets('testing selection on open-ai smart menu replace', (tester) async { final appFlowyEditor = await setUpOpenAITesting(tester); final editorState = appFlowyEditor.editorState; - const dummyText = 'Some text to test open ai'; - editorState.document.insert([0], [TextNode(delta: Delta()..insert(dummyText))]); - await tester.pumpAndSettle(); editorState.service.selectionService.updateSelection(Selection( - start: Position(path: [0], offset: 4), - end: Position(path: [0], offset: dummyText.length - 2), + start: Position(path: [1], offset: 4), + end: Position(path: [1], offset: 10), )); await tester.pumpAndSettle(const Duration(milliseconds: 500)); await tester.pumpAndSettle(); + expect(find.byType(ToolbarWidget), findsAtLeastNWidgets(1)); await tester.tap(find.byTooltip('AI Assistants')); @@ -53,21 +42,18 @@ void run() { expect( editorState.service.selectionService.currentSelection.value, Selection( - start: Position(path: [0], offset: 4), - end: Position(path: [0], offset: 84), + start: Position(path: [1], offset: 4), + end: Position(path: [1], offset: 84), ), ); }); testWidgets('testing selection on open-ai smart menu insert', (tester) async { final appFlowyEditor = await setUpOpenAITesting(tester); final editorState = appFlowyEditor.editorState; - const dummyText = 'Some text to test open ai'; - editorState.document.insert([0], [TextNode(delta: Delta()..insert(dummyText))]); - await tester.pumpAndSettle(); editorState.service.selectionService.updateSelection(Selection( - start: Position(path: [0], offset: 0), - end: Position(path: [0], offset: dummyText.length), + start: Position(path: [1], offset: 0), + end: Position(path: [1], offset: 5), )); await tester.pumpAndSettle(const Duration(milliseconds: 500)); await tester.pumpAndSettle(); @@ -85,8 +71,8 @@ void run() { expect( editorState.service.selectionService.currentSelection.value, Selection( - start: Position(path: [1], offset: 0), - end: Position(path: [2], offset: 0), + start: Position(path: [2], offset: 0), + end: Position(path: [3], offset: 0), ), ); }); @@ -94,33 +80,13 @@ void run() { } Future setUpOpenAITesting(WidgetTester tester) async { - const folderName = 'test_flowy'; - const dummyKey = 'dummyKey'; - await TestFolder.cleanTestLocation(folderName); - await TestFolder.setTestLocation(folderName); - await tester.initializeAppFlowy(); - - await mockGetDirectoryPath(folderName); - - await tester.tapOpenFolderButton(); - await tester.expectToSeeWelcomePage(); - await mockOpenAIRepository(); - await tester.openSettings(); - await tester.openSettingsPage(SettingsPage.user); - await tester.enterDummyApiKey(dummyKey); - await tester.pumpAndSettle(); - - await simulateKeyDownEvent(LogicalKeyboardKey.escape); - await tester.pumpAndSettle(const Duration(milliseconds: 500)); - await simulateKeyDownEvent(LogicalKeyboardKey.controlLeft); await simulateKeyDownEvent(LogicalKeyboardKey.backslash); await tester.pumpAndSettle(); - final Finder editor = find.byType(AppFlowyEditor); await tester.tap(editor); await tester.pumpAndSettle(); diff --git a/frontend/appflowy_flutter/integration_test/runner.dart b/frontend/appflowy_flutter/integration_test/runner.dart index 1592cccb9375f..b848ce1fc3c60 100644 --- a/frontend/appflowy_flutter/integration_test/runner.dart +++ b/frontend/appflowy_flutter/integration_test/runner.dart @@ -3,6 +3,7 @@ import 'package:integration_test/integration_test.dart'; import 'board_test.dart' as board_test; import 'switch_folder_test.dart' as switch_folder_test; import 'empty_document_test.dart' as empty_document_test; +import 'open_ai_smart_menu_test.dart' as smart_menu_test; /// The main task runner for all integration tests in AppFlowy. /// @@ -16,4 +17,5 @@ void main() { switch_folder_test.main(); board_test.main(); empty_document_test.main(); + smart_menu_test.main(); } diff --git a/frontend/appflowy_flutter/integration_test/switch_folder_test.dart b/frontend/appflowy_flutter/integration_test/switch_folder_test.dart index c519e19bcbdd4..6dcd41b081644 100644 --- a/frontend/appflowy_flutter/integration_test/switch_folder_test.dart +++ b/frontend/appflowy_flutter/integration_test/switch_folder_test.dart @@ -6,7 +6,7 @@ import 'package:integration_test/integration_test.dart'; import 'util/mock/mock_file_picker.dart'; import 'util/util.dart'; -void run() { +void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('customize the folder path', () { diff --git a/frontend/appflowy_flutter/integration_test/util/data.dart b/frontend/appflowy_flutter/integration_test/util/data.dart index a527950489a14..bd34dc4d1358e 100644 --- a/frontend/appflowy_flutter/integration_test/util/data.dart +++ b/frontend/appflowy_flutter/integration_test/util/data.dart @@ -9,7 +9,8 @@ import 'package:shared_preferences/shared_preferences.dart'; enum TestWorkspace { board("board"), - emptyDocument("empty_document"); + emptyDocument("empty_document"), + aiWorkSpace("ai_workspace"); const TestWorkspace(this._name); diff --git a/frontend/appflowy_flutter/pubspec.lock b/frontend/appflowy_flutter/pubspec.lock index c785f0285f76f..a42a7b587e2b6 100644 --- a/frontend/appflowy_flutter/pubspec.lock +++ b/frontend/appflowy_flutter/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: "direct main" description: name: appflowy_editor - sha256: "2f28ff3ef62bfb02f13e10931fa8c091aa9f804934dfbf5d3d0af0acaf06a240" + sha256: "0768e7aee78c67c6ddd2ee8cbaa182848c9d94a98d495bd415ff0059b491ac08" url: "https://pub.dev" source: hosted - version: "0.1.4" + version: "0.1.5" appflowy_editor_plugins: dependency: "direct main" description: @@ -64,7 +64,7 @@ packages: source: path version: "0.0.1" archive: - dependency: transitive + dependency: "direct main" description: name: archive sha256: "80e5141fafcb3361653ce308776cfd7d45e6e9fbb429e14eec571382c0c5fecb" @@ -131,7 +131,7 @@ packages: dependency: transitive description: name: build_daemon - sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf" + sha256: "757153e5d9cd88253cb13f28c2fb55a537dc31fefd98137549895b5beb7c6169" url: "https://pub.dev" source: hosted version: "3.1.1" @@ -171,7 +171,7 @@ packages: dependency: transitive description: name: built_value - sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725" + sha256: "31b7c748fd4b9adf8d25d72a4c4a59ef119f12876cf414f94f8af5131d5fa2b0" url: "https://pub.dev" source: hosted version: "8.4.4" @@ -527,7 +527,7 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + sha256: c224ac897bed083dabf11f238dd11a239809b446740be0c2044608c50029ffdf url: "https://pub.dev" source: hosted version: "2.0.9" @@ -553,7 +553,7 @@ packages: dependency: "direct main" description: name: fluttertoast - sha256: "7cc92eabe01e3f1babe1571c5560b135dfc762a34e41e9056881e2196b178ec1" + sha256: "2f9c4d3f4836421f7067a28f8939814597b27614e021da9d63e5d3fb6e212d25" url: "https://pub.dev" source: hosted version: "8.2.1" @@ -638,7 +638,7 @@ packages: dependency: transitive description: name: html - sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + sha256: "79d498e6d6761925a34ee5ea8fa6dfef38607781d2fa91e37523474282af55cb" url: "https://pub.dev" source: hosted version: "0.15.2" @@ -763,7 +763,7 @@ packages: dependency: transitive description: name: logger - sha256: "5076f09225f91dc49289a4ccb92df2eeea9ea01cf7c26d49b3a1f04c6a49eec1" + sha256: db2ff852ed77090ba9f62d3611e4208a3d11dfa35991a81ae724c113fcb3e3f7 url: "https://pub.dev" source: hosted version: "1.3.0" @@ -816,7 +816,7 @@ packages: source: hosted version: "1.0.4" mocktail: - dependency: transitive + dependency: "direct main" description: name: mocktail sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53" @@ -843,7 +843,7 @@ packages: dependency: transitive description: name: node_preamble - sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d" + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" url: "https://pub.dev" source: hosted version: "2.0.2" @@ -923,7 +923,7 @@ packages: dependency: "direct main" description: name: path_provider - sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + sha256: c7edf82217d4b2952b2129a61d3ad60f1075b9299e629e149a8d2e39c2e6aad4 url: "https://pub.dev" source: hosted version: "2.0.14" @@ -931,7 +931,7 @@ packages: dependency: transitive description: name: path_provider_android - sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + sha256: "019f18c9c10ae370b08dce1f3e3b73bc9f58e7f087bb5e921f06529438ac0ae7" url: "https://pub.dev" source: hosted version: "2.0.24" @@ -939,7 +939,7 @@ packages: dependency: transitive description: name: path_provider_foundation - sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" + sha256: "12eee51abdf4d34c590f043f45073adbb45514a108bd9db4491547a2fd891059" url: "https://pub.dev" source: hosted version: "2.2.0" @@ -947,7 +947,7 @@ packages: dependency: transitive description: name: path_provider_linux - sha256: "2e32f1640f07caef0d3cb993680f181c79e54a3827b997d5ee221490d131fbd9" + sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" url: "https://pub.dev" source: hosted version: "2.1.10" @@ -955,7 +955,7 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" url: "https://pub.dev" source: hosted version: "2.0.6" @@ -971,7 +971,7 @@ packages: dependency: "direct main" description: name: percent_indicator - sha256: cec41f67181fbd5322aa68b355621d1a4eea827426b8eeb613f6cbe195ff7b4a + sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c url: "https://pub.dev" source: hosted version: "4.2.3" @@ -995,7 +995,7 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" url: "https://pub.dev" source: hosted version: "2.1.4" @@ -1115,7 +1115,7 @@ packages: dependency: transitive description: name: rich_clipboard_windows - sha256: "03decfbd9bf6c50c663f8c4a0db14063e2a4d9ad5dd053fdb72875aa8bc4fd1b" + sha256: fa2a28e75ce4bcc9efc6d5d0e9788b76716cdaf3b7063c141fe8af12a315f414 url: "https://pub.dev" source: hosted version: "1.0.2" @@ -1131,7 +1131,7 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "5949029e70abe87f75cfe59d17bf5c397619c4b74a099b10116baeb34786fad9" + sha256: "78528fd87d0d08ffd3e69551173c026e8eacc7b7079c82eb6a77413957b7e394" url: "https://pub.dev" source: hosted version: "2.0.20" @@ -1139,7 +1139,7 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: "955e9736a12ba776bdd261cf030232b30eadfcd9c79b32a3250dd4a494e8c8f7" + sha256: ad423a80fe7b4e48b50d6111b3ea1027af0e959e49d485712e134863d9c1c521 url: "https://pub.dev" source: hosted version: "2.0.17" @@ -1147,7 +1147,7 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "2b55c18636a4edc529fa5cd44c03d3f3100c00513f518c5127c951978efcccd0" + sha256: "1e755f8583229f185cfca61b1d80fb2344c9d660e1c69ede5450d8f478fa5310" url: "https://pub.dev" source: hosted version: "2.1.5" @@ -1155,7 +1155,7 @@ packages: dependency: transitive description: name: shared_preferences_linux - sha256: f8ea038aa6da37090093974ebdcf4397010605fd2ff65c37a66f9d28394cb874 + sha256: "3a59ed10890a8409ad0faad7bb2957dab4b92b8fbe553257b05d30ed8af2c707" url: "https://pub.dev" source: hosted version: "2.1.5" @@ -1163,7 +1163,7 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: da9431745ede5ece47bc26d5d73a9d3c6936ef6945c101a5aca46f62e52c1cf3 + sha256: "824bfd02713e37603b2bdade0842e47d56e7db32b1dcdd1cae533fb88e2913fc" url: "https://pub.dev" source: hosted version: "2.1.1" @@ -1171,7 +1171,7 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: a4b5bc37fe1b368bbc81f953197d55e12f49d0296e7e412dfe2d2d77d6929958 + sha256: "0dc2633f215a3d4aa3184c9b2c5766f4711e4e5a6b256e62aafee41f89f1bfb8" url: "https://pub.dev" source: hosted version: "2.0.6" @@ -1179,7 +1179,7 @@ packages: dependency: transitive description: name: shared_preferences_windows - sha256: "5eaf05ae77658d3521d0e993ede1af962d4b326cd2153d312df716dc250f00c9" + sha256: "71bcd669bb9cdb6b39f22c4a7728b6d49e934f6cba73157ffa5a54f1eed67436" url: "https://pub.dev" source: hosted version: "2.1.5" @@ -1227,7 +1227,7 @@ packages: dependency: "direct main" description: name: sized_context - sha256: "4da0ecbb6a58afc3f51ba1984dc25eef6ee0e8176f8923b686c96ee1cfba23ac" + sha256: "9921e6c09e018132c3e1c6a18e14febbc1cc5c87a200d64ff7578cb49991f6e7" url: "https://pub.dev" source: hosted version: "1.0.0+4" @@ -1264,7 +1264,7 @@ packages: dependency: transitive description: name: source_maps - sha256: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427" + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" url: "https://pub.dev" source: hosted version: "0.10.12" @@ -1424,7 +1424,7 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: e8f2efc804810c0f2f5b485f49e7942179f56eabcfe81dce3387fec4bb55876b + sha256: "75f2846facd11168d007529d6cd8fcb2b750186bea046af9711f10b907e1587e" url: "https://pub.dev" source: hosted version: "6.1.10" @@ -1432,7 +1432,7 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" + sha256: dd729390aa936bf1bdf5cd1bc7468ff340263f80a2c4f569416507667de8e3c8 url: "https://pub.dev" source: hosted version: "6.0.26" @@ -1440,7 +1440,7 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: "0a5af0aefdd8cf820dd739886efb1637f1f24489900204f50984634c07a54815" + sha256: "3dedc66ca3c0bef9e6a93c0999aee102556a450afcc1b7bcfeace7a424927d92" url: "https://pub.dev" source: hosted version: "6.1.3" @@ -1448,7 +1448,7 @@ packages: dependency: transitive description: name: url_launcher_linux - sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" + sha256: "206fb8334a700ef7754d6a9ed119e7349bc830448098f21a69bf1b4ed038cabc" url: "https://pub.dev" source: hosted version: "3.0.4" @@ -1456,7 +1456,7 @@ packages: dependency: transitive description: name: url_launcher_macos - sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" + sha256: "0ef2b4f97942a16523e51256b799e9aa1843da6c60c55eefbfa9dbc2dcb8331a" url: "https://pub.dev" source: hosted version: "3.0.4" @@ -1464,7 +1464,7 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" url: "https://pub.dev" source: hosted version: "2.1.2" @@ -1472,7 +1472,7 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" + sha256: "81fe91b6c4f84f222d186a9d23c73157dc4c8e1c71489c4d08be1ad3b228f1aa" url: "https://pub.dev" source: hosted version: "2.0.16" @@ -1480,7 +1480,7 @@ packages: dependency: transitive description: name: url_launcher_windows - sha256: b6217370f8eb1fd85c8890c539f5a639a01ab209a36db82c921ebeacefc7a615 + sha256: a83ba3607a507758669cfafb03f9de09bf6e6280c14d9b9cb18f013e406dcacd url: "https://pub.dev" source: hosted version: "3.0.5" @@ -1576,7 +1576,7 @@ packages: dependency: "direct main" description: name: window_manager - sha256: "5bdd29dc5f1f3185fc90696373a571d77968e03e5e820fb1ecdbdade3f5d8fff" + sha256: "492806c69879f0d28e95472bbe5e8d5940ac8c6e99cc07052fe14946974555ba" url: "https://pub.dev" source: hosted version: "0.3.1" diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml index 94d0fb2a30d99..dc1345f6b8b88 100644 --- a/frontend/appflowy_flutter/pubspec.yaml +++ b/frontend/appflowy_flutter/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: git: url: https://github.com/AppFlowy-IO/appflowy-board.git ref: a183c57 - appflowy_editor: ^0.1.4 + appflowy_editor: ^0.1.5 appflowy_popover: path: packages/appflowy_popover From 0d990d303a084f68962d200671fa1f9d3034d49d Mon Sep 17 00:00:00 2001 From: squidrye Date: Fri, 7 Apr 2023 03:58:31 +0530 Subject: [PATCH 10/13] refactor: reverting redundant changes due to recent changes in repo --- .../presentation/settings/widgets/settings_user_view.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart index 29f1fe2625b63..1b6f7a9a6fcc5 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_user_view.dart @@ -94,10 +94,10 @@ class _OpenaiKeyInput extends StatefulWidget { }) : super(key: key); @override - State<_OpenaiKeyInput> createState() => OpenaiKeyInputState(); + State<_OpenaiKeyInput> createState() => _OpenaiKeyInputState(); } -class OpenaiKeyInputState extends State<_OpenaiKeyInput> { +class _OpenaiKeyInputState extends State<_OpenaiKeyInput> { bool visible = false; final textEditingController = TextEditingController(); final debounce = Debounce(); From d4d560782c11ae89e8d2c5e7fd566b86ee70e7ad Mon Sep 17 00:00:00 2001 From: squidrye Date: Wed, 12 Apr 2023 01:33:42 +0530 Subject: [PATCH 11/13] chore: fix analysis issues --- .../open_ai_smart_menu_test.dart | 20 +++++++++++-------- .../util/mock/mock_openai_repository.dart | 6 +++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart b/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart index 528997d0820bb..f63197a039253 100644 --- a/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart +++ b/frontend/appflowy_flutter/integration_test/open_ai_smart_menu_test.dart @@ -21,10 +21,12 @@ void main() { final appFlowyEditor = await setUpOpenAITesting(tester); final editorState = appFlowyEditor.editorState; - editorState.service.selectionService.updateSelection(Selection( - start: Position(path: [1], offset: 4), - end: Position(path: [1], offset: 10), - )); + editorState.service.selectionService.updateSelection( + Selection( + start: Position(path: [1], offset: 4), + end: Position(path: [1], offset: 10), + ), + ); await tester.pumpAndSettle(const Duration(milliseconds: 500)); await tester.pumpAndSettle(); @@ -51,10 +53,12 @@ void main() { final appFlowyEditor = await setUpOpenAITesting(tester); final editorState = appFlowyEditor.editorState; - editorState.service.selectionService.updateSelection(Selection( - start: Position(path: [1], offset: 0), - end: Position(path: [1], offset: 5), - )); + editorState.service.selectionService.updateSelection( + Selection( + start: Position(path: [1], offset: 0), + end: Position(path: [1], offset: 5), + ), + ); await tester.pumpAndSettle(const Duration(milliseconds: 500)); await tester.pumpAndSettle(); expect(find.byType(ToolbarWidget), findsAtLeastNWidgets(1)); diff --git a/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart b/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart index 18027f4fb43c6..a9486a8536878 100644 --- a/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart +++ b/frontend/appflowy_flutter/integration_test/util/mock/mock_openai_repository.dart @@ -16,7 +16,8 @@ class MyMockClient extends Mock implements http.Client { final responseHeaders = {'content-type': 'text/event-stream'}; final responseBody = Stream.fromIterable([ utf8.encode( - '{ "choices": [{"text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula ", "index": 0, "logprobs": null, "finish_reason": null}]}'), + '{ "choices": [{"text": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula ", "index": 0, "logprobs": null, "finish_reason": null}]}', + ), utf8.encode('\n'), utf8.encode('[DONE]'), ]); @@ -45,7 +46,6 @@ class MockOpenAIRepository extends HttpOpenAIRepository { double temperature = 0.3, bool useAction = false, }) async { - final request = http.Request('POST', OpenAIRequestType.textCompletion.uri); final response = await client.send(request); @@ -73,4 +73,4 @@ class MockOpenAIRepository extends HttpOpenAIRepository { } return; } -} \ No newline at end of file +} From a452e010457f4741701d4b8b71ae419b12fa2d6d Mon Sep 17 00:00:00 2001 From: squidrye Date: Fri, 14 Apr 2023 21:56:29 +0530 Subject: [PATCH 12/13] chore: fix analysis issues --- frontend/appflowy_flutter/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/appflowy_flutter/pubspec.yaml b/frontend/appflowy_flutter/pubspec.yaml index dc1345f6b8b88..ecf208f80e9d2 100644 --- a/frontend/appflowy_flutter/pubspec.yaml +++ b/frontend/appflowy_flutter/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: git: url: https://github.com/AppFlowy-IO/appflowy-board.git ref: a183c57 - appflowy_editor: ^0.1.5 + appflowy_editor: ^0.1.8 appflowy_popover: path: packages/appflowy_popover From c7d38db5b663157456511c2af249758f1758094b Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Wed, 3 May 2023 15:15:57 +0800 Subject: [PATCH 13/13] chore: remove the unnecessary conversion --- .../presentation/plugins/openai/service/openai_client.dart | 1 + .../plugins/openai/widgets/smart_edit_node_widget.dart | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/service/openai_client.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/service/openai_client.dart index ccb4b08866515..5daf57756436c 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/service/openai_client.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/service/openai_client.dart @@ -50,6 +50,7 @@ abstract class OpenAIRepository { String? suffix, int maxTokens = 2048, double temperature = 0.3, + bool useAction = false, }); /// Get edits from GPT-3 diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart index 42873128cbcd4..d308d4b2dd8ae 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/widgets/smart_edit_node_widget.dart @@ -272,7 +272,7 @@ class _SmartEditInputState extends State<_SmartEditInput> { ), onPressed: () async => await _onExit(), ), - const Spacer(flex:2), + const Spacer(flex: 2), Expanded( child: FlowyText.regular( overflow: TextOverflow.ellipsis, @@ -360,7 +360,7 @@ class _SmartEditInputState extends State<_SmartEditInput> { } Future _requestCompletions() async { - final openAIRepository = await getIt.getAsync() as HttpOpenAIRepository; + final openAIRepository = await getIt.getAsync(); var lines = input.split('\n\n'); if (action == SmartEditAction.summarize) { @@ -409,4 +409,4 @@ class _SmartEditInputState extends State<_SmartEditInput> { ), ); } -} \ No newline at end of file +}