diff --git a/.github/workflows/rust_ci.yaml b/.github/workflows/rust_ci.yaml index 785966e00a..ced3afcb0f 100644 --- a/.github/workflows/rust_ci.yaml +++ b/.github/workflows/rust_ci.yaml @@ -68,6 +68,31 @@ jobs: echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} >> .env.ci echo SUPABASE_JWT_SECRET=${{ secrets.SUPABASE_JWT_SECRET }} >> .env.ci + - name: Checkout appflowy cloud code + uses: actions/checkout@v3 + with: + repository: AppFlowy-IO/AppFlowy-Cloud + path: AppFlowy-Cloud + depth: 1 + + - name: Prepare appflowy cloud env + working-directory: AppFlowy-Cloud + run: | + # log level + cp dev.env .env + sed -i 's|RUST_LOG=.*|RUST_LOG=trace|' .env + sed -i 's/GOTRUE_SMTP_USER=.*/GOTRUE_SMTP_USER=${{ secrets.INTEGRATION_TEST_GOTRUE_SMTP_USER }}/' .env + sed -i 's/GOTRUE_SMTP_PASS=.*/GOTRUE_SMTP_PASS=${{ secrets.INTEGRATION_TEST_GOTRUE_SMTP_PASS }}/' .env + sed -i 's/GOTRUE_SMTP_ADMIN_EMAIL=.*/GOTRUE_SMTP_ADMIN_EMAIL=${{ secrets.INTEGRATION_TEST_GOTRUE_SMTP_ADMIN_EMAIL }}/' .env + sed -i 's/GOTRUE_EXTERNAL_GOOGLE_ENABLED=.*/GOTRUE_EXTERNAL_GOOGLE_ENABLED=true/' .env + sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env + cat .env + + - name: Run Docker-Compose + working-directory: AppFlowy-Cloud + run: | + docker compose up -d + - name: Run rust-lib tests working-directory: frontend/rust-lib run: RUST_LOG=info RUST_BACKTRACE=1 cargo test --no-default-features --features="rev-sqlite" diff --git a/frontend/appflowy_flutter/assets/test/workspaces/039_local.zip b/frontend/appflowy_flutter/assets/test/workspaces/039_local.zip deleted file mode 100644 index 7ef72daa02..0000000000 Binary files a/frontend/appflowy_flutter/assets/test/workspaces/039_local.zip and /dev/null differ diff --git a/frontend/appflowy_flutter/integration_test/appearance_settings_test.dart b/frontend/appflowy_flutter/integration_test/appearance_settings_test.dart index 8bace6f2eb..696b43c015 100644 --- a/frontend/appflowy_flutter/integration_test/appearance_settings_test.dart +++ b/frontend/appflowy_flutter/integration_test/appearance_settings_test.dart @@ -16,7 +16,7 @@ void main() { await tester.initializeAppFlowy(); await tester.tapGoButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); await tester.openSettings(); await tester.openSettingsPage(SettingsPage.appearance); @@ -48,7 +48,7 @@ void main() { await tester.initializeAppFlowy(); await tester.tapGoButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); await tester.openSettings(); await tester.openSettingsPage(SettingsPage.appearance); diff --git a/frontend/appflowy_flutter/integration_test/cloud/anon_user_continue_test.dart b/frontend/appflowy_flutter/integration_test/cloud/anon_user_continue_test.dart new file mode 100644 index 0000000000..68a3fd3ed5 --- /dev/null +++ b/frontend/appflowy_flutter/integration_test/cloud/anon_user_continue_test.dart @@ -0,0 +1,68 @@ +// ignore_for_file: unused_import + +import 'dart:io'; + +import 'package:appflowy/env/cloud_env.dart'; +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/startup/startup.dart'; +import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart'; +import 'package:appflowy/user/application/auth/auth_service.dart'; +import 'package:appflowy/workspace/application/settings/prelude.dart'; +import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart'; +import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/uuid.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; +import 'package:integration_test/integration_test.dart'; +import '../util/dir.dart'; +import '../util/mock/mock_file_picker.dart'; +import '../util/util.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('appflowy cloud', () { + testWidgets('anon user and then sign in', (tester) async { + await tester.initializeAppFlowy( + cloudType: AuthenticatorType.appflowyCloud, + ); + + tester.expectToSeeText(LocaleKeys.signIn_loginStartWithAnonymous.tr()); + await tester.tapGoButton(); + await tester.expectToSeeHomePage(); + + // reanme the name of the anon user + await tester.openSettings(); + await tester.openSettingsPage(SettingsPage.user); + final userNameFinder = find.descendant( + of: find.byType(SettingsUserView), + matching: find.byType(UserNameInput), + ); + await tester.enterText(userNameFinder, 'local_user'); + await tester.pumpAndSettle(); + + // sign up with Google + await tester.tapGoogleLoginInButton(); + await tester.pumpAndSettle(); + + // sign out + await tester.openSettings(); + await tester.openSettingsPage(SettingsPage.user); + await tester.logout(); + await tester.pumpAndSettle(); + + // tap the continue as anonymous button + await tester + .tapButton(find.text(LocaleKeys.signIn_continueAnonymousUser.tr())); + await tester.expectToSeeHomePage(); + + // assert the name of the anon user is local_user + await tester.openSettings(); + await tester.openSettingsPage(SettingsPage.user); + final userNameInput = tester.widget(userNameFinder) as UserNameInput; + expect(userNameInput.name, 'local_user'); + }); + }); +} diff --git a/frontend/appflowy_flutter/integration_test/cloud/anon_user_to_cloud_test.dart b/frontend/appflowy_flutter/integration_test/cloud/anon_user_to_cloud_test.dart new file mode 100644 index 0000000000..68d89252f0 --- /dev/null +++ b/frontend/appflowy_flutter/integration_test/cloud/anon_user_to_cloud_test.dart @@ -0,0 +1,74 @@ +// ignore_for_file: unused_import + +import 'dart:io'; + +import 'package:appflowy/env/cloud_env.dart'; +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/startup/startup.dart'; +import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart'; +import 'package:appflowy/user/application/auth/auth_service.dart'; +import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/sign_in_anonymous_button.dart'; +import 'package:appflowy/workspace/application/settings/prelude.dart'; +import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart'; +import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/uuid.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; +import 'package:integration_test/integration_test.dart'; +import '../util/database_test_op.dart'; +import '../util/dir.dart'; +import '../util/mock/mock_file_picker.dart'; +import '../util/util.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('appflowy cloud', () { + testWidgets('anon user -> af cloud -> continue anon', (tester) async { + await tester.initializeAppFlowy( + cloudType: AuthenticatorType.appflowyCloud, + ); + + tester.expectToSeeText(LocaleKeys.signIn_loginStartWithAnonymous.tr()); + await tester.tapGoButton(); + await tester.expectToSeeHomePage(); + + // reanme the name of the anon user + await tester.openSettings(); + await tester.openSettingsPage(SettingsPage.user); + final userNameFinder = find.descendant( + of: find.byType(SettingsUserView), + matching: find.byType(UserNameInput), + ); + await tester.enterText(userNameFinder, 'local_user'); + await tester.openSettingsPage(SettingsPage.user); + await tester.tapEscButton(); + await tester.expectToSeeHomePage(); + + // sign up with Google + await tester.openSettings(); + await tester.openSettingsPage(SettingsPage.user); + await tester.tapGoogleLoginInButton(); + + await tester.expectToSeeHomePage(); + + // sign out + await tester.openSettings(); + await tester.openSettingsPage(SettingsPage.user); + await tester.logout(); + await tester.pumpAndSettle(); + + tester.expectToSeeText(LocaleKeys.signIn_continueAnonymousUser.tr()); + // tap the continue as anonymous button + await tester.tapButton(find.byType(SignInAnonymousButton)); + + await tester.expectToSeeHomePage(); + await tester.openSettings(); + await tester.openSettingsPage(SettingsPage.user); + final userNameInput = tester.widget(userNameFinder) as UserNameInput; + expect(userNameInput.name, 'local_user'); + }); + }); +} diff --git a/frontend/appflowy_flutter/integration_test/cloud/appflowy_cloud_auth_test.dart b/frontend/appflowy_flutter/integration_test/cloud/appflowy_cloud_auth_test.dart index 72eb62631d..8e8ecff0e2 100644 --- a/frontend/appflowy_flutter/integration_test/cloud/appflowy_cloud_auth_test.dart +++ b/frontend/appflowy_flutter/integration_test/cloud/appflowy_cloud_auth_test.dart @@ -25,7 +25,7 @@ void main() { cloudType: AuthenticatorType.appflowyCloud, ); await tester.tapGoogleLoginInButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); }); testWidgets('sign out', (tester) async { diff --git a/frontend/appflowy_flutter/integration_test/cloud/cloud_runner.dart b/frontend/appflowy_flutter/integration_test/cloud/cloud_runner.dart index 58c1abdb0a..805fbc4dc8 100644 --- a/frontend/appflowy_flutter/integration_test/cloud/cloud_runner.dart +++ b/frontend/appflowy_flutter/integration_test/cloud/cloud_runner.dart @@ -1,14 +1,17 @@ -import 'empty_test.dart' as empty_test; +import 'empty_test.dart' as preset_af_cloud_env_test; import 'appflowy_cloud_auth_test.dart' as appflowy_cloud_auth_test; import 'document_sync_test.dart' as document_sync_test; import 'user_setting_sync_test.dart' as user_sync_test; +// import 'anon_user_continue_test.dart' as anon_user_continue_test; Future main() async { - empty_test.main(); + preset_af_cloud_env_test.main(); appflowy_cloud_auth_test.main(); document_sync_test.main(); user_sync_test.main(); + + // anon_user_continue_test.main(); } diff --git a/frontend/appflowy_flutter/integration_test/cloud/document_sync_test.dart b/frontend/appflowy_flutter/integration_test/cloud/document_sync_test.dart index 07fd8caccd..798b1c7473 100644 --- a/frontend/appflowy_flutter/integration_test/cloud/document_sync_test.dart +++ b/frontend/appflowy_flutter/integration_test/cloud/document_sync_test.dart @@ -35,7 +35,7 @@ void main() { email: email, ); await tester.tapGoogleLoginInButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); // create a new document called Sample await tester.createNewPageWithName( @@ -52,8 +52,7 @@ void main() { await tester.openSettings(); await tester.openSettingsPage(SettingsPage.user); - await tester.tapButton(find.byType(SettingLogoutButton)); - tester.expectToSeeText(LocaleKeys.button_ok.tr()); + await tester.logout(); }); testWidgets('sync doc from server', (tester) async { @@ -62,7 +61,7 @@ void main() { email: email, ); await tester.tapGoogleLoginInButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); await tester.pumpAndSettle(const Duration(seconds: 2)); // The document will be synced from the server diff --git a/frontend/appflowy_flutter/integration_test/cloud/supabase_auth_test.dart b/frontend/appflowy_flutter/integration_test/cloud/supabase_auth_test.dart index 34aff21fee..8079a2da69 100644 --- a/frontend/appflowy_flutter/integration_test/cloud/supabase_auth_test.dart +++ b/frontend/appflowy_flutter/integration_test/cloud/supabase_auth_test.dart @@ -15,7 +15,7 @@ void main() { testWidgets('sign in with supabase', (tester) async { await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase); await tester.tapGoogleLoginInButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); }); testWidgets('sign out with supabase', (tester) async { diff --git a/frontend/appflowy_flutter/integration_test/cloud/user_setting_sync_test.dart b/frontend/appflowy_flutter/integration_test/cloud/user_setting_sync_test.dart index 78aecf1c08..ec52540c39 100644 --- a/frontend/appflowy_flutter/integration_test/cloud/user_setting_sync_test.dart +++ b/frontend/appflowy_flutter/integration_test/cloud/user_setting_sync_test.dart @@ -36,7 +36,7 @@ void main() { email: email, ); await tester.tapGoogleLoginInButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); await tester.openSettings(); await tester.openSettingsPage(SettingsPage.user); @@ -74,7 +74,7 @@ void main() { email: email, ); await tester.tapGoogleLoginInButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); await tester.pumpAndSettle(); await tester.openSettings(); diff --git a/frontend/appflowy_flutter/integration_test/hotkeys_test.dart b/frontend/appflowy_flutter/integration_test/hotkeys_test.dart index 6cc2f484a7..3f216010e0 100644 --- a/frontend/appflowy_flutter/integration_test/hotkeys_test.dart +++ b/frontend/appflowy_flutter/integration_test/hotkeys_test.dart @@ -19,7 +19,7 @@ void main() { await tester.initializeAppFlowy(); await tester.tapGoButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); await tester.openSettings(); await tester.openSettingsPage(SettingsPage.appearance); @@ -71,7 +71,7 @@ void main() { await tester.initializeAppFlowy(); await tester.tapGoButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); await tester.pumpAndSettle(); diff --git a/frontend/appflowy_flutter/integration_test/settings/user_language_test.dart b/frontend/appflowy_flutter/integration_test/settings/user_language_test.dart index 6bc4c07bb8..d9aa28812c 100644 --- a/frontend/appflowy_flutter/integration_test/settings/user_language_test.dart +++ b/frontend/appflowy_flutter/integration_test/settings/user_language_test.dart @@ -14,7 +14,7 @@ void main() { await tester.initializeAppFlowy(); await tester.tapGoButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); await tester.openSettings(); await tester.openSettingsPage(SettingsPage.language); diff --git a/frontend/appflowy_flutter/integration_test/switch_folder_test.dart b/frontend/appflowy_flutter/integration_test/switch_folder_test.dart index ded49d3bd2..341fef0446 100644 --- a/frontend/appflowy_flutter/integration_test/switch_folder_test.dart +++ b/frontend/appflowy_flutter/integration_test/switch_folder_test.dart @@ -33,7 +33,7 @@ void main() { ); await tester.tapGoButton(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); // switch to user B { @@ -51,7 +51,7 @@ void main() { ); await tester.tapCustomLocationButton(); await tester.pumpAndSettle(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); // set user name for userB await tester.openSettings(); @@ -71,7 +71,7 @@ void main() { await tester.tapCustomLocationButton(); await tester.pumpAndSettle(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); tester.expectToSeeUserName(userA); } @@ -88,7 +88,7 @@ void main() { await tester.tapCustomLocationButton(); await tester.pumpAndSettle(); - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); tester.expectToSeeUserName(userB); } }); @@ -99,7 +99,7 @@ void main() { await tester.tapGoButton(); // home and readme document - tester.expectToSeeHomePage(); + await tester.expectToSeeHomePage(); // open settings and restore the location await tester.openSettings(); diff --git a/frontend/appflowy_flutter/integration_test/util/auth_operation.dart b/frontend/appflowy_flutter/integration_test/util/auth_operation.dart index 688a246113..1119c428e1 100644 --- a/frontend/appflowy_flutter/integration_test/util/auth_operation.dart +++ b/frontend/appflowy_flutter/integration_test/util/auth_operation.dart @@ -1,16 +1,27 @@ +import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/setting_appflowy_cloud.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/setting_supabase_cloud.dart'; +import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'base.dart'; +import 'expectation.dart'; extension AppFlowyAuthTest on WidgetTester { Future tapGoogleLoginInButton() async { await tapButton(find.byKey(const Key('signInWithGoogleButton'))); } + Future logout() async { + await tapButton(find.byType(SettingLogoutButton)); + + expectToSeeText(LocaleKeys.button_ok.tr()); + await tapButtonWithName(LocaleKeys.button_ok.tr()); + } + Future tapSignInAsGuest() async { await tapButton(find.byType(SignInAnonymousButton)); } diff --git a/frontend/appflowy_flutter/integration_test/util/base.dart b/frontend/appflowy_flutter/integration_test/util/base.dart index b34ac866f5..5df7e9edb8 100644 --- a/frontend/appflowy_flutter/integration_test/util/base.dart +++ b/frontend/appflowy_flutter/integration_test/util/base.dart @@ -15,7 +15,6 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_infra/uuid.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as p; @@ -33,21 +32,24 @@ extension AppFlowyTestBase on WidgetTester { Future initializeAppFlowy({ // use to append after the application data directory String? pathExtension, + // use to specify the application data directory, if not specified, a temporary directory will be used. + String? dataDirectory, Size windowsSize = const Size(1600, 1200), AuthenticatorType? cloudType, String? email, }) async { + // view.physicalSize = windowsSize; binding.setSurfaceSize(windowsSize); + // addTearDown(() => binding.setSurfaceSize(null)); mockHotKeyManagerHandlers(); - final directory = await mockApplicationDataStorage( - pathExtension: pathExtension, - ); - - WidgetsFlutterBinding.ensureInitialized(); + final applicationDataDirectory = dataDirectory ?? + await mockApplicationDataStorage( + pathExtension: pathExtension, + ); await FlowyRunner.run( - FlowyApp(), + AppFlowyApplication(), IntegrationMode.integrationTest, rustEnvsBuilder: () { final rustEnvs = {}; @@ -93,9 +95,10 @@ extension AppFlowyTestBase on WidgetTester { ); }, ); + await waitUntilSignInPageShow(); return FlowyTestContext( - applicationDataDirectory: directory, + applicationDataDirectory: applicationDataDirectory, ); } @@ -110,27 +113,6 @@ extension AppFlowyTestBase on WidgetTester { }); } - Future mockApplicationDataStorage({ - // use to append after the application data directory - String? pathExtension, - }) async { - final dir = await getTemporaryDirectory(); - - // Use a random uuid to avoid conflict. - String path = p.join(dir.path, 'appflowy_integration_test', uuid()); - if (pathExtension != null && pathExtension.isNotEmpty) { - path = '$path/$pathExtension'; - } - final directory = Directory(path); - if (!directory.existsSync()) { - await directory.create(recursive: true); - } - - MockApplicationDataStorage.initialPath = directory.path; - - return directory.path; - } - Future waitUntilSignInPageShow() async { if (isAuthEnabled) { final finder = find.byType(SignInAnonymousButton); @@ -143,16 +125,22 @@ extension AppFlowyTestBase on WidgetTester { } } + Future waitForSeconds(int seconds) async { + await Future.delayed((Duration(seconds: seconds)), () {}); + } + Future pumpUntilFound( Finder finder, { Duration timeout = const Duration(seconds: 10), + Duration pumpInterval = + const Duration(milliseconds: 50), // Interval between pumps }) async { bool timerDone = false; final timer = Timer(timeout, () => timerDone = true); - while (timerDone != true) { - await pump(); + while (!timerDone) { + await pump(pumpInterval); // Pump with an interval if (any(finder)) { - timerDone = true; + break; } } timer.cancel(); @@ -273,3 +261,24 @@ Future useAppFlowyCloud() async { await setAuthenticatorType(AuthenticatorType.appflowyCloud); await setAppFlowyCloudUrl(Some(TestEnv.afCloudUrl)); } + +Future mockApplicationDataStorage({ + // use to append after the application data directory + String? pathExtension, +}) async { + final dir = await getTemporaryDirectory(); + + // Use a random uuid to avoid conflict. + String path = p.join(dir.path, 'appflowy_integration_test', uuid()); + if (pathExtension != null && pathExtension.isNotEmpty) { + path = '$path/$pathExtension'; + } + final directory = Directory(path); + if (!directory.existsSync()) { + await directory.create(recursive: true); + } + + MockApplicationDataStorage.initialPath = directory.path; + + return directory.path; +} diff --git a/frontend/appflowy_flutter/integration_test/util/dir.dart b/frontend/appflowy_flutter/integration_test/util/dir.dart index 9df4871222..9dc00a57c9 100644 --- a/frontend/appflowy_flutter/integration_test/util/dir.dart +++ b/frontend/appflowy_flutter/integration_test/util/dir.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'package:path/path.dart' as p; +import 'package:archive/archive.dart'; Future deleteDirectoriesWithSameBaseNameAsPrefix( String path, @@ -28,3 +29,25 @@ Future deleteDirectoriesWithSameBaseNameAsPrefix( } } } + +Future unzipFile(File zipFile, Directory targetDirectory) async { + // Read the Zip file from disk. + final bytes = zipFile.readAsBytesSync(); + + // Decode the Zip file + final archive = ZipDecoder().decodeBytes(bytes); + + // Extract the contents of the Zip archive to disk. + for (final file in archive) { + final filename = file.name; + if (file.isFile) { + final data = file.content as List; + File(p.join(targetDirectory.path, filename)) + ..createSync(recursive: true) + ..writeAsBytesSync(data); + } else { + Directory(p.join(targetDirectory.path, filename)) + .createSync(recursive: true); + } + } +} diff --git a/frontend/appflowy_flutter/integration_test/util/expectation.dart b/frontend/appflowy_flutter/integration_test/util/expectation.dart index f9c5ebe4f5..bbe56e1d59 100644 --- a/frontend/appflowy_flutter/integration_test/util/expectation.dart +++ b/frontend/appflowy_flutter/integration_test/util/expectation.dart @@ -11,14 +11,20 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'util.dart'; + // const String readme = 'Read me'; const String gettingStarted = 'Getting started'; extension Expectation on WidgetTester { /// Expect to see the home page and with a default read me page. - void expectToSeeHomePage() { - expect(find.byType(HomeStack), findsOneWidget); - expect(find.textContaining(gettingStarted), findsWidgets); + Future expectToSeeHomePage() async { + final finder = find.byType(HomeStack); + await pumpUntilFound(finder); + expect(finder, findsOneWidget); + + final docFinder = find.textContaining(gettingStarted); + await pumpUntilFound(docFinder); } /// Expect to see the page name on the home page. diff --git a/frontend/appflowy_flutter/integration_test/util/settings.dart b/frontend/appflowy_flutter/integration_test/util/settings.dart index 68bc4d5d6d..23d9f73d44 100644 --- a/frontend/appflowy_flutter/integration_test/util/settings.dart +++ b/frontend/appflowy_flutter/integration_test/util/settings.dart @@ -1,6 +1,7 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart'; import 'package:appflowy/workspace/application/settings/prelude.dart'; +import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_user.dart'; import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart'; import 'package:appflowy/workspace/presentation/settings/widgets/settings_user_view.dart'; @@ -13,7 +14,7 @@ import 'base.dart'; extension AppFlowySettings on WidgetTester { /// Open settings page Future openSettings() async { - final settingsButton = find.byTooltip(LocaleKeys.settings_menu_open.tr()); + final settingsButton = find.byType(UserSettingButton); expect(settingsButton, findsOneWidget); await tapButton(settingsButton); final settingsDialog = find.byType(SettingsDialog); diff --git a/frontend/appflowy_flutter/lib/startup/deps_resolver.dart b/frontend/appflowy_flutter/lib/startup/deps_resolver.dart index 28f348d0c5..af7a8abe81 100644 --- a/frontend/appflowy_flutter/lib/startup/deps_resolver.dart +++ b/frontend/appflowy_flutter/lib/startup/deps_resolver.dart @@ -131,7 +131,7 @@ void _resolveUserDeps(GetIt getIt, IntegrationMode mode) { case AuthenticatorType.local: getIt.registerFactory( () => BackendAuthService( - AuthTypePB.Local, + AuthenticatorPB.Local, ), ); break; diff --git a/frontend/appflowy_flutter/lib/startup/entry_point.dart b/frontend/appflowy_flutter/lib/startup/entry_point.dart index 51350369e5..13987751b3 100644 --- a/frontend/appflowy_flutter/lib/startup/entry_point.dart +++ b/frontend/appflowy_flutter/lib/startup/entry_point.dart @@ -3,7 +3,7 @@ import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/user/presentation/screens/splash_screen.dart'; import 'package:flutter/material.dart'; -class FlowyApp implements EntryPoint { +class AppFlowyApplication implements EntryPoint { @override Widget create(LaunchConfiguration config) { return SplashScreen( diff --git a/frontend/appflowy_flutter/lib/startup/startup.dart b/frontend/appflowy_flutter/lib/startup/startup.dart index 60a8fe3f7d..1cde15681e 100644 --- a/frontend/appflowy_flutter/lib/startup/startup.dart +++ b/frontend/appflowy_flutter/lib/startup/startup.dart @@ -29,14 +29,30 @@ class FlowyRunnerContext { FlowyRunnerContext({required this.applicationDataDirectory}); } -Future runAppFlowy() async { - await FlowyRunner.run( - FlowyApp(), - integrationMode(), - ); +Future runAppFlowy({bool isAnon = false}) async { + if (kReleaseMode) { + await FlowyRunner.run( + AppFlowyApplication(), + integrationMode(), + isAnon: isAnon, + ); + } else { + // When running the app in integration test mode, we need to + // specify the mode to run the app again. + await FlowyRunner.run( + AppFlowyApplication(), + FlowyRunner.currentMode, + didInitGetItCallback: IntegrationTestHelper.didInitGetItCallback, + rustEnvsBuilder: IntegrationTestHelper.rustEnvsBuilder, + isAnon: isAnon, + ); + } } class FlowyRunner { + // This variable specifies the initial mode of the app when it is launched for the first time. + // The same mode will be automatically applied in subsequent executions when the runAppFlowy() + // method is called. static var currentMode = integrationMode(); static Future run( @@ -55,6 +71,13 @@ class FlowyRunner { bool isAnon = false, }) async { currentMode = mode; + + // Only set the mode when it's not release mode + if (!kReleaseMode) { + IntegrationTestHelper.didInitGetItCallback = didInitGetItCallback; + IntegrationTestHelper.rustEnvsBuilder = rustEnvsBuilder; + } + // Clear all the states in case of rebuilding. await getIt.reset(); @@ -220,3 +243,9 @@ IntegrationMode integrationMode() { return IntegrationMode.develop; } + +/// Only used for integration test +class IntegrationTestHelper { + static Future Function()? didInitGetItCallback; + static Map Function()? rustEnvsBuilder; +} diff --git a/frontend/appflowy_flutter/lib/startup/tasks/appflowy_cloud_task.dart b/frontend/appflowy_flutter/lib/startup/tasks/appflowy_cloud_task.dart index 67cd67abc9..d781cb6b82 100644 --- a/frontend/appflowy_flutter/lib/startup/tasks/appflowy_cloud_task.dart +++ b/frontend/appflowy_flutter/lib/startup/tasks/appflowy_cloud_task.dart @@ -87,7 +87,7 @@ class AppFlowyCloudDeepLink { (_) async { final deviceId = await getDeviceId(); final payload = OauthSignInPB( - authType: AuthTypePB.AFCloud, + authType: AuthenticatorPB.AppFlowyCloud, map: { AuthServiceMapKeys.signInURL: uri.toString(), AuthServiceMapKeys.deviceId: deviceId, diff --git a/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_auth_service.dart index d7d8b7de23..737de56eb7 100644 --- a/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_auth_service.dart +++ b/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_auth_service.dart @@ -17,7 +17,7 @@ class AppFlowyCloudAuthService implements AuthService { AppFlowyCloudAuthService(); final BackendAuthService _backendAuthService = BackendAuthService( - AuthTypePB.AFCloud, + AuthenticatorPB.AppFlowyCloud, ); @override diff --git a/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_mock_auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_mock_auth_service.dart index 8e860e2ed6..e7d45bd4ed 100644 --- a/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_mock_auth_service.dart +++ b/frontend/appflowy_flutter/lib/user/application/auth/af_cloud_mock_auth_service.dart @@ -18,7 +18,7 @@ class AppFlowyCloudMockAuthService implements AuthService { : userEmail = email ?? "${uuid()}@appflowy.io"; final BackendAuthService _appFlowyAuthService = - BackendAuthService(AuthTypePB.Supabase); + BackendAuthService(AuthenticatorPB.Supabase); @override Future> signUp({ @@ -45,7 +45,7 @@ class AppFlowyCloudMockAuthService implements AuthService { Map params = const {}, }) async { final payload = SignInUrlPayloadPB.create() - ..authType = AuthTypePB.AFCloud + ..authType = AuthenticatorPB.AppFlowyCloud // don't use nanoid here, the gotrue server will transform the email ..email = userEmail; @@ -55,7 +55,7 @@ class AppFlowyCloudMockAuthService implements AuthService { return getSignInURLResult.fold( (urlPB) async { final payload = OauthSignInPB( - authType: AuthTypePB.AFCloud, + authType: AuthenticatorPB.AppFlowyCloud, map: { AuthServiceMapKeys.signInURL: urlPB.signInUrl, AuthServiceMapKeys.deviceId: deviceId, diff --git a/frontend/appflowy_flutter/lib/user/application/auth/backend_auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/backend_auth_service.dart index d7ca4ee89f..e990cc75f8 100644 --- a/frontend/appflowy_flutter/lib/user/application/auth/backend_auth_service.dart +++ b/frontend/appflowy_flutter/lib/user/application/auth/backend_auth_service.dart @@ -14,7 +14,7 @@ import '../../../generated/locale_keys.g.dart'; import 'device_id.dart'; class BackendAuthService implements AuthService { - final AuthTypePB authType; + final AuthenticatorPB authType; BackendAuthService(this.authType); @@ -73,7 +73,7 @@ class BackendAuthService implements AuthService { ..email = userEmail ..password = password // When sign up as guest, the auth type is always local. - ..authType = AuthTypePB.Local + ..authType = AuthenticatorPB.Local ..deviceId = await getDeviceId(); final response = await UserEventSignUp(request).send().then( (value) => value.swap(), @@ -84,7 +84,7 @@ class BackendAuthService implements AuthService { @override Future> signUpWithOAuth({ required String platform, - AuthTypePB authType = AuthTypePB.Local, + AuthenticatorPB authType = AuthenticatorPB.Local, Map params = const {}, }) async { return left( diff --git a/frontend/appflowy_flutter/lib/user/application/auth/supabase_auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/supabase_auth_service.dart index bdb4ab4752..bb0a22b673 100644 --- a/frontend/appflowy_flutter/lib/user/application/auth/supabase_auth_service.dart +++ b/frontend/appflowy_flutter/lib/user/application/auth/supabase_auth_service.dart @@ -22,7 +22,7 @@ class SupabaseAuthService implements AuthService { GoTrueClient get _auth => _client.auth; final BackendAuthService _backendAuthService = BackendAuthService( - AuthTypePB.Supabase, + AuthenticatorPB.Supabase, ); @override @@ -171,7 +171,7 @@ class SupabaseAuthService implements AuthService { required Map map, }) async { final payload = OauthSignInPB( - authType: AuthTypePB.Supabase, + authType: AuthenticatorPB.Supabase, map: map, ); diff --git a/frontend/appflowy_flutter/lib/user/application/auth/supabase_mock_auth_service.dart b/frontend/appflowy_flutter/lib/user/application/auth/supabase_mock_auth_service.dart index c6863c6954..abfc0910fc 100644 --- a/frontend/appflowy_flutter/lib/user/application/auth/supabase_mock_auth_service.dart +++ b/frontend/appflowy_flutter/lib/user/application/auth/supabase_mock_auth_service.dart @@ -21,7 +21,7 @@ class SupabaseMockAuthService implements AuthService { GoTrueClient get _auth => _client.auth; final BackendAuthService _appFlowyAuthService = - BackendAuthService(AuthTypePB.Supabase); + BackendAuthService(AuthenticatorPB.Supabase); @override Future> signUp({ @@ -67,7 +67,7 @@ class SupabaseMockAuthService implements AuthService { // Create the OAuth sign-in payload. final payload = OauthSignInPB( - authType: AuthTypePB.Supabase, + authType: AuthenticatorPB.Supabase, map: { AuthServiceMapKeys.uuid: uuid, AuthServiceMapKeys.email: email, diff --git a/frontend/appflowy_flutter/lib/user/presentation/anon_user.dart b/frontend/appflowy_flutter/lib/user/presentation/anon_user.dart index bbd8f40aa5..8f63a70df6 100644 --- a/frontend/appflowy_flutter/lib/user/presentation/anon_user.dart +++ b/frontend/appflowy_flutter/lib/user/presentation/anon_user.dart @@ -72,8 +72,9 @@ class AnonUserItem extends StatelessWidget { @override Widget build(BuildContext context) { final icon = isSelected ? const FlowySvg(FlowySvgs.check_s) : null; - final isDisabled = isSelected || user.authType != AuthTypePB.Local; - final desc = "${user.name}\t ${user.authType}\t"; + final isDisabled = + isSelected || user.authenticator != AuthenticatorPB.Local; + final desc = "${user.name}\t ${user.authenticator}\t"; final child = SizedBox( height: 30, child: FlowyButton( diff --git a/frontend/appflowy_flutter/lib/user/presentation/screens/skip_log_in_screen.dart b/frontend/appflowy_flutter/lib/user/presentation/screens/skip_log_in_screen.dart index 0fb70d1820..402704cd2b 100644 --- a/frontend/appflowy_flutter/lib/user/presentation/screens/skip_log_in_screen.dart +++ b/frontend/appflowy_flutter/lib/user/presentation/screens/skip_log_in_screen.dart @@ -1,7 +1,6 @@ import 'package:appflowy/core/frameless_window.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/startup/entry_point.dart'; import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/user/application/auth/auth_service.dart'; import 'package:appflowy/user/application/anon_user_bloc.dart'; @@ -101,11 +100,7 @@ class _SkipLogInScreenState extends State { } Future _relaunchAppAndAutoRegister() async { - await FlowyRunner.run( - FlowyApp(), - integrationMode(), - isAnon: true, - ); + await runAppFlowy(isAnon: true); } } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_user.dart b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_user.dart index b8c76f34c1..31fece1055 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_user.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/sidebar_user.dart @@ -46,7 +46,7 @@ class SidebarUser extends StatelessWidget { Expanded( child: _buildUserName(context, state), ), - _buildSettingsButton(context, state), + UserSettingButton(userProfile: state.userProfile), const HSpace(4), NotificationButton(views: views), ], @@ -64,8 +64,22 @@ class SidebarUser extends StatelessWidget { ); } - Widget _buildSettingsButton(BuildContext context, MenuUserState state) { - final userProfile = state.userProfile; + /// Return the user name, if the user name is empty, return the default user name. + String _userName(UserProfilePB userProfile) { + String name = userProfile.name; + if (name.isEmpty) { + name = LocaleKeys.defaultUsername.tr(); + } + return name; + } +} + +class UserSettingButton extends StatelessWidget { + final UserProfilePB userProfile; + const UserSettingButton({required this.userProfile, super.key}); + + @override + Widget build(BuildContext context) { return FlowyTooltip( message: LocaleKeys.settings_menu_open.tr(), child: IconButton( @@ -109,13 +123,4 @@ class SidebarUser extends StatelessWidget { ), ); } - - /// Return the user name, if the user name is empty, return the default user name. - String _userName(UserProfilePB userProfile) { - String name = userProfile.name; - if (name.isEmpty) { - name = LocaleKeys.defaultUsername.tr(); - } - return name; - } } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_file_customize_location_view.dart b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_file_customize_location_view.dart index 6f7de5ccd9..86c812ee84 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_file_customize_location_view.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/settings/widgets/settings_file_customize_location_view.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:appflowy/generated/flowy_svgs.g.dart'; -import 'package:appflowy/startup/entry_point.dart'; import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/file_picker/file_picker_service.dart'; @@ -207,11 +206,7 @@ class _ChangeStoragePathButtonState extends State<_ChangeStoragePathButton> { return; } await context.read().setCustomPath(path); - await FlowyRunner.run( - FlowyApp(), - FlowyRunner.currentMode, - isAnon: true, - ); + await runAppFlowy(isAnon: true); if (mounted) { Navigator.of(context).pop(); } @@ -283,11 +278,7 @@ class _RecoverDefaultStorageButtonState await context .read() .resetDataStoragePathToApplicationDefault(); - await FlowyRunner.run( - FlowyApp(), - FlowyRunner.currentMode, - isAnon: true, - ); + await runAppFlowy(isAnon: true); if (mounted) { Navigator.of(context).pop(); } 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 a01f227815..92fb73a147 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 @@ -54,7 +54,8 @@ class SettingsUserView extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ _buildUserIconSetting(context), - if (isAuthEnabled && user.authType != AuthTypePB.Local) ...[ + if (isAuthEnabled && + user.authenticator != AuthenticatorPB.Local) ...[ const VSpace(12), UserEmailInput(user.email), ], @@ -146,7 +147,7 @@ class SettingsUserView extends StatelessWidget { } // If the user is logged in locally, render a third-party login button. - if (state.userProfile.authType == AuthTypePB.Local) { + if (state.userProfile.authenticator == AuthenticatorPB.Local) { return SettingThirdPartyLogin(didLogin: didLogin); } @@ -284,6 +285,7 @@ class UserNameInputState extends State { @override void dispose() { _controller.dispose(); + _debounce?.cancel(); super.dispose(); } } @@ -348,6 +350,7 @@ class UserEmailInputState extends State { @override void dispose() { _controller.dispose(); + _debounce?.cancel(); super.dispose(); } } diff --git a/frontend/appflowy_flutter/test/util.dart b/frontend/appflowy_flutter/test/util.dart index 9044bf1019..014f45d08a 100644 --- a/frontend/appflowy_flutter/test/util.dart +++ b/frontend/appflowy_flutter/test/util.dart @@ -35,7 +35,7 @@ class AppFlowyUnitTest { _pathProviderInitialized(); await FlowyRunner.run( - FlowyTestApp(), + AppFlowyApplicationUniTest(), IntegrationMode.unitTest, ); @@ -111,7 +111,7 @@ void _pathProviderInitialized() { }); } -class FlowyTestApp implements EntryPoint { +class AppFlowyApplicationUniTest implements EntryPoint { @override Widget create(LaunchConfiguration config) { return Container(); diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.lock b/frontend/appflowy_tauri/src-tauri/Cargo.lock index a258f965c5..71c0269702 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.lock +++ b/frontend/appflowy_tauri/src-tauri/Cargo.lock @@ -139,7 +139,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "reqwest", @@ -786,7 +786,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "app-error", @@ -883,7 +883,7 @@ dependencies = [ [[package]] name = "collab" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "async-trait", @@ -902,7 +902,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "async-trait", @@ -932,7 +932,7 @@ dependencies = [ [[package]] name = "collab-derive" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "proc-macro2", "quote", @@ -944,7 +944,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "collab", @@ -963,7 +963,7 @@ dependencies = [ [[package]] name = "collab-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "bytes", @@ -977,7 +977,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "chrono", @@ -1019,7 +1019,7 @@ dependencies = [ [[package]] name = "collab-persistence" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "async-trait", @@ -1040,7 +1040,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "async-trait", @@ -1066,7 +1066,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "collab", @@ -1471,7 +1471,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "app-error", @@ -2842,7 +2842,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "futures-util", @@ -2858,7 +2858,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "app-error", @@ -3280,7 +3280,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "reqwest", @@ -5040,7 +5040,7 @@ dependencies = [ [[package]] name = "realtime-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "bincode", @@ -5062,7 +5062,7 @@ dependencies = [ [[package]] name = "realtime-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "bincode", @@ -5809,7 +5809,7 @@ dependencies = [ [[package]] name = "shared_entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "app-error", @@ -7699,7 +7699,7 @@ dependencies = [ [[package]] name = "workspace-template" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "async-trait", diff --git a/frontend/appflowy_tauri/src-tauri/Cargo.toml b/frontend/appflowy_tauri/src-tauri/Cargo.toml index 7a83598b44..cbcc539b05 100644 --- a/frontend/appflowy_tauri/src-tauri/Cargo.toml +++ b/frontend/appflowy_tauri/src-tauri/Cargo.toml @@ -57,7 +57,7 @@ custom-protocol = ["tauri/custom-protocol"] # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5c1a16cec52e628e2fb7648455581d6fe5e84be1" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "80d4048c69a22c0af77b2f2e9b13b1004b2156e2" } # Please use the following script to update collab. # Working directory: frontend # @@ -67,14 +67,14 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5c1 # To switch to the local path, run: # scripts/tool/update_collab_source.sh # ⚠️⚠️⚠️️ -collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } +collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 2b86b72076..b68193cc94 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -125,7 +125,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "app-error" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "reqwest", @@ -667,7 +667,7 @@ dependencies = [ [[package]] name = "client-api" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "app-error", @@ -733,7 +733,7 @@ dependencies = [ [[package]] name = "collab" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "async-trait", @@ -752,7 +752,7 @@ dependencies = [ [[package]] name = "collab-database" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "async-trait", @@ -782,7 +782,7 @@ dependencies = [ [[package]] name = "collab-derive" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "proc-macro2", "quote", @@ -794,7 +794,7 @@ dependencies = [ [[package]] name = "collab-document" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "collab", @@ -813,7 +813,7 @@ dependencies = [ [[package]] name = "collab-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "bytes", @@ -827,7 +827,7 @@ dependencies = [ [[package]] name = "collab-folder" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "chrono", @@ -869,7 +869,7 @@ dependencies = [ [[package]] name = "collab-persistence" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "async-trait", @@ -890,7 +890,7 @@ dependencies = [ [[package]] name = "collab-plugins" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "async-trait", @@ -916,7 +916,7 @@ dependencies = [ [[package]] name = "collab-user" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=0e117f568bd2465762582f6aeb8d9c11fe714e63#0e117f568bd2465762582f6aeb8d9c11fe714e63" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=d5324139e6450e32246520416af768202f544869#d5324139e6450e32246520416af768202f544869" dependencies = [ "anyhow", "collab", @@ -1277,7 +1277,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "database-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "app-error", @@ -2483,7 +2483,7 @@ dependencies = [ [[package]] name = "gotrue" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "futures-util", @@ -2499,7 +2499,7 @@ dependencies = [ [[package]] name = "gotrue-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "app-error", @@ -2860,7 +2860,7 @@ dependencies = [ [[package]] name = "infra" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "reqwest", @@ -4329,7 +4329,7 @@ dependencies = [ [[package]] name = "realtime-entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "bincode", @@ -4351,7 +4351,7 @@ dependencies = [ [[package]] name = "realtime-protocol" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "bincode", @@ -5020,7 +5020,7 @@ dependencies = [ [[package]] name = "shared_entity" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "app-error", @@ -6401,7 +6401,7 @@ dependencies = [ [[package]] name = "workspace-template" version = "0.1.0" -source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=5c1a16cec52e628e2fb7648455581d6fe5e84be1#5c1a16cec52e628e2fb7648455581d6fe5e84be1" +source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2" dependencies = [ "anyhow", "async-trait", diff --git a/frontend/rust-lib/Cargo.toml b/frontend/rust-lib/Cargo.toml index 0204a1f1a9..55d0e492d3 100644 --- a/frontend/rust-lib/Cargo.toml +++ b/frontend/rust-lib/Cargo.toml @@ -99,7 +99,7 @@ incremental = false # Run the script: # scripts/tool/update_client_api_rev.sh new_rev_id # ⚠️⚠️⚠️️ -client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5c1a16cec52e628e2fb7648455581d6fe5e84be1" } +client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "80d4048c69a22c0af77b2f2e9b13b1004b2156e2" } # Please use the following script to update collab. # Working directory: frontend # @@ -109,11 +109,11 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "5c1 # To switch to the local path, run: # scripts/tool/update_collab_source.sh # ⚠️⚠️⚠️️ -collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } -collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "0e117f568bd2465762582f6aeb8d9c11fe714e63" } +collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } +collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "d5324139e6450e32246520416af768202f544869" } diff --git a/frontend/rust-lib/dart-ffi/Cargo.toml b/frontend/rust-lib/dart-ffi/Cargo.toml index 7379e52be9..8e2caeb021 100644 --- a/frontend/rust-lib/dart-ffi/Cargo.toml +++ b/frontend/rust-lib/dart-ffi/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [lib] name = "dart_ffi" # this value will change depending on the target os -# default staticlib +# default static library crate-type = ["staticlib"] diff --git a/frontend/rust-lib/event-integration/src/lib.rs b/frontend/rust-lib/event-integration/src/lib.rs index a0d315a027..6ac0fb5f4e 100644 --- a/frontend/rust-lib/event-integration/src/lib.rs +++ b/frontend/rust-lib/event-integration/src/lib.rs @@ -8,7 +8,7 @@ use parking_lot::RwLock; use flowy_core::config::AppFlowyCoreConfig; use flowy_core::AppFlowyCore; use flowy_notification::register_notification_sender; -use flowy_user::entities::AuthTypePB; +use flowy_user::entities::AuthenticatorPB; use crate::user_event::TestNotificationSender; @@ -21,7 +21,7 @@ pub mod user_event; #[derive(Clone)] pub struct EventIntegrationTest { - pub auth_type: Arc>, + pub auth_type: Arc>, pub inner: AppFlowyCore, #[allow(dead_code)] cleaner: Arc, @@ -48,7 +48,7 @@ impl EventIntegrationTest { let inner = init_core(config).await; let notification_sender = TestNotificationSender::new(); - let auth_type = Arc::new(RwLock::new(AuthTypePB::Local)); + let auth_type = Arc::new(RwLock::new(AuthenticatorPB::Local)); register_notification_sender(notification_sender.clone()); std::mem::forget(inner.dispatcher()); Self { diff --git a/frontend/rust-lib/event-integration/src/user_event.rs b/frontend/rust-lib/event-integration/src/user_event.rs index 0c8dfb0003..c133b98954 100644 --- a/frontend/rust-lib/event-integration/src/user_event.rs +++ b/frontend/rust-lib/event-integration/src/user_event.rs @@ -15,7 +15,7 @@ use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_SIGN_IN_UR use flowy_server_config::af_cloud_config::AFCloudConfiguration; use flowy_server_config::AuthenticatorType; use flowy_user::entities::{ - AuthTypePB, CloudSettingPB, OauthSignInPB, SignInUrlPB, SignInUrlPayloadPB, SignUpPayloadPB, + AuthenticatorPB, CloudSettingPB, OauthSignInPB, SignInUrlPB, SignInUrlPayloadPB, SignUpPayloadPB, UpdateCloudConfigPB, UpdateUserProfilePayloadPB, UserProfilePB, }; use flowy_user::errors::{FlowyError, FlowyResult}; @@ -59,7 +59,7 @@ impl EventIntegrationTest { email, name: "appflowy".to_string(), password: password.clone(), - auth_type: AuthTypePB::Local, + auth_type: AuthenticatorPB::Local, device_id: uuid::Uuid::new_v4().to_string(), } .into_bytes() @@ -88,7 +88,7 @@ impl EventIntegrationTest { let map = third_party_sign_up_param(Uuid::new_v4().to_string()); let payload = OauthSignInPB { map, - auth_type: AuthTypePB::Supabase, + auth_type: AuthenticatorPB::Supabase, }; EventBuilder::new(self.clone()) @@ -106,7 +106,7 @@ impl EventIntegrationTest { .await; } - pub fn set_auth_type(&self, auth_type: AuthTypePB) { + pub fn set_auth_type(&self, auth_type: AuthenticatorPB) { *self.auth_type.write() = auth_type; } @@ -133,7 +133,7 @@ impl EventIntegrationTest { pub async fn af_cloud_sign_in_with_email(&self, email: &str) -> FlowyResult { let payload = SignInUrlPayloadPB { email: email.to_string(), - auth_type: AuthTypePB::AFCloud, + auth_type: AuthenticatorPB::AppFlowyCloud, }; let sign_in_url = EventBuilder::new(self.clone()) .event(GenerateSignInURL) @@ -148,7 +148,7 @@ impl EventIntegrationTest { map.insert(USER_DEVICE_ID.to_string(), Uuid::new_v4().to_string()); let payload = OauthSignInPB { map, - auth_type: AuthTypePB::AFCloud, + auth_type: AuthenticatorPB::AppFlowyCloud, }; let user_profile = EventBuilder::new(self.clone()) @@ -175,7 +175,7 @@ impl EventIntegrationTest { ); let payload = OauthSignInPB { map, - auth_type: AuthTypePB::Supabase, + auth_type: AuthenticatorPB::Supabase, }; let user_profile = EventBuilder::new(self.clone()) diff --git a/frontend/rust-lib/event-integration/tests/user/af_cloud_test/anon_user_test.rs b/frontend/rust-lib/event-integration/tests/user/af_cloud_test/anon_user_test.rs index 975292da61..9827164f62 100644 --- a/frontend/rust-lib/event-integration/tests/user/af_cloud_test/anon_user_test.rs +++ b/frontend/rust-lib/event-integration/tests/user/af_cloud_test/anon_user_test.rs @@ -1,9 +1,7 @@ -use event_integration::user_event::user_localhost_af_cloud; use event_integration::EventIntegrationTest; use flowy_core::DEFAULT_NAME; -use flowy_user::entities::AuthTypePB; -use crate::util::{get_af_cloud_config, unzip_history_user_db}; +use crate::util::unzip_history_user_db; #[tokio::test] async fn reading_039_anon_user_data_test() { @@ -36,70 +34,43 @@ async fn reading_039_anon_user_data_test() { drop(cleaner); } -#[tokio::test] -async fn anon_user_to_af_cloud_test() { - if get_af_cloud_config().is_none() { - return; - } - let (cleaner, user_db_path) = unzip_history_user_db("./tests/asset", "039_local").unwrap(); - user_localhost_af_cloud().await; - let test = - EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await; - let anon_first_level_views = test.get_all_workspace_views().await; - let _anon_second_level_views = test - .get_views(&anon_first_level_views[0].id) - .await - .child_views; - - let user = test.af_cloud_sign_up().await; - assert_eq!(user.auth_type, AuthTypePB::AFCloud); - // let mut sync_state = test - // .folder_manager - // .get_mutex_folder() - // .lock() - // .as_ref() - // .unwrap() - // .subscribe_sync_state(); - // - // // TODO(nathan): will be removed when supporting merge FolderData - // // wait until the state is SyncFinished with 10 secs timeout - // loop { - // select! { - // _ = tokio::time::sleep(Duration::from_secs(10)) => { - // panic!("Timeout waiting for sync finished"); - // } - // state = sync_state.next() => { - // if let Some(state) = &state { - // if state == &SyncState::SyncFinished { - // break; - // } - // } - // } - // } - // } - // - // let user_first_level_views = test.get_all_workspace_views().await; - // let user_second_level_views = test - // .get_views(&user_first_level_views[1].id) - // .await - // .child_views; - // - // // first - // assert_eq!(anon_first_level_views.len(), 1); - // assert_eq!(user_first_level_views.len(), 2); - // assert_eq!( - // anon_first_level_views[0].name, - // // The first one is the get started document - // user_first_level_views[1].name - // ); - // assert_ne!(anon_first_level_views[0].id, user_first_level_views[1].id); - // - // // second - // assert_eq!(anon_second_level_views.len(), user_second_level_views.len()); - // assert_eq!( - // anon_second_level_views[0].name, - // user_second_level_views[0].name - // ); - // assert_ne!(anon_second_level_views[0].id, user_second_level_views[0].id); - drop(cleaner); -} +// #[tokio::test] +// async fn migrate_anon_user_data_to_af_cloud_test() { +// let (cleaner, user_db_path) = unzip_history_user_db("./tests/asset", "039_local").unwrap(); +// user_localhost_af_cloud().await; +// let test = +// EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await; +// let anon_first_level_views = test.get_all_workspace_views().await; +// let anon_second_level_views = test +// .get_views(&anon_first_level_views[0].id) +// .await +// .child_views; +// +// // The anon user data will be migrated to the AppFlowy cloud after sign up +// let user = test.af_cloud_sign_up().await; +// assert_eq!(user.authenticator, AuthenticatorPB::AppFlowyCloud); +// +// let user_first_level_views = test.get_all_workspace_views().await; +// let user_second_level_views = test +// .get_views(&user_first_level_views[0].id) +// .await +// .child_views; +// +// // first +// assert_eq!(anon_first_level_views.len(), 1); +// assert_eq!(user_first_level_views.len(), 1); +// assert_eq!( +// anon_first_level_views[0].name, +// user_first_level_views[0].name +// ); +// assert_ne!(anon_first_level_views[0].id, user_first_level_views[0].id); +// +// // second +// assert_eq!(anon_second_level_views.len(), user_second_level_views.len()); +// assert_eq!( +// anon_second_level_views[0].name, +// user_second_level_views[0].name +// ); +// assert_ne!(anon_second_level_views[0].id, user_second_level_views[0].id); +// drop(cleaner); +// } diff --git a/frontend/rust-lib/event-integration/tests/user/local_test/auth_test.rs b/frontend/rust-lib/event-integration/tests/user/local_test/auth_test.rs index bb864cc3b0..010a88d484 100644 --- a/frontend/rust-lib/event-integration/tests/user/local_test/auth_test.rs +++ b/frontend/rust-lib/event-integration/tests/user/local_test/auth_test.rs @@ -1,6 +1,6 @@ use event_integration::user_event::{login_password, unique_email}; use event_integration::{event_builder::EventBuilder, EventIntegrationTest}; -use flowy_user::entities::{AuthTypePB, SignInPayloadPB, SignUpPayloadPB}; +use flowy_user::entities::{AuthenticatorPB, SignInPayloadPB, SignUpPayloadPB}; use flowy_user::errors::ErrorCode; use flowy_user::event_map::UserEvent::*; @@ -14,7 +14,7 @@ async fn sign_up_with_invalid_email() { email: email.to_string(), name: valid_name(), password: login_password(), - auth_type: AuthTypePB::Local, + auth_type: AuthenticatorPB::Local, device_id: "".to_string(), }; @@ -38,7 +38,7 @@ async fn sign_up_with_long_password() { email: unique_email(), name: valid_name(), password: "1234".repeat(100).as_str().to_string(), - auth_type: AuthTypePB::Local, + auth_type: AuthenticatorPB::Local, device_id: "".to_string(), }; @@ -63,7 +63,7 @@ async fn sign_in_with_invalid_email() { email: email.to_string(), password: login_password(), name: "".to_string(), - auth_type: AuthTypePB::Local, + auth_type: AuthenticatorPB::Local, device_id: "".to_string(), }; @@ -90,7 +90,7 @@ async fn sign_in_with_invalid_password() { email: unique_email(), password, name: "".to_string(), - auth_type: AuthTypePB::Local, + auth_type: AuthenticatorPB::Local, device_id: "".to_string(), }; diff --git a/frontend/rust-lib/event-integration/tests/user/local_test/user_profile_test.rs b/frontend/rust-lib/event-integration/tests/user/local_test/user_profile_test.rs index 7418b267af..17274059b3 100644 --- a/frontend/rust-lib/event-integration/tests/user/local_test/user_profile_test.rs +++ b/frontend/rust-lib/event-integration/tests/user/local_test/user_profile_test.rs @@ -1,7 +1,7 @@ use nanoid::nanoid; use event_integration::{event_builder::EventBuilder, EventIntegrationTest}; -use flowy_user::entities::{AuthTypePB, UpdateUserProfilePayloadPB, UserProfilePB}; +use flowy_user::entities::{AuthenticatorPB, UpdateUserProfilePayloadPB, UserProfilePB}; use flowy_user::{errors::ErrorCode, event_map::UserEvent::*}; use crate::user::local_test::helper::*; @@ -32,7 +32,7 @@ async fn anon_user_profile_get() { assert_eq!(user_profile.openai_key, user.openai_key); assert_eq!(user_profile.stability_ai_key, user.stability_ai_key); assert_eq!(user_profile.workspace_id, user.workspace_id); - assert_eq!(user_profile.auth_type, AuthTypePB::Local); + assert_eq!(user_profile.authenticator, AuthenticatorPB::Local); } #[tokio::test] diff --git a/frontend/rust-lib/event-integration/tests/user/supabase_test/auth_test.rs b/frontend/rust-lib/event-integration/tests/user/supabase_test/auth_test.rs index 53a0d71179..5f5479a86b 100644 --- a/frontend/rust-lib/event-integration/tests/user/supabase_test/auth_test.rs +++ b/frontend/rust-lib/event-integration/tests/user/supabase_test/auth_test.rs @@ -14,7 +14,9 @@ use event_integration::EventIntegrationTest; use flowy_core::DEFAULT_NAME; use flowy_encrypt::decrypt_text; use flowy_server::supabase::define::{USER_DEVICE_ID, USER_EMAIL, USER_UUID}; -use flowy_user::entities::{AuthTypePB, OauthSignInPB, UpdateUserProfilePayloadPB, UserProfilePB}; +use flowy_user::entities::{ + AuthenticatorPB, OauthSignInPB, UpdateUserProfilePayloadPB, UserProfilePB, +}; use flowy_user::errors::ErrorCode; use flowy_user::event_map::UserEvent::*; @@ -33,7 +35,7 @@ async fn third_party_sign_up_test() { map.insert(USER_DEVICE_ID.to_string(), uuid::Uuid::new_v4().to_string()); let payload = OauthSignInPB { map, - auth_type: AuthTypePB::Supabase, + auth_type: AuthenticatorPB::Supabase, }; let response = EventBuilder::new(test.clone()) @@ -77,7 +79,7 @@ async fn third_party_sign_up_with_duplicated_uuid() { .event(OauthSignIn) .payload(OauthSignInPB { map: map.clone(), - auth_type: AuthTypePB::Supabase, + auth_type: AuthenticatorPB::Supabase, }) .async_send() .await @@ -88,7 +90,7 @@ async fn third_party_sign_up_with_duplicated_uuid() { .event(OauthSignIn) .payload(OauthSignInPB { map: map.clone(), - auth_type: AuthTypePB::Supabase, + auth_type: AuthenticatorPB::Supabase, }) .async_send() .await diff --git a/frontend/rust-lib/event-integration/tests/user/supabase_test/workspace_test.rs b/frontend/rust-lib/event-integration/tests/user/supabase_test/workspace_test.rs index 543e76f262..ccd1d6fb03 100644 --- a/frontend/rust-lib/event-integration/tests/user/supabase_test/workspace_test.rs +++ b/frontend/rust-lib/event-integration/tests/user/supabase_test/workspace_test.rs @@ -4,7 +4,7 @@ use event_integration::{event_builder::EventBuilder, EventIntegrationTest}; use flowy_folder2::entities::WorkspaceSettingPB; use flowy_folder2::event_map::FolderEvent::GetCurrentWorkspaceSetting; use flowy_server::supabase::define::{USER_EMAIL, USER_UUID}; -use flowy_user::entities::{AuthTypePB, OauthSignInPB, UserProfilePB}; +use flowy_user::entities::{AuthenticatorPB, OauthSignInPB, UserProfilePB}; use flowy_user::event_map::UserEvent::*; use crate::util::*; @@ -21,7 +21,7 @@ async fn initial_workspace_test() { ); let payload = OauthSignInPB { map, - auth_type: AuthTypePB::Supabase, + auth_type: AuthenticatorPB::Supabase, }; let _ = EventBuilder::new(test.clone()) diff --git a/frontend/rust-lib/event-integration/tests/util.rs b/frontend/rust-lib/event-integration/tests/util.rs index c62b58360c..0491fe4851 100644 --- a/frontend/rust-lib/event-integration/tests/util.rs +++ b/frontend/rust-lib/event-integration/tests/util.rs @@ -23,7 +23,7 @@ use flowy_server::supabase::api::*; use flowy_server::{AppFlowyEncryption, EncryptionImpl}; use flowy_server_config::af_cloud_config::AFCloudConfiguration; use flowy_server_config::supabase_config::SupabaseConfiguration; -use flowy_user::entities::{AuthTypePB, UpdateUserProfilePayloadPB}; +use flowy_user::entities::{AuthenticatorPB, UpdateUserProfilePayloadPB}; use flowy_user::errors::FlowyError; use flowy_user::event_map::UserCloudServiceProvider; use flowy_user::event_map::UserEvent::*; @@ -43,7 +43,7 @@ impl FlowySupabaseTest { pub async fn new() -> Option { let _ = get_supabase_config()?; let test = EventIntegrationTest::new().await; - test.set_auth_type(AuthTypePB::Supabase); + test.set_auth_type(AuthenticatorPB::Supabase); test .server_provider .set_authenticator(Authenticator::Supabase); @@ -210,7 +210,7 @@ impl AFCloudTest { pub async fn new() -> Option { let _ = get_af_cloud_config()?; let test = EventIntegrationTest::new().await; - test.set_auth_type(AuthTypePB::AFCloud); + test.set_auth_type(AuthenticatorPB::AppFlowyCloud); test .server_provider .set_authenticator(Authenticator::AppFlowyCloud); diff --git a/frontend/rust-lib/flowy-core/src/integrate/server.rs b/frontend/rust-lib/flowy-core/src/integrate/server.rs index 8c1f8c00aa..8b1ae63866 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/server.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/server.rs @@ -22,25 +22,25 @@ pub(crate) const SERVER_PROVIDER_TYPE_KEY: &str = "server_provider_type"; #[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize_repr, Deserialize_repr)] #[repr(u8)] -pub enum ServerType { +pub enum Server { /// Local server provider. /// Offline mode, no user authentication and the data is stored locally. Local = 0, /// AppFlowy Cloud server provider. /// The [AppFlowy-Server](https://github.com/AppFlowy-IO/AppFlowy-Cloud) is still a work in /// progress. - AFCloud = 1, + AppFlowyCloud = 1, /// Supabase server provider. /// It uses supabase postgresql database to store data and user authentication. Supabase = 2, } -impl Display for ServerType { +impl Display for Server { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - ServerType::Local => write!(f, "Local"), - ServerType::AFCloud => write!(f, "AppFlowyCloud"), - ServerType::Supabase => write!(f, "Supabase"), + Server::Local => write!(f, "Local"), + Server::AppFlowyCloud => write!(f, "AppFlowyCloud"), + Server::Supabase => write!(f, "Supabase"), } } } @@ -51,8 +51,8 @@ impl Display for ServerType { /// Each server implements the [AppFlowyServer] trait, which provides the [UserCloudService], etc. pub struct ServerProvider { config: AppFlowyCoreConfig, - server_type: RwLock, - providers: RwLock>>, + server: RwLock, + providers: RwLock>>, pub(crate) encryption: RwLock>, pub(crate) store_preferences: Weak, pub(crate) enable_sync: RwLock, @@ -62,13 +62,13 @@ pub struct ServerProvider { impl ServerProvider { pub fn new( config: AppFlowyCoreConfig, - server_type: ServerType, + server: Server, store_preferences: Weak, ) -> Self { let encryption = EncryptionImpl::new(None); Self { config, - server_type: RwLock::new(server_type), + server: RwLock::new(server), providers: RwLock::new(HashMap::new()), enable_sync: RwLock::new(true), encryption: RwLock::new(Arc::new(encryption)), @@ -77,37 +77,34 @@ impl ServerProvider { } } - pub fn get_server_type(&self) -> ServerType { - self.server_type.read().clone() + pub fn get_server_type(&self) -> Server { + self.server.read().clone() } - pub fn set_server_type(&self, server_type: ServerType) { - let old_server_type = self.server_type.read().clone(); + pub fn set_server_type(&self, server_type: Server) { + let old_server_type = self.server.read().clone(); if server_type != old_server_type { self.providers.write().remove(&old_server_type); } - *self.server_type.write() = server_type; + *self.server.write() = server_type; } /// Returns a [AppFlowyServer] trait implementation base on the provider_type. - pub(crate) fn get_server( - &self, - server_type: &ServerType, - ) -> FlowyResult> { + pub(crate) fn get_server(&self, server_type: &Server) -> FlowyResult> { if let Some(provider) = self.providers.read().get(server_type) { return Ok(provider.clone()); } let server = match server_type { - ServerType::Local => { + Server::Local => { let local_db = Arc::new(LocalServerDBImpl { storage_path: self.config.storage_path.clone(), }); let server = Arc::new(LocalServer::new(local_db)); Ok::, FlowyError>(server) }, - ServerType::AFCloud => { + Server::AppFlowyCloud => { let config = AFCloudConfiguration::from_env()?; let server = Arc::new(AppFlowyCloudServer::new( config, @@ -117,7 +114,7 @@ impl ServerProvider { Ok::, FlowyError>(server) }, - ServerType::Supabase => { + Server::Supabase => { let config = SupabaseConfiguration::from_env()?; let uid = self.uid.clone(); tracing::trace!("🔑Supabase config: {:?}", config); @@ -140,36 +137,35 @@ impl ServerProvider { } } -impl From for ServerType { +impl From for Server { fn from(auth_provider: Authenticator) -> Self { match auth_provider { - Authenticator::Local => ServerType::Local, - Authenticator::AppFlowyCloud => ServerType::AFCloud, - Authenticator::Supabase => ServerType::Supabase, + Authenticator::Local => Server::Local, + Authenticator::AppFlowyCloud => Server::AppFlowyCloud, + Authenticator::Supabase => Server::Supabase, } } } -impl From for Authenticator { - fn from(ty: ServerType) -> Self { +impl From for Authenticator { + fn from(ty: Server) -> Self { match ty { - ServerType::Local => Authenticator::Local, - ServerType::AFCloud => Authenticator::AppFlowyCloud, - ServerType::Supabase => Authenticator::Supabase, + Server::Local => Authenticator::Local, + Server::AppFlowyCloud => Authenticator::AppFlowyCloud, + Server::Supabase => Authenticator::Supabase, } } } -impl From<&Authenticator> for ServerType { +impl From<&Authenticator> for Server { fn from(auth_provider: &Authenticator) -> Self { Self::from(auth_provider.clone()) } } -pub fn current_server_type(store_preferences: &Arc) -> ServerType { - match store_preferences.get_object::(SERVER_PROVIDER_TYPE_KEY) { - None => ServerType::Local, - Some(provider_type) => provider_type, - } +pub fn current_server_type(store_preferences: &Arc) -> Server { + store_preferences + .get_object::(SERVER_PROVIDER_TYPE_KEY) + .unwrap_or(Server::Local) } struct LocalServerDBImpl { diff --git a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs index 26607a5b67..f3ff03a328 100644 --- a/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs +++ b/frontend/rust-lib/flowy-core/src/integrate/trait_impls.rs @@ -30,7 +30,7 @@ use flowy_user_deps::cloud::UserCloudService; use flowy_user_deps::entities::{Authenticator, UserTokenState}; use lib_infra::future::{to_fut, Fut, FutureResult}; -use crate::integrate::server::{ServerProvider, ServerType, SERVER_PROVIDER_TYPE_KEY}; +use crate::integrate::server::{Server, ServerProvider, SERVER_PROVIDER_TYPE_KEY}; impl FileStorageService for ServerProvider { fn create_object(&self, object: StorageObject) -> FutureResult { @@ -91,12 +91,12 @@ impl UserCloudServiceProvider for ServerProvider { /// When user login, the provider type is set by the [Authenticator] and save to disk for next use. /// - /// Each [Authenticator] has a corresponding [ServerType]. The [ServerType] is used - /// to create a new [AppFlowyServer] if it doesn't exist. Once the [ServerType] is set, + /// Each [Authenticator] has a corresponding [Server]. The [Server] is used + /// to create a new [AppFlowyServer] if it doesn't exist. Once the [Server] is set, /// it will be used when user open the app again. /// fn set_authenticator(&self, authenticator: Authenticator) { - let server_type: ServerType = authenticator.into(); + let server_type: Server = authenticator.into(); self.set_server_type(server_type.clone()); match self.store_preferences.upgrade() { @@ -117,7 +117,7 @@ impl UserCloudServiceProvider for ServerProvider { Authenticator::from(server_type) } - /// Returns the [UserCloudService] base on the current [ServerType]. + /// Returns the [UserCloudService] base on the current [Server]. /// Creates a new [AppFlowyServer] if it doesn't exist. fn get_user_service(&self) -> Result, FlowyError> { let server_type = self.get_server_type(); @@ -127,11 +127,11 @@ impl UserCloudServiceProvider for ServerProvider { fn service_url(&self) -> String { match self.get_server_type() { - ServerType::Local => "".to_string(), - ServerType::AFCloud => AFCloudConfiguration::from_env() + Server::Local => "".to_string(), + Server::AppFlowyCloud => AFCloudConfiguration::from_env() .map(|config| config.base_url) .unwrap_or_default(), - ServerType::Supabase => SupabaseConfiguration::from_env() + Server::Supabase => SupabaseConfiguration::from_env() .map(|config| config.url) .unwrap_or_default(), } @@ -325,7 +325,7 @@ impl CollabStorageProvider for ServerProvider { collab_object, local_collab, } => { - if let Ok(server) = self.get_server(&ServerType::AFCloud) { + if let Ok(server) = self.get_server(&Server::AppFlowyCloud) { to_fut(async move { let mut plugins: Vec> = vec![]; match server.collab_ws_channel(&collab_object.object_id).await { @@ -373,7 +373,7 @@ impl CollabStorageProvider for ServerProvider { } => { let mut plugins: Vec> = vec![]; if let Some(remote_collab_storage) = self - .get_server(&ServerType::Supabase) + .get_server(&Server::Supabase) .ok() .and_then(|provider| provider.collab_storage(&collab_object)) { diff --git a/frontend/rust-lib/flowy-core/src/lib.rs b/frontend/rust-lib/flowy-core/src/lib.rs index c9b5b68d2f..2563fbc0d2 100644 --- a/frontend/rust-lib/flowy-core/src/lib.rs +++ b/frontend/rust-lib/flowy-core/src/lib.rs @@ -26,7 +26,7 @@ use crate::deps_resolve::collab_backup::RocksdbBackupImpl; use crate::deps_resolve::*; use crate::integrate::collab_interact::CollabInteractImpl; use crate::integrate::log::init_log; -use crate::integrate::server::{current_server_type, ServerProvider, ServerType}; +use crate::integrate::server::{current_server_type, Server, ServerProvider}; use crate::integrate::user::UserStatusCallbackImpl; pub mod config; @@ -232,12 +232,12 @@ fn init_user_manager( ) } -impl From for CollabDataSource { - fn from(server_type: ServerType) -> Self { +impl From for CollabDataSource { + fn from(server_type: Server) -> Self { match server_type { - ServerType::Local => CollabDataSource::Local, - ServerType::AFCloud => CollabDataSource::AppFlowyCloud, - ServerType::Supabase => CollabDataSource::Supabase, + Server::Local => CollabDataSource::Local, + Server::AppFlowyCloud => CollabDataSource::AppFlowyCloud, + Server::Supabase => CollabDataSource::Supabase, } } } diff --git a/frontend/rust-lib/flowy-document2/src/parser/utils.rs b/frontend/rust-lib/flowy-document2/src/parser/utils.rs index 59719d7311..e5365f2227 100644 --- a/frontend/rust-lib/flowy-document2/src/parser/utils.rs +++ b/frontend/rust-lib/flowy-document2/src/parser/utils.rs @@ -5,7 +5,6 @@ use collab_document::blocks::DocumentData; use serde_json::Value; use std::collections::HashMap; use std::sync::Arc; -use tracing::trace; use validator::ValidationError; pub fn get_delta_for_block(block_id: &str, data: &DocumentData) -> Option> { diff --git a/frontend/rust-lib/flowy-folder2/src/manager.rs b/frontend/rust-lib/flowy-folder2/src/manager.rs index 372f6951b1..e42c1198a5 100644 --- a/frontend/rust-lib/flowy-folder2/src/manager.rs +++ b/frontend/rust-lib/flowy-folder2/src/manager.rs @@ -47,9 +47,6 @@ pub struct FolderManager { pub cloud_service: Arc, } -unsafe impl Send for FolderManager {} -unsafe impl Sync for FolderManager {} - impl FolderManager { pub async fn new( user: Arc, @@ -1012,8 +1009,8 @@ impl FolderManager { /// Return the views that belong to the workspace. The views are filtered by the trash. pub(crate) fn get_workspace_view_pbs(_workspace_id: &str, folder: &Folder) -> Vec { - let trash_ids = folder - .get_all_trash() + let items = folder.get_all_trash(); + let trash_ids = items .into_iter() .map(|trash| trash.id) .collect::>(); diff --git a/frontend/rust-lib/flowy-folder2/src/manager_init.rs b/frontend/rust-lib/flowy-folder2/src/manager_init.rs index f7d61a4306..55f3c52506 100644 --- a/frontend/rust-lib/flowy-folder2/src/manager_init.rs +++ b/frontend/rust-lib/flowy-folder2/src/manager_init.rs @@ -37,10 +37,10 @@ impl FolderManager { let collab_db = self.user.collab_db(uid)?; let (view_tx, view_rx) = tokio::sync::broadcast::channel(100); - let (trash_tx, trash_rx) = tokio::sync::broadcast::channel(100); + let (section_change_tx, section_change_rx) = tokio::sync::broadcast::channel(100); let folder_notifier = FolderNotify { view_change_tx: view_tx, - trash_change_tx: trash_tx, + section_change_tx, }; let folder = match initial_data { @@ -99,7 +99,7 @@ impl FolderManager { let weak_mutex_folder = Arc::downgrade(&self.mutex_folder); subscribe_folder_sync_state_changed(workspace_id.clone(), folder_state_rx, &weak_mutex_folder); subscribe_folder_snapshot_state_changed(workspace_id, &weak_mutex_folder); - subscribe_folder_trash_changed(trash_rx, &weak_mutex_folder); + subscribe_folder_trash_changed(section_change_rx, &weak_mutex_folder); subscribe_folder_view_changed(view_rx, &weak_mutex_folder); Ok(()) } diff --git a/frontend/rust-lib/flowy-folder2/src/manager_observer.rs b/frontend/rust-lib/flowy-folder2/src/manager_observer.rs index ed18cf25ab..6209aadcc4 100644 --- a/frontend/rust-lib/flowy-folder2/src/manager_observer.rs +++ b/frontend/rust-lib/flowy-folder2/src/manager_observer.rs @@ -3,7 +3,8 @@ use std::sync::{Arc, Weak}; use collab::core::collab_state::SyncState; use collab_folder::{ - Folder, TrashChange, TrashChangeReceiver, View, ViewChange, ViewChangeReceiver, + Folder, SectionChange, SectionChangeReceiver, TrashSectionChange, View, ViewChange, + ViewChangeReceiver, }; use tokio_stream::wrappers::WatchStream; use tokio_stream::StreamExt; @@ -102,7 +103,7 @@ pub(crate) fn subscribe_folder_sync_state_changed( /// Listen on the [TrashChange]s and notify the frontend some views were changed. pub(crate) fn subscribe_folder_trash_changed( - mut rx: TrashChangeReceiver, + mut rx: SectionChangeReceiver, weak_mutex_folder: &Weak, ) { let weak_mutex_folder = weak_mutex_folder.clone(); @@ -111,25 +112,29 @@ pub(crate) fn subscribe_folder_trash_changed( if let Some(folder) = weak_mutex_folder.upgrade() { let mut unique_ids = HashSet::new(); tracing::trace!("Did receive trash change: {:?}", value); - let ids = match value { - TrashChange::DidCreateTrash { ids } => ids, - TrashChange::DidDeleteTrash { ids } => ids, - }; - if let Some(folder) = folder.lock().as_ref() { - let views = folder.views.get_views(&ids); - for view in views { - unique_ids.insert(view.parent_view_id.clone()); - } + match value { + SectionChange::Trash(change) => { + let ids = match change { + TrashSectionChange::TrashItemAdded { ids } => ids, + TrashSectionChange::TrashItemRemoved { ids } => ids, + }; + if let Some(folder) = folder.lock().as_ref() { + let views = folder.views.get_views(&ids); + for view in views { + unique_ids.insert(view.parent_view_id.clone()); + } - let repeated_trash: RepeatedTrashPB = folder.get_all_trash().into(); - send_notification("trash", FolderNotification::DidUpdateTrash) - .payload(repeated_trash) - .send(); + let repeated_trash: RepeatedTrashPB = folder.get_all_trash().into(); + send_notification("trash", FolderNotification::DidUpdateTrash) + .payload(repeated_trash) + .send(); + } + + let parent_view_ids = unique_ids.into_iter().collect(); + notify_parent_view_did_change(folder.clone(), parent_view_ids); + }, } - - let parent_view_ids = unique_ids.into_iter().collect(); - notify_parent_view_did_change(folder.clone(), parent_view_ids); } } }); diff --git a/frontend/rust-lib/flowy-folder2/src/user_default.rs b/frontend/rust-lib/flowy-folder2/src/user_default.rs index 910273a60b..128278c347 100644 --- a/frontend/rust-lib/flowy-folder2/src/user_default.rs +++ b/frontend/rust-lib/flowy-folder2/src/user_default.rs @@ -54,6 +54,7 @@ impl DefaultFolderBuilder { views: FlattedViews::flatten_views(views), favorites: Default::default(), recent: Default::default(), + trash: Default::default(), } } } diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/database.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/database.rs index 1a794f212f..9f7b94ca44 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/database.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/database.rs @@ -1,6 +1,6 @@ use anyhow::Error; use client_api::entity::QueryCollabResult::{Failed, Success}; -use client_api::entity::{BatchQueryCollab, BatchQueryCollabParams, QueryCollabParams}; +use client_api::entity::{QueryCollab, QueryCollabParams}; use client_api::error::ErrorCode::RecordNotFound; use collab::core::collab_plugin::EncodedCollabV1; use collab_entity::CollabType; @@ -31,8 +31,10 @@ where FutureResult::new(async move { let params = QueryCollabParams { workspace_id, - object_id, - collab_type, + inner: QueryCollab { + object_id, + collab_type, + }, }; match try_get_client?.get_collab(params).await { Ok(data) => Ok(vec![data.doc_state.to_vec()]), @@ -57,15 +59,13 @@ where let try_get_client = self.0.try_get_client(); FutureResult::new(async move { let client = try_get_client?; - let params = BatchQueryCollabParams( - object_ids - .into_iter() - .map(|object_id| BatchQueryCollab { - object_id, - collab_type: object_ty.clone(), - }) - .collect(), - ); + let params = object_ids + .into_iter() + .map(|object_id| QueryCollab { + object_id, + collab_type: object_ty.clone(), + }) + .collect(); let results = client.batch_get_collab(&workspace_id, params).await?; Ok( results diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/document.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/document.rs index 3541b11b4b..23525aec10 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/document.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/document.rs @@ -1,5 +1,5 @@ use anyhow::Error; -use client_api::entity::QueryCollabParams; +use client_api::entity::{QueryCollab, QueryCollabParams}; use collab::core::origin::CollabOrigin; use collab_document::document::Document; use collab_entity::CollabType; @@ -27,8 +27,10 @@ where FutureResult::new(async move { let params = QueryCollabParams { workspace_id, - object_id: document_id.to_string(), - collab_type: CollabType::Document, + inner: QueryCollab { + object_id: document_id.to_string(), + collab_type: CollabType::Document, + }, }; let data = try_get_client? .get_collab(params) @@ -60,8 +62,10 @@ where FutureResult::new(async move { let params = QueryCollabParams { workspace_id, - object_id: document_id.clone(), - collab_type: CollabType::Document, + inner: QueryCollab { + object_id: document_id.clone(), + collab_type: CollabType::Document, + }, }; let doc_state = try_get_client? .get_collab(params) diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs index 23d88cfe48..335575e209 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/folder.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Error}; -use client_api::entity::QueryCollabParams; +use client_api::entity::{QueryCollab, QueryCollabParams}; use collab::core::origin::CollabOrigin; use collab_entity::CollabType; @@ -60,9 +60,11 @@ where let try_get_client = self.0.try_get_client(); FutureResult::new(async move { let params = QueryCollabParams { - object_id: workspace_id.clone(), workspace_id: workspace_id.clone(), - collab_type: CollabType::Folder, + inner: QueryCollab { + object_id: workspace_id.clone(), + collab_type: CollabType::Folder, + }, }; let doc_state = try_get_client? .get_collab(params) @@ -98,9 +100,11 @@ where let try_get_client = self.0.try_get_client(); FutureResult::new(async move { let params = QueryCollabParams { - object_id: workspace_id.clone(), - workspace_id, - collab_type: CollabType::Folder, + workspace_id: workspace_id.clone(), + inner: QueryCollab { + object_id: workspace_id, + collab_type: CollabType::Folder, + }, }; let doc_state = try_get_client? .get_collab(params) diff --git a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs index cfaa609e4d..91212aad04 100644 --- a/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs +++ b/frontend/rust-lib/flowy-server/src/af_cloud/impls/user/cloud_service_impl.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use anyhow::{anyhow, Error}; use client_api::entity::workspace_dto::{CreateWorkspaceMember, WorkspaceMemberChangeset}; -use client_api::entity::{AFRole, AFWorkspace, AuthProvider, InsertCollabParams}; +use client_api::entity::{AFRole, AFWorkspace, AuthProvider, CollabParams, CreateCollabParams}; use collab_entity::CollabObject; use parking_lot::RwLock; @@ -231,16 +231,20 @@ where &self, collab_object: &CollabObject, data: Vec, + override_if_exist: bool, ) -> FutureResult<(), Error> { let try_get_client = self.server.try_get_client(); let collab_object = collab_object.clone(); FutureResult::new(async move { let client = try_get_client?; - let params = InsertCollabParams::new( - collab_object.object_id.clone(), - collab_object.collab_type.clone(), - data, + let params = CreateCollabParams::new( collab_object.workspace_id.clone(), + CollabParams { + object_id: collab_object.object_id.clone(), + encoded_collab_v1: data, + collab_type: collab_object.collab_type.clone(), + override_if_exist, + }, ); client.create_collab(params).await?; Ok(()) diff --git a/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs index ddf0176eae..16a23170cf 100644 --- a/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs +++ b/frontend/rust-lib/flowy-server/src/local_server/impls/user.rs @@ -141,6 +141,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl { &self, _collab_object: &CollabObject, _data: Vec, + _override_if_exist: bool, ) -> FutureResult<(), Error> { FutureResult::new(async { Ok(()) }) } diff --git a/frontend/rust-lib/flowy-server/src/supabase/api/user.rs b/frontend/rust-lib/flowy-server/src/supabase/api/user.rs index 650fb6b997..8e3558824e 100644 --- a/frontend/rust-lib/flowy-server/src/supabase/api/user.rs +++ b/frontend/rust-lib/flowy-server/src/supabase/api/user.rs @@ -98,12 +98,10 @@ where // Query the user profile and workspaces tracing::debug!("user uuid: {}", params.uuid); - let user_profile = get_user_profile( - postgrest.clone(), - GetUserProfileParams::Uuid(params.uuid.clone()), - ) - .await? - .unwrap(); + let user_profile = + get_user_profile(postgrest.clone(), GetUserProfileParams::Uuid(params.uuid)) + .await? + .unwrap(); let user_workspaces = get_user_workspaces(postgrest.clone(), user_profile.uid).await?; let latest_workspace = user_workspaces .iter() @@ -137,7 +135,7 @@ where FutureResult::new(async move { let postgrest = try_get_postgrest?; let params = oauth_params_from_box_any(params)?; - let uuid = params.uuid.clone(); + let uuid = params.uuid; let response = get_user_profile(postgrest.clone(), GetUserProfileParams::Uuid(uuid)) .await? .unwrap(); @@ -311,7 +309,8 @@ where fn create_collab_object( &self, collab_object: &CollabObject, - update: Vec, + data: Vec, + _override_if_exist: bool, ) -> FutureResult<(), Error> { let try_get_postgrest = self.server.try_get_weak_postgrest(); let cloned_collab_object = collab_object.clone(); @@ -319,7 +318,7 @@ where af_spawn(async move { tx.send( async move { - CreateCollabAction::new(cloned_collab_object, try_get_postgrest?, update) + CreateCollabAction::new(cloned_collab_object, try_get_postgrest?, data) .run() .await?; Ok(()) diff --git a/frontend/rust-lib/flowy-user-deps/src/cloud.rs b/frontend/rust-lib/flowy-user-deps/src/cloud.rs index 03141af05b..b21f704e4b 100644 --- a/frontend/rust-lib/flowy-user-deps/src/cloud.rs +++ b/frontend/rust-lib/flowy-user-deps/src/cloud.rs @@ -141,6 +141,7 @@ pub trait UserCloudService: Send + Sync + 'static { &self, collab_object: &CollabObject, data: Vec, + override_if_exist: bool, ) -> FutureResult<(), Error>; } diff --git a/frontend/rust-lib/flowy-user/src/anon_user_upgrade/migrate_anon_user_collab.rs b/frontend/rust-lib/flowy-user/src/anon_user_upgrade/migrate_anon_user_collab.rs index ee0a3dbf59..83862c875d 100644 --- a/frontend/rust-lib/flowy-user/src/anon_user_upgrade/migrate_anon_user_collab.rs +++ b/frontend/rust-lib/flowy-user/src/anon_user_upgrade/migrate_anon_user_collab.rs @@ -17,6 +17,7 @@ use parking_lot::{Mutex, RwLock}; use collab_integrate::{PersistenceError, RocksCollabDB, YrsDocAction}; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_folder_deps::cloud::gen_view_id; +use flowy_user_deps::entities::Authenticator; use crate::migrations::MigrationUser; @@ -27,6 +28,7 @@ pub fn migration_anon_user_on_sign_up( old_collab_db: &Arc, new_user: &MigrationUser, new_collab_db: &Arc, + authenticator: &Authenticator, ) -> FlowyResult<()> { new_collab_db .with_write_txn(|new_collab_w_txn| { @@ -72,6 +74,7 @@ pub fn migration_anon_user_on_sign_up( &old_collab_r_txn, new_user, new_collab_w_txn, + authenticator, )?; // Migrate other collab objects @@ -191,6 +194,7 @@ fn migrate_workspace_folder<'a, 'b, W>( old_collab_r_txn: &'b W, new_user: &MigrationUser, new_collab_w_txn: &'a W, + _authenticator: &Authenticator, ) -> Result<(), PersistenceError> where 'a: 'b, @@ -206,9 +210,9 @@ where old_folder_collab.with_origin_transact_mut(|txn| { old_collab_r_txn.load_doc_with_txn(old_uid, old_workspace_id, txn) })?; - let oid_user_id = UserId::from(old_uid); + let old_user_id = UserId::from(old_uid); let old_folder = Folder::open( - oid_user_id, + old_user_id.clone(), Arc::new(MutexCollab::from_collab(old_folder_collab)), None, ) @@ -219,6 +223,41 @@ where "Can't migrate the folder data" )))?; + if let Some(old_fav_map) = folder_data.favorites.remove(&old_user_id) { + let fav_map = old_fav_map + .into_iter() + .map(|mut item| { + let new_view_id = old_to_new_id_map.get_new_id(&item.id); + item.id = new_view_id; + item + }) + .collect(); + folder_data.favorites.insert(UserId::from(new_uid), fav_map); + } + if let Some(old_trash_map) = folder_data.trash.remove(&old_user_id) { + let trash_map = old_trash_map + .into_iter() + .map(|mut item| { + let new_view_id = old_to_new_id_map.get_new_id(&item.id); + item.id = new_view_id; + item + }) + .collect(); + folder_data.trash.insert(UserId::from(new_uid), trash_map); + } + + if let Some(old_recent_map) = folder_data.recent.remove(&old_user_id) { + let recent_map = old_recent_map + .into_iter() + .map(|mut item| { + let new_view_id = old_to_new_id_map.get_new_id(&item.id); + item.id = new_view_id; + item + }) + .collect(); + folder_data.recent.insert(UserId::from(new_uid), recent_map); + } + old_to_new_id_map .0 .insert(old_workspace_id.to_string(), new_workspace_id.to_string()); diff --git a/frontend/rust-lib/flowy-user/src/anon_user_upgrade/sync_af_user_collab.rs b/frontend/rust-lib/flowy-user/src/anon_user_upgrade/sync_af_user_collab.rs index 88f934cdd7..0705667c85 100644 --- a/frontend/rust-lib/flowy-user/src/anon_user_upgrade/sync_af_user_collab.rs +++ b/frontend/rust-lib/flowy-user/src/anon_user_upgrade/sync_af_user_collab.rs @@ -109,7 +109,7 @@ fn sync_view( encode_v1.len() ); user_service - .create_collab_object(&collab_object, encode_v1) + .create_collab_object(&collab_object, encode_v1, false) .await?; }, ViewLayout::Grid | ViewLayout::Board | ViewLayout::Calendar => { @@ -121,7 +121,7 @@ fn sync_view( database_encode_v1.len() ); user_service - .create_collab_object(&collab_object, database_encode_v1) + .create_collab_object(&collab_object, database_encode_v1, false) .await?; // sync database's row @@ -145,7 +145,7 @@ fn sync_view( ); let _ = user_service - .create_collab_object(&database_row_collab_object, database_row_encode_v1) + .create_collab_object(&database_row_collab_object, database_row_encode_v1, false) .await; let database_row_document = CollabObject::new( @@ -165,7 +165,7 @@ fn sync_view( document_encode_v1.len() ); let _ = user_service - .create_collab_object(&database_row_document, document_encode_v1) + .create_collab_object(&database_row_document, document_encode_v1, false) .await; } } @@ -271,7 +271,7 @@ async fn sync_folder( encode_v1.len() ); if let Err(err) = user_service - .create_collab_object(&collab_object, encode_v1) + .create_collab_object(&collab_object, encode_v1, true) .await { tracing::error!("🔴sync folder failed: {:?}", err); @@ -316,7 +316,7 @@ async fn sync_database_views( if let Ok((records, encode_v1)) = result { if let Ok(encode_v1) = encode_v1 { let _ = user_service - .create_collab_object(&collab_object, encode_v1) + .create_collab_object(&collab_object, encode_v1, false) .await; } diff --git a/frontend/rust-lib/flowy-user/src/anon_user_upgrade/sync_supabase_user_collab.rs b/frontend/rust-lib/flowy-user/src/anon_user_upgrade/sync_supabase_user_collab.rs index 63da725f4e..a1cc335402 100644 --- a/frontend/rust-lib/flowy-user/src/anon_user_upgrade/sync_supabase_user_collab.rs +++ b/frontend/rust-lib/flowy-user/src/anon_user_upgrade/sync_supabase_user_collab.rs @@ -109,7 +109,7 @@ fn sync_view( doc_state.len() ); user_service - .create_collab_object(&collab_object, doc_state) + .create_collab_object(&collab_object, doc_state, false) .await?; }, ViewLayout::Grid | ViewLayout::Board | ViewLayout::Calendar => { @@ -121,7 +121,7 @@ fn sync_view( database_doc_state.len() ); user_service - .create_collab_object(&collab_object, database_doc_state) + .create_collab_object(&collab_object, database_doc_state, false) .await?; // sync database's row @@ -145,7 +145,7 @@ fn sync_view( ); let _ = user_service - .create_collab_object(&database_row_collab_object, database_row_doc_state) + .create_collab_object(&database_row_collab_object, database_row_doc_state, false) .await; let database_row_document = CollabObject::new( @@ -165,7 +165,7 @@ fn sync_view( document_doc_state.len() ); let _ = user_service - .create_collab_object(&database_row_document, document_doc_state) + .create_collab_object(&database_row_document, document_doc_state, false) .await; } } @@ -281,7 +281,7 @@ async fn sync_folder( update.len() ); if let Err(err) = user_service - .create_collab_object(&collab_object, update.to_vec()) + .create_collab_object(&collab_object, update.to_vec(), false) .await { tracing::error!("🔴sync folder failed: {:?}", err); @@ -325,7 +325,7 @@ async fn sync_database_views( if let Ok((records, doc_state)) = result { let _ = user_service - .create_collab_object(&collab_object, doc_state.to_vec()) + .create_collab_object(&collab_object, doc_state.to_vec(), false) .await; records.into_iter().map(Arc::new).collect() } else { diff --git a/frontend/rust-lib/flowy-user/src/entities/auth.rs b/frontend/rust-lib/flowy-user/src/entities/auth.rs index 99a7fe9960..1e8332c462 100644 --- a/frontend/rust-lib/flowy-user/src/entities/auth.rs +++ b/frontend/rust-lib/flowy-user/src/entities/auth.rs @@ -19,7 +19,7 @@ pub struct SignInPayloadPB { pub name: String, #[pb(index = 4)] - pub auth_type: AuthTypePB, + pub auth_type: AuthenticatorPB, #[pb(index = 5)] pub device_id: String, @@ -53,7 +53,7 @@ pub struct SignUpPayloadPB { pub password: String, #[pb(index = 4)] - pub auth_type: AuthTypePB, + pub auth_type: AuthenticatorPB, #[pb(index = 5)] pub device_id: String, @@ -88,7 +88,7 @@ pub struct OauthSignInPB { pub map: HashMap, #[pb(index = 2)] - pub auth_type: AuthTypePB, + pub auth_type: AuthenticatorPB, } #[derive(ProtoBuf, Default)] @@ -97,7 +97,7 @@ pub struct SignInUrlPayloadPB { pub email: String, #[pb(index = 2)] - pub auth_type: AuthTypePB, + pub auth_type: AuthenticatorPB, } #[derive(ProtoBuf, Default)] @@ -173,13 +173,13 @@ pub struct OauthProviderDataPB { } #[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)] -pub enum AuthTypePB { +pub enum AuthenticatorPB { Local = 0, Supabase = 1, - AFCloud = 2, + AppFlowyCloud = 2, } -impl Default for AuthTypePB { +impl Default for AuthenticatorPB { fn default() -> Self { Self::Local } @@ -232,7 +232,7 @@ impl From for UserCredentials { #[derive(Default, ProtoBuf)] pub struct UserStatePB { #[pb(index = 1)] - pub auth_type: AuthTypePB, + pub auth_type: AuthenticatorPB, } #[derive(ProtoBuf, Debug, Default, Clone)] diff --git a/frontend/rust-lib/flowy-user/src/entities/user_profile.rs b/frontend/rust-lib/flowy-user/src/entities/user_profile.rs index 186dc5a6d9..81f2272cd6 100644 --- a/frontend/rust-lib/flowy-user/src/entities/user_profile.rs +++ b/frontend/rust-lib/flowy-user/src/entities/user_profile.rs @@ -7,7 +7,7 @@ use flowy_user_deps::entities::*; use crate::entities::parser::{UserEmail, UserIcon, UserName, UserOpenaiKey, UserPassword}; use crate::entities::required_not_empty_str; -use crate::entities::AuthTypePB; +use crate::entities::AuthenticatorPB; use crate::errors::ErrorCode; use super::parser::UserStabilityAIKey; @@ -45,7 +45,7 @@ pub struct UserProfilePB { pub openai_key: String, #[pb(index = 7)] - pub auth_type: AuthTypePB, + pub authenticator: AuthenticatorPB, #[pb(index = 8)] pub encryption_sign: String, @@ -85,7 +85,7 @@ impl std::convert::From for UserProfilePB { token: user_profile.token, icon_url: user_profile.icon_url, openai_key: user_profile.openai_key, - auth_type: user_profile.authenticator.into(), + authenticator: user_profile.authenticator.into(), encryption_sign, encryption_type: encryption_ty, workspace_id: user_profile.workspace_id, diff --git a/frontend/rust-lib/flowy-user/src/entities/user_setting.rs b/frontend/rust-lib/flowy-user/src/entities/user_setting.rs index 7be2764675..95f0d83e6c 100644 --- a/frontend/rust-lib/flowy-user/src/entities/user_setting.rs +++ b/frontend/rust-lib/flowy-user/src/entities/user_setting.rs @@ -114,7 +114,7 @@ impl std::default::Default for LocaleSettingsPB { } } -#[derive(ProtoBuf, Serialize, Deserialize, Debug, Clone)] +#[derive(ProtoBuf, Serialize, Deserialize, Debug, Clone, Default)] pub struct DocumentSettingsPB { #[pb(index = 1, one_of)] pub cursor_color: Option, @@ -123,15 +123,6 @@ pub struct DocumentSettingsPB { pub selection_color: Option, } -impl std::default::Default for DocumentSettingsPB { - fn default() -> Self { - Self { - cursor_color: None, - selection_color: None, - } - } -} - pub const APPEARANCE_DEFAULT_THEME: &str = "Default"; pub const APPEARANCE_DEFAULT_FONT: &str = "Poppins"; pub const APPEARANCE_DEFAULT_MONOSPACE_FONT: &str = "SF Mono"; diff --git a/frontend/rust-lib/flowy-user/src/manager.rs b/frontend/rust-lib/flowy-user/src/manager.rs index 6007a73541..688184dbf9 100644 --- a/frontend/rust-lib/flowy-user/src/manager.rs +++ b/frontend/rust-lib/flowy-user/src/manager.rs @@ -35,6 +35,7 @@ use crate::migrations::document_empty_content::HistoricalEmptyDocumentMigration; use crate::migrations::migration::{UserDataMigration, UserLocalDataMigration}; use crate::migrations::session_migration::migrate_session_with_user_uuid; use crate::migrations::workspace_and_favorite_v1::FavoriteV1AndWorkspaceArrayMigration; +use crate::migrations::workspace_trash_v1::WorkspaceTrashMapToSectionMigration; use crate::migrations::MigrationUser; use crate::services::cloud_config::get_cloud_config; use crate::services::collab_interact::{CollabInteract, DefaultCollabInteract}; @@ -198,16 +199,18 @@ impl UserManager { let weak_pool = Arc::downgrade(&self.db_pool(user.uid)?); if let Some(mut token_state_rx) = self.cloud_services.subscribe_token_state() { event!(tracing::Level::DEBUG, "Listen token state change"); + let user_uid = user.uid; + let user_token = user.token.clone(); af_spawn(async move { while let Some(token_state) = token_state_rx.next().await { debug!("Token state changed: {:?}", token_state); match token_state { UserTokenState::Refresh { token } => { // Only save the token if the token is different from the current token - if token != user.token { + if token != user_token { if let Some(pool) = weak_pool.upgrade() { // Save the new token - if let Err(err) = save_user_token(user.uid, pool, token) { + if let Err(err) = save_user_token(user_uid, pool, token) { error!("Save user token failed: {}", err); } } @@ -232,9 +235,10 @@ impl UserManager { let migrations: Vec> = vec![ Box::new(HistoricalEmptyDocumentMigration), Box::new(FavoriteV1AndWorkspaceArrayMigration), + Box::new(WorkspaceTrashMapToSectionMigration), ]; match UserLocalDataMigration::new(session.clone(), collab_db, sqlite_pool) - .run(migrations, ¤t_authenticator) + .run(migrations, &user.authenticator) { Ok(applied_migrations) => { if !applied_migrations.is_empty() { @@ -786,7 +790,13 @@ impl UserManager { ) -> Result<(), FlowyError> { let old_collab_db = self.database.get_collab_db(old_user.session.user_id)?; let new_collab_db = self.database.get_collab_db(new_user.session.user_id)?; - migration_anon_user_on_sign_up(old_user, &old_collab_db, new_user, &new_collab_db)?; + migration_anon_user_on_sign_up( + old_user, + &old_collab_db, + new_user, + &new_collab_db, + authenticator, + )?; match authenticator { Authenticator::Supabase => { diff --git a/frontend/rust-lib/flowy-user/src/migrations/mod.rs b/frontend/rust-lib/flowy-user/src/migrations/mod.rs index 30f2b846b6..244e72f5de 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/mod.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/mod.rs @@ -1,11 +1,13 @@ -use crate::services::entities::Session; use flowy_user_deps::entities::UserProfile; +use crate::services::entities::Session; + pub mod document_empty_content; pub mod migration; pub mod session_migration; mod util; pub mod workspace_and_favorite_v1; +pub mod workspace_trash_v1; #[derive(Clone, Debug)] pub struct MigrationUser { diff --git a/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs b/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs index c5fae7bbb4..a3d5f3dfc3 100644 --- a/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs +++ b/frontend/rust-lib/flowy-user/src/migrations/session_migration.rs @@ -15,23 +15,21 @@ pub fn migrate_session_with_user_uuid( session: &Arc>>, store_preferences: &Arc, ) { - if !store_preferences.get_bool(MIGRATION_USER_NO_USER_UUID) { - if store_preferences + if !store_preferences.get_bool(MIGRATION_USER_NO_USER_UUID) + && store_preferences .set_bool(MIGRATION_USER_NO_USER_UUID, true) .is_ok() - { - if let Some(mut value) = store_preferences.get_object::(&user_config.session_cache_key) - { - if value.get("user_uuid").is_none() { - value.as_object_mut().map(|map| { - map.insert("user_uuid".to_string(), json!(Uuid::new_v4())); - }); + { + if let Some(mut value) = store_preferences.get_object::(&user_config.session_cache_key) { + if value.get("user_uuid").is_none() { + if let Some(map) = value.as_object_mut() { + map.insert("user_uuid".to_string(), json!(Uuid::new_v4())); } + } - if let Ok(new_session) = serde_json::from_value::(value) { - *session.write() = Some(new_session.clone()); - let _ = store_preferences.set_object(&user_config.session_cache_key, &new_session); - } + if let Ok(new_session) = serde_json::from_value::(value) { + *session.write() = Some(new_session.clone()); + let _ = store_preferences.set_object(&user_config.session_cache_key, &new_session); } } } diff --git a/frontend/rust-lib/flowy-user/src/migrations/workspace_trash_v1.rs b/frontend/rust-lib/flowy-user/src/migrations/workspace_trash_v1.rs new file mode 100644 index 0000000000..6d6c0e6afc --- /dev/null +++ b/frontend/rust-lib/flowy-user/src/migrations/workspace_trash_v1.rs @@ -0,0 +1,56 @@ +use std::sync::Arc; + +use collab_folder::Folder; +use tracing::instrument; + +use collab_integrate::{RocksCollabDB, YrsDocAction}; +use flowy_error::{internal_error, FlowyResult}; +use flowy_user_deps::entities::Authenticator; + +use crate::migrations::migration::UserDataMigration; +use crate::migrations::util::load_collab; +use crate::services::entities::Session; + +/// 1. Migrate the workspace: { trash: [view_id] } to { trash: { uid: [view_id] } } +pub struct WorkspaceTrashMapToSectionMigration; + +impl UserDataMigration for WorkspaceTrashMapToSectionMigration { + fn name(&self) -> &str { + "workspace_trash_map_to_section_migration" + } + + #[instrument(name = "WorkspaceTrashMapToSectionMigration", skip_all, err)] + fn run( + &self, + session: &Session, + collab_db: &Arc, + _authenticator: &Authenticator, + ) -> FlowyResult<()> { + let write_txn = collab_db.write_txn(); + if let Ok(collab) = load_collab(session.user_id, &write_txn, &session.user_workspace.id) { + let folder = Folder::open(session.user_id, collab, None)?; + let trash_ids = folder + .get_trash_v1() + .into_iter() + .map(|fav| fav.id) + .collect::>(); + + if !trash_ids.is_empty() { + folder.add_trash(trash_ids); + } + + let encode = folder.encode_collab_v1(); + write_txn + .flush_doc_with( + session.user_id, + &session.user_workspace.id, + &encode.doc_state, + &encode.state_vector, + ) + .map_err(internal_error)?; + } + + write_txn.commit_transaction().map_err(internal_error)?; + Ok(()) + } +} diff --git a/frontend/rust-lib/flowy-user/src/services/entities.rs b/frontend/rust-lib/flowy-user/src/services/entities.rs index 9035220a4d..c1cb4b447d 100644 --- a/frontend/rust-lib/flowy-user/src/services/entities.rs +++ b/frontend/rust-lib/flowy-user/src/services/entities.rs @@ -11,7 +11,7 @@ use uuid::Uuid; use flowy_user_deps::entities::{AuthResponse, UserProfile, UserWorkspace}; use flowy_user_deps::entities::{Authenticator, UserAuthResponse}; -use crate::entities::AuthTypePB; +use crate::entities::AuthenticatorPB; use crate::migrations::MigrationUser; #[derive(Debug, Clone, Serialize)] @@ -99,7 +99,7 @@ where fn from(value: &T) -> Self { Self { user_id: value.user_id(), - user_uuid: value.user_uuid().clone(), + user_uuid: *value.user_uuid(), user_workspace: value.latest_workspace().clone(), } } @@ -114,22 +114,22 @@ impl std::convert::From for String { } } -impl From for Authenticator { - fn from(pb: AuthTypePB) -> Self { +impl From for Authenticator { + fn from(pb: AuthenticatorPB) -> Self { match pb { - AuthTypePB::Supabase => Authenticator::Supabase, - AuthTypePB::Local => Authenticator::Local, - AuthTypePB::AFCloud => Authenticator::AppFlowyCloud, + AuthenticatorPB::Supabase => Authenticator::Supabase, + AuthenticatorPB::Local => Authenticator::Local, + AuthenticatorPB::AppFlowyCloud => Authenticator::AppFlowyCloud, } } } -impl From for AuthTypePB { +impl From for AuthenticatorPB { fn from(auth_type: Authenticator) -> Self { match auth_type { - Authenticator::Supabase => AuthTypePB::Supabase, - Authenticator::Local => AuthTypePB::Local, - Authenticator::AppFlowyCloud => AuthTypePB::AFCloud, + Authenticator::Supabase => AuthenticatorPB::Supabase, + Authenticator::Local => AuthenticatorPB::Local, + Authenticator::AppFlowyCloud => AuthenticatorPB::AppFlowyCloud, } } } diff --git a/frontend/rust-lib/lib-log/src/lib.rs b/frontend/rust-lib/lib-log/src/lib.rs index eeeea7431e..e51773e584 100644 --- a/frontend/rust-lib/lib-log/src/lib.rs +++ b/frontend/rust-lib/lib-log/src/lib.rs @@ -6,7 +6,7 @@ use tracing::subscriber::set_global_default; use tracing_appender::{non_blocking::WorkerGuard, rolling::RollingFileAppender}; use tracing_bunyan_formatter::JsonStorageLayer; use tracing_subscriber::fmt::format::Writer; -use tracing_subscriber::{layer::SubscriberExt, EnvFilter}; +use tracing_subscriber::{fmt, layer::SubscriberExt, EnvFilter}; use crate::layer::FlowyFormattingLayer; @@ -37,22 +37,25 @@ impl Builder { self } - pub fn build(self) -> std::result::Result<(), String> { + pub fn build(self) -> Result<(), String> { let env_filter = EnvFilter::new(self.env_filter); + let std_out_layer = fmt::layer().with_writer(std::io::stdout).pretty(); let (non_blocking, guard) = tracing_appender::non_blocking(self.file_appender); + let file_layer = FlowyFormattingLayer::new(non_blocking); + let subscriber = tracing_subscriber::fmt() .with_timer(CustomTime) .with_ansi(true) .with_target(false) .with_max_level(tracing::Level::TRACE) .with_thread_ids(false) - .with_writer(std::io::stderr) .pretty() .with_env_filter(env_filter) .finish() .with(JsonStorageLayer) - .with(FlowyFormattingLayer::new(non_blocking)); + .with(file_layer) + .with(std_out_layer); set_global_default(subscriber).map_err(|e| format!("{:?}", e))?; diff --git a/frontend/scripts/makefile/tests.toml b/frontend/scripts/makefile/tests.toml index 8f00701530..947b013636 100644 --- a/frontend/scripts/makefile/tests.toml +++ b/frontend/scripts/makefile/tests.toml @@ -1,11 +1,11 @@ # If you want to test a single file with single case, you can try this command: -# RUST_LOG="debug" flutter test -j, --concurrency=1 'path to the file' --name 'test case name' +# RUST_LOG="debug" flutter test -d macOS -j, 'path to the file' --name 'test case name' [tasks.flutter_test] description = "Run flutter test with single case in single file. Input: cargo make flutter_test 'path to the file' --name 'test case name'" script = ''' cd appflowy_flutter -RUST_LOG="debug" flutter test -j, --concurrency=1 "${@}" +flutter test -j, --concurrency=1 "${@}" ''' script_runner = "@shell"