refactor: remove singleton db (#4208)

* refactor: remove singleton db

* chore: fix warning

* chore: fix warning

* chore: update test

* chore: only resotre or backup when init call

* test: fix

* test: fix

* test: fix

* fix: timeout notification

* chore: rename

* chore: rename

* chore: disable test

* chore: remove log

* chore: remove log

* chore: add log

* chore: rename test functions

* chore: add test asset

* chore: bump client api

* chore: disable some tests
This commit is contained in:
Nathan.fooo 2023-12-27 11:42:39 +08:00 committed by GitHub
parent 121ed5a06e
commit df8409178b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
110 changed files with 947 additions and 829 deletions

View File

@ -25,7 +25,7 @@ env:
jobs:
test-on-ubuntu:
environment: SUPABASE_CI
# environment: SUPABASE_CI
runs-on: ubuntu-latest
steps:
- name: Checkout source code
@ -52,21 +52,21 @@ jobs:
workspaces: |
frontend/rust-lib
- name: Create .env file in flowy-server
working-directory: frontend/rust-lib/flowy-server
run: |
touch .env.ci
echo SUPABASE_URL=${{ secrets.SUPABASE_URL }} >> .env.ci
echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} >> .env.ci
echo SUPABASE_JWT_SECRET=${{ secrets.SUPABASE_JWT_SECRET }} >> .env.ci
- name: Create .env file in event-integration
working-directory: frontend/rust-lib/event-integration
run: |
touch .env.ci
echo SUPABASE_URL=${{ secrets.SUPABASE_URL }} >> .env.ci
echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} >> .env.ci
echo SUPABASE_JWT_SECRET=${{ secrets.SUPABASE_JWT_SECRET }} >> .env.ci
# - name: Create .env file in flowy-server
# working-directory: frontend/rust-lib/flowy-server
# run: |
# touch .env.ci
# echo SUPABASE_URL=${{ secrets.SUPABASE_URL }} >> .env.ci
# echo SUPABASE_ANON_KEY=${{ secrets.SUPABASE_ANON_KEY }} >> .env.ci
# echo SUPABASE_JWT_SECRET=${{ secrets.SUPABASE_JWT_SECRET }} >> .env.ci
#
# - name: Create .env file in event-integration
# working-directory: frontend/rust-lib/event-integration
# run: |
# touch .env.ci
# echo SUPABASE_URL=${{ secrets.SUPABASE_URL }} >> .env.ci
# 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
@ -86,11 +86,11 @@ jobs:
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 down -v --remove-orphans
docker compose up -d
- name: Run rust-lib tests

View File

@ -16,7 +16,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
@ -48,7 +48,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);

View File

@ -21,7 +21,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final findFirstCard = find.descendant(
of: find.byType(AppFlowyGroupCard),
@ -64,7 +64,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final findLastCard = find.descendant(
of: find.byType(AppFlowyGroupCard),

View File

@ -17,7 +17,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final card1 = find.ancestor(
of: find.findTextInFlowyText(card1Name),
matching: find.byType(AppFlowyGroupCard),

View File

@ -17,7 +17,7 @@ void main() {
testWidgets('expand/collapse hidden groups', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
final collapseFinder = find.byFlowySvg(FlowySvgs.pull_left_outlined_s);
final expandFinder = find.byFlowySvg(FlowySvgs.hamburger_s_s);
@ -46,7 +46,7 @@ void main() {
testWidgets('hide first group, and show it again', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
// Tap the options of the first group
final optionsFinder = find
@ -82,7 +82,7 @@ void main() {
testWidgets('delete a group', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
expect(tester.widgetList(find.byType(BoardColumnHeader)).length, 4);

View File

@ -18,7 +18,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.findTextInFlowyText(name);
await tester.hoverOnWidget(
@ -36,7 +36,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
const name = 'Card 1';
final card1 = find.findTextInFlowyText(name);
await tester.hoverOnWidget(
@ -53,7 +53,7 @@ void main() {
testWidgets('add new group', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Board);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Board);
// assert number of groups
tester.assertNumberOfGroups(4);

View File

@ -31,7 +31,7 @@ void main() {
tester.expectToSeeText(LocaleKeys.signIn_loginStartWithAnonymous.tr());
await tester.tapGoButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
// reanme the name of the anon user
await tester.openSettings();
@ -41,13 +41,14 @@ void main() {
matching: find.byType(UserNameInput),
);
await tester.enterText(userNameFinder, 'local_user');
await tester.openSettingsPage(SettingsPage.user);
await tester.pumpAndSettle();
// sign up with Google
await tester.tapGoogleLoginInButton();
await tester.pumpAndSettle();
// sign out
await tester.expectToSeeHomePage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
await tester.logout();

View File

@ -1,74 +0,0 @@
// 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');
});
});
}

View File

@ -25,7 +25,7 @@ void main() {
cloudType: AuthenticatorType.appflowyCloud,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
});
testWidgets('sign out', (tester) async {

View File

@ -1,17 +1,17 @@
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 '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;
import 'anon_user_continue_test.dart' as anon_user_continue_test;
Future<void> main() async {
preset_af_cloud_env_test.main();
appflowy_cloud_auth_test.main();
document_sync_test.main();
// document_sync_test.main();
user_sync_test.main();
// anon_user_continue_test.main();
anon_user_continue_test.main();
}

View File

@ -22,8 +22,8 @@ import '../util/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
const pageName = 'Sample';
final email = '${uuid()}@appflowy.io';
const inputContent = 'Hello world, this is a test document';
// The test will create a new document called Sample, and sync it to the server.
// Then the test will logout the user, and login with the same user. The data will
@ -35,20 +35,21 @@ void main() {
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
// create a new document called Sample
await tester.createNewPageWithName(
name: pageName,
await tester.createNewPage(
layout: ViewLayoutPB.Document,
);
// focus on the editor
await tester.editor.tapLineOfEditorAt(0);
await tester.ime.insertText('hello world');
await tester.ime.insertText(inputContent);
expect(find.text(inputContent, findRichText: true), findsOneWidget);
await tester.pumpAndSettle();
expect(find.text('hello world', findRichText: true), findsOneWidget);
// TODO(nathan): remove the await
// 6 seconds for data sync
await tester.waitForSeconds(6);
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
@ -62,15 +63,10 @@ void main() {
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePage();
await tester.pumpAndSettle(const Duration(seconds: 2));
// The document will be synced from the server
await tester.openPage(
pageName,
);
await tester.pumpAndSettle(const Duration(seconds: 2));
expect(find.text('hello world', findRichText: true), findsOneWidget);
// the latest document will be opened, so the content must be the inputContent
await tester.pumpAndSettle();
expect(find.text(inputContent, findRichText: true), findsOneWidget);
});
});
}

View File

@ -15,7 +15,7 @@ void main() {
testWidgets('sign in with supabase', (tester) async {
await tester.initializeAppFlowy(cloudType: AuthenticatorType.supabase);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
});
testWidgets('sign out with supabase', (tester) async {

View File

@ -36,7 +36,7 @@ void main() {
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.user);
@ -74,7 +74,7 @@ void main() {
email: email,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.pumpAndSettle();
await tester.openSettings();

View File

@ -14,7 +14,9 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Calendar,
);
// open setting
await tester.tapDatabaseSettingButton();
@ -36,7 +38,7 @@ void main() {
// Create calendar view
const name = 'calendar';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: ViewLayoutPB.Calendar,
);
@ -68,7 +70,9 @@ void main() {
await tester.tapGoButton();
// Create the calendar view
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Calendar,
);
// Scroll until today's date cell is visible
await tester.scrollToToday();
@ -148,7 +152,9 @@ void main() {
await tester.tapGoButton();
// Create the calendar view
await tester.createNewPageWithName(layout: ViewLayoutPB.Calendar);
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Calendar,
);
// Create a new event on the first of this month
final today = DateTime.now();

View File

@ -15,7 +15,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.editCell(
rowIndex: 0,
@ -37,7 +37,7 @@ void main() {
testWidgets('multiple text cells', (tester) async {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'my grid',
layout: ViewLayoutPB.Grid,
);
@ -77,7 +77,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.Number;
@ -135,7 +135,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.assertCheckboxCell(rowIndex: 0, isSelected: false);
await tester.tapCheckboxCellInGrid(rowIndex: 0);
@ -153,7 +153,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.CreatedTime;
// Create a create time field
@ -171,7 +171,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.LastEditedTime;
// Create a last time field
@ -189,7 +189,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.DateTime;
await tester.createField(fieldType, fieldType.name);
@ -282,7 +282,7 @@ void main() {
const fieldType = FieldType.SingleSelect;
// When create a grid, it will create a single select field by default
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Tap the cell to invoke the selection option editor
await tester.tapSelectOptionCellInGrid(rowIndex: 0, fieldType: fieldType);
@ -358,7 +358,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.MultiSelect;
await tester.createField(fieldType, fieldType.name);
@ -441,7 +441,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
const fieldType = FieldType.Checklist;
await tester.createField(fieldType, fieldType.name);

View File

@ -15,7 +15,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Grid);
// create a field

View File

@ -17,7 +17,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Name');
@ -34,7 +34,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Invoke the field editor
await tester.tapGridFieldWithName('Type');
@ -56,7 +56,7 @@ void main() {
await tester.tapGoButton();
// create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checklist, 'checklist');
@ -70,7 +70,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.createField(FieldType.Checkbox, 'New field 1');
@ -90,7 +90,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// create a field
await tester.scrollToRight(find.byType(GridPage));
@ -110,7 +110,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
@ -133,7 +133,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.scrollToRight(find.byType(GridPage));
await tester.tapNewPropertyButton();
@ -153,7 +153,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
for (final fieldType in [
FieldType.Checklist,
@ -185,7 +185,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Grid,
);

View File

@ -20,7 +20,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -34,7 +34,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -53,7 +53,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -80,7 +80,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -101,7 +101,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -135,7 +135,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -168,7 +168,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -216,7 +216,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -231,7 +231,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -271,7 +271,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -310,7 +310,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();
@ -327,7 +327,7 @@ void main() {
await tester.tapGoButton();
// Create a new grid
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Hover first row and then open the row page
await tester.openFirstRowDetailPage();

View File

@ -13,7 +13,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.tapCreateRowButtonInGrid();
// The initial number of rows is 3
@ -25,7 +25,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid();
@ -41,7 +41,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.hoverOnFirstRowOfGrid();
// Open the row menu and then click the delete
@ -59,7 +59,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
await tester.assertRowCountInGridPage(3);
await tester.pumpAndSettle();

View File

@ -14,7 +14,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// open setting
await tester.tapDatabaseSettingButton();
@ -31,7 +31,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// open setting
await tester.tapDatabaseSettingButton();

View File

@ -14,7 +14,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Create board view
await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Board);
@ -35,7 +35,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Create board view
await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Board);
@ -60,7 +60,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(layout: ViewLayoutPB.Grid);
await tester.createNewPageWithNameUnderParent(layout: ViewLayoutPB.Grid);
// Create board view
await tester.tapCreateLinkedDatabaseViewButton(DatabaseLayoutPB.Board);

View File

@ -18,7 +18,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName();
await tester.createNewPageWithNameUnderParent();
// mock the clipboard
const lines = 3;

View File

@ -307,7 +307,7 @@ extension on WidgetTester {
await tapGoButton();
// create a new document
await createNewPageWithName();
await createNewPageWithNameUnderParent();
await beforeTest?.call(editor.getCurrentEditorState());

View File

@ -17,7 +17,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName();
await tester.createNewPageWithNameUnderParent();
// expect to see a new document
tester.expectToSeePageName(

View File

@ -86,7 +86,7 @@ void main() {
Future<String> createDocumentToReference(WidgetTester tester) async {
final name = 'document_${uuid()}';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: ViewLayoutPB.Document,
openAfterCreated: false,

View File

@ -32,7 +32,7 @@ void main() {
await tester.tapAt(Offset.zero);
await tester.tapAt(Offset.zero);
await tester.createNewPageWithName(name: 'test');
await tester.createNewPageWithNameUnderParent(name: 'test');
await tester.openPage(gettingStarted);
// check the status again

View File

@ -136,13 +136,13 @@ Future<void> insertReferenceDatabase(
// create a new grid
final id = uuid();
final name = '${layout.name}_$id';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: layout,
openAfterCreated: false,
);
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'insert_a_reference_${layout.name}',
layout: ViewLayoutPB.Document,
openAfterCreated: true,
@ -171,7 +171,7 @@ Future<void> createInlineDatabase(
) async {
// create a new document
final documentName = 'insert_a_inline_${layout.name}';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: documentName,
layout: ViewLayoutPB.Document,
openAfterCreated: true,

View File

@ -31,7 +31,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: LocaleKeys.document_plugins_image_addAnImage.tr(),
layout: ViewLayoutPB.Document,
);
@ -79,7 +79,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: LocaleKeys.document_plugins_image_addAnImage.tr(),
layout: ViewLayoutPB.Document,
);
@ -133,7 +133,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: LocaleKeys.document_plugins_image_addAnImage.tr(),
layout: ViewLayoutPB.Document,
);

View File

@ -20,7 +20,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'math equation',
layout: ViewLayoutPB.Document,
);
@ -66,7 +66,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'math equation',
layout: ViewLayoutPB.Document,
);

View File

@ -105,14 +105,14 @@ Future<String> insertInlinePage(
// create a new grid
final id = uuid();
final name = '${layout.name}_$id';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: layout,
openAfterCreated: false,
);
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'insert_a_inline_page_${layout.name}',
layout: ViewLayoutPB.Document,
);

View File

@ -24,7 +24,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Document,
);

View File

@ -15,7 +15,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'outline_test',
layout: ViewLayoutPB.Document,
);
@ -32,7 +32,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: 'outline_test',
layout: ViewLayoutPB.Document,
);

View File

@ -40,7 +40,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Document,
);
@ -86,7 +86,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Document,
);
@ -125,7 +125,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Document,
);
@ -162,7 +162,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Document,
);
@ -196,7 +196,7 @@ void main() {
await tester.tapGoButton();
// create a new document
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
layout: ViewLayoutPB.Document,
);

View File

@ -18,7 +18,7 @@ void main() {
// create a new document called Sample
const pageName = 'Sample';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: pageName,
layout: ViewLayoutPB.Document,
);
@ -75,7 +75,7 @@ void main() {
// create a new document called Sample
const pageName = 'Sample';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: pageName,
layout: ViewLayoutPB.Document,
);

View File

@ -19,7 +19,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.appearance);
@ -71,7 +71,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.pumpAndSettle();

View File

@ -14,7 +14,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.language);

View File

@ -31,7 +31,7 @@ void main() {
].map((e) => 'document_$e').toList();
for (var i = 0; i < names.length; i++) {
final parentName = i == 0 ? gettingStarted : names[i - 1];
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
@ -113,7 +113,7 @@ void main() {
final names = [1, 2].map((e) => 'document_$e').toList();
for (var i = 0; i < names.length; i++) {
final parentName = i == 0 ? gettingStarted : names[i - 1];
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
@ -170,7 +170,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName();
await tester.createNewPageWithNameUnderParent();
await tester.favoriteViewByName(gettingStarted);
expect(
find.byWidgetPredicate(
@ -190,7 +190,7 @@ void main() {
await tester.initializeAppFlowy();
await tester.tapGoButton();
await tester.createNewPageWithName();
await tester.createNewPageWithNameUnderParent();
await tester.favoriteViewByName(gettingStarted);
await tester.hoverOnPageName(
gettingStarted,

View File

@ -18,7 +18,7 @@ void main() {
// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: value.name,
parentName: gettingStarted,
layout: value,
@ -46,7 +46,7 @@ void main() {
// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: value.name,
parentName: gettingStarted,
layout: value,

View File

@ -41,7 +41,7 @@ void main() {
for (final layout in ViewLayoutPB.values) {
// create a new page
final name = 'AppFlowy_$layout';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: name,
layout: layout,
);
@ -79,7 +79,7 @@ void main() {
final names = [1, 2, 3, 4].map((e) => 'document_$e').toList();
for (var i = 0; i < names.length; i++) {
final parentName = i == 0 ? gettingStarted : names[i - 1];
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: names[i],
parentName: parentName,
layout: ViewLayoutPB.Document,
@ -144,14 +144,14 @@ void main() {
await tester.tapGoButton();
const document = 'document';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: document,
openAfterCreated: false,
);
tester.expectToSeePageName(document, layout: ViewLayoutPB.Document);
const grid = 'grid';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: grid,
layout: ViewLayoutPB.Grid,
openAfterCreated: false,
@ -187,7 +187,7 @@ void main() {
await tester.tapGoButton();
const grid = 'grid';
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: grid,
layout: ViewLayoutPB.Grid,
openAfterCreated: true,

View File

@ -33,7 +33,7 @@ void main() {
);
await tester.tapGoButton();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
// switch to user B
{
@ -51,7 +51,7 @@ void main() {
);
await tester.tapCustomLocationButton();
await tester.pumpAndSettle();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
// set user name for userB
await tester.openSettings();
@ -71,7 +71,7 @@ void main() {
await tester.tapCustomLocationButton();
await tester.pumpAndSettle();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
tester.expectToSeeUserName(userA);
}
@ -88,7 +88,7 @@ void main() {
await tester.tapCustomLocationButton();
await tester.pumpAndSettle();
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
tester.expectToSeeUserName(userB);
}
});
@ -99,7 +99,7 @@ void main() {
await tester.tapGoButton();
// home and readme document
await tester.expectToSeeHomePage();
await tester.expectToSeeHomePageWithGetStartedPage();
// open settings and restore the location
await tester.openSettings();

View File

@ -32,12 +32,12 @@ void main() {
findsNothing,
);
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: _documentName,
layout: ViewLayoutPB.Document,
);
await tester.createNewPageWithName(
await tester.createNewPageWithNameUnderParent(
name: _documentTwoName,
layout: ViewLayoutPB.Document,
);

View File

@ -290,7 +290,7 @@ extension CommonOperations on WidgetTester {
await tapButton(markdownButton);
}
Future<void> createNewPageWithName({
Future<void> createNewPageWithNameUnderParent({
String? name,
ViewLayoutPB layout = ViewLayoutPB.Document,
String? parentName,
@ -333,6 +333,13 @@ extension CommonOperations on WidgetTester {
}
}
Future<void> createNewPage({
ViewLayoutPB layout = ViewLayoutPB.Document,
bool openAfterCreated = true,
}) async {
await tapButton(find.byType(SidebarNewPageButton));
}
Future<void> simulateKeyEvent(
LogicalKeyboardKey key, {
bool isControlPressed = false,

View File

@ -18,7 +18,7 @@ const String gettingStarted = 'Getting started';
extension Expectation on WidgetTester {
/// Expect to see the home page and with a default read me page.
Future<void> expectToSeeHomePage() async {
Future<void> expectToSeeHomePageWithGetStartedPage() async {
final finder = find.byType(HomeStack);
await pumpUntilFound(finder);
expect(finder, findsOneWidget);
@ -27,6 +27,12 @@ extension Expectation on WidgetTester {
await pumpUntilFound(docFinder);
}
Future<void> expectToSeeHomePage() async {
final finder = find.byType(HomeStack);
await pumpUntilFound(finder);
expect(finder, findsOneWidget);
}
/// Expect to see the page name on the home page.
void expectToSeePageName(
String name, {

View File

@ -49,7 +49,6 @@ class NetworkListener {
return NetworkTypePB.NetworkUnknown;
}
}();
Log.info("Network type: $networkType");
final state = NetworkStatePB.create()..ty = networkType;
UserEventUpdateNetworkState(state).send().then((result) {
result.fold(

View File

@ -105,7 +105,7 @@ enum AuthenticatorType {
supabase,
appflowyCloud;
bool get isEnabled => this != AuthenticatorType.local;
bool get isLocal => this == AuthenticatorType.local;
int get value {
switch (this) {
case AuthenticatorType.local:
@ -161,8 +161,12 @@ class AppFlowyCloudSharedEnv {
if (Env.enableCustomCloud) {
// Use the custom cloud configuration.
final cloudType = await getAuthenticatorType();
final appflowyCloudConfig = await getAppFlowyCloudConfig();
final supabaseCloudConfig = await getSupabaseCloudConfig();
final appflowyCloudConfig = cloudType.isLocal
? AppFlowyCloudConfiguration.defaultConfig()
: await getAppFlowyCloudConfig();
final supabaseCloudConfig = cloudType.isLocal
? SupabaseConfiguration.defaultConfig()
: await getSupabaseCloudConfig();
return AppFlowyCloudSharedEnv(
authenticatorType: cloudType,
@ -184,6 +188,13 @@ class AppFlowyCloudSharedEnv {
);
}
}
@override
String toString() {
return 'authenticator: $_authenticatorType\n'
'appflowy: ${appflowyCloudConfig.toJson()}\n'
'supabase: ${supabaseConfig.toJson()})\n';
}
}
Future<AppFlowyCloudConfiguration> configurationFromUri(

View File

@ -28,9 +28,10 @@ import 'package:appflowy/workspace/application/user/prelude.dart';
import 'package:appflowy/workspace/application/view/prelude.dart';
import 'package:appflowy/workspace/application/workspace/prelude.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:flowy_infra/file_picker/file_picker_impl.dart';
import 'package:flowy_infra/file_picker/file_picker_service.dart';
import 'package:fluttertoast/fluttertoast.dart';
@ -55,6 +56,7 @@ class DependencyResolver {
Future<void> _resolveCloudDeps(GetIt getIt) async {
final env = await AppFlowyCloudSharedEnv.fromEnv();
Log.info("cloud setting: \n$env");
getIt.registerFactory<AppFlowyCloudSharedEnv>(() => env);
if (isAppFlowyCloudEnabled) {

View File

@ -4,7 +4,6 @@ import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy_backend/appflowy_backend.dart';
import 'package:appflowy_backend/log.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
@ -139,9 +138,14 @@ Future<void> initGetIt(
LaunchConfiguration config,
) async {
getIt.registerFactory<EntryPoint>(() => f);
getIt.registerLazySingleton<FlowySDK>(() {
return FlowySDK();
});
getIt.registerLazySingleton<FlowySDK>(
() {
return FlowySDK();
},
dispose: (sdk) async {
await sdk.dispose();
},
);
getIt.registerLazySingleton<AppLauncher>(
() => AppLauncher(
context: LaunchContext(
@ -205,7 +209,6 @@ class AppLauncher {
}
Future<void> dispose() async {
Log.info('AppLauncher dispose');
for (final task in tasks) {
await task.dispose();
}

View File

@ -87,7 +87,7 @@ class AppFlowyCloudDeepLink {
(_) async {
final deviceId = await getDeviceId();
final payload = OauthSignInPB(
authType: AuthenticatorPB.AppFlowyCloud,
authenticator: AuthenticatorPB.AppFlowyCloud,
map: {
AuthServiceMapKeys.signInURL: uri.toString(),
AuthServiceMapKeys.deviceId: deviceId,

View File

@ -5,6 +5,7 @@ import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/application/auth/device_id.dart';
import 'package:appflowy/user/application/user_service.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:dartz/dartz.dart';
@ -45,7 +46,7 @@ class AppFlowyCloudMockAuthService implements AuthService {
Map<String, String> params = const {},
}) async {
final payload = SignInUrlPayloadPB.create()
..authType = AuthenticatorPB.AppFlowyCloud
..authenticator = AuthenticatorPB.AppFlowyCloud
// don't use nanoid here, the gotrue server will transform the email
..email = userEmail;
@ -55,17 +56,22 @@ class AppFlowyCloudMockAuthService implements AuthService {
return getSignInURLResult.fold(
(urlPB) async {
final payload = OauthSignInPB(
authType: AuthenticatorPB.AppFlowyCloud,
authenticator: AuthenticatorPB.AppFlowyCloud,
map: {
AuthServiceMapKeys.signInURL: urlPB.signInUrl,
AuthServiceMapKeys.deviceId: deviceId,
},
);
return await UserEventOauthSignIn(payload)
.send()
.then((value) => value.swap());
Log.info("UserEventOauthSignIn with payload: $payload");
return await UserEventOauthSignIn(payload).send().then((value) {
value.fold((l) => null, (err) => Log.error(err));
return value.swap();
});
},
(r) {
Log.error(r);
return left(r);
},
(r) => left(r),
);
}

View File

@ -171,7 +171,7 @@ class SupabaseAuthService implements AuthService {
required Map<String, String> map,
}) async {
final payload = OauthSignInPB(
authType: AuthenticatorPB.Supabase,
authenticator: AuthenticatorPB.Supabase,
map: map,
);

View File

@ -67,7 +67,7 @@ class SupabaseMockAuthService implements AuthService {
// Create the OAuth sign-in payload.
final payload = OauthSignInPB(
authType: AuthenticatorPB.Supabase,
authenticator: AuthenticatorPB.Supabase,
map: {
AuthServiceMapKeys.uuid: uuid,
AuthServiceMapKeys.email: email,

View File

@ -1,5 +1,4 @@
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/env/env.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
@ -95,9 +94,6 @@ class SplashScreen extends StatelessWidget {
}
void _handleUnauthenticated(BuildContext context, Unauthenticated result) {
Log.trace(
"_handleUnauthenticated -> enable custom cloud: ${Env.enableCustomCloud}, appflowy cloud is enabled: $isAppFlowyCloudEnabled, appflowy cloud config: ${getIt<AppFlowyCloudSharedEnv>().appflowyCloudConfig.toJson()}",
);
// replace Splash screen as root page
if (isAuthEnabled || PlatformExtension.isMobile) {
context.go(SignInScreen.routeName);

View File

@ -7,7 +7,6 @@ import 'package:appflowy/workspace/application/favorite/favorite_listener.dart';
import 'package:appflowy/workspace/application/recent/recent_service.dart';
import 'package:appflowy/workspace/application/view/view_listener.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:collection/collection.dart';
@ -256,9 +255,6 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
Future<ViewPB?> _updateChildViews(
ChildViewUpdatePB update,
) async {
Log.debug(
'received child views of ${this.view.name}(${this.view.id}) update, $update',
);
if (update.createChildViews.isNotEmpty) {
// refresh the child views if the update isn't empty
// because there's no info to get the inserted index.

View File

@ -24,7 +24,7 @@ class FlowySDK {
FlowySDK();
void dispose() {}
Future<void> dispose() async {}
Future<void> init(String configuration) async {
final port = RustStreamReceiver.shared.port;

View File

@ -139,7 +139,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
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=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"app-error",
@ -1325,7 +1325,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa 1.0.6",
"phf 0.11.2",
"phf 0.8.0",
"smallvec",
]
@ -1471,7 +1471,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
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=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
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=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
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=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"reqwest",
@ -4378,7 +4378,6 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_macros 0.11.2",
"phf_shared 0.11.2",
]
@ -4470,19 +4469,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator 0.11.2",
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.32",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
@ -4724,7 +4710,7 @@ checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac"
dependencies = [
"bytes",
"heck 0.4.1",
"itertools 0.11.0",
"itertools 0.10.5",
"log",
"multimap",
"once_cell",
@ -4745,7 +4731,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
dependencies = [
"anyhow",
"itertools 0.11.0",
"itertools 0.10.5",
"proc-macro2",
"quote",
"syn 2.0.32",
@ -5040,7 +5026,7 @@ dependencies = [
[[package]]
name = "realtime-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"bincode",
@ -5062,7 +5048,7 @@ dependencies = [
[[package]]
name = "realtime-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"bincode",
@ -5809,7 +5795,7 @@ dependencies = [
[[package]]
name = "shared_entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"app-error",
@ -7699,7 +7685,7 @@ dependencies = [
[[package]]
name = "workspace-template"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"async-trait",

View File

@ -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 = "80d4048c69a22c0af77b2f2e9b13b1004b2156e2" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "a455c9de8e6448cec956da5a00ba5cc136ed7274" }
# Please use the following script to update collab.
# Working directory: frontend
#

View File

@ -125,7 +125,7 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
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=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"app-error",
@ -1149,7 +1149,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa",
"phf 0.11.2",
"phf 0.8.0",
"smallvec",
]
@ -1277,7 +1277,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
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=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
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=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
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=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"reqwest",
@ -3665,7 +3665,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [
"phf_macros 0.8.0",
"phf_macros",
"phf_shared 0.8.0",
"proc-macro-hack",
]
@ -3685,7 +3685,6 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_macros 0.11.2",
"phf_shared 0.11.2",
]
@ -3753,19 +3752,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator 0.11.2",
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.31",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
@ -3969,7 +3955,7 @@ checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac"
dependencies = [
"bytes",
"heck 0.4.1",
"itertools 0.11.0",
"itertools 0.10.5",
"log",
"multimap",
"once_cell",
@ -3990,7 +3976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
dependencies = [
"anyhow",
"itertools 0.11.0",
"itertools 0.10.5",
"proc-macro2",
"quote",
"syn 2.0.31",
@ -4329,7 +4315,7 @@ dependencies = [
[[package]]
name = "realtime-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"bincode",
@ -4351,7 +4337,7 @@ dependencies = [
[[package]]
name = "realtime-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"bincode",
@ -5020,7 +5006,7 @@ dependencies = [
[[package]]
name = "shared_entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"app-error",
@ -6401,7 +6387,7 @@ dependencies = [
[[package]]
name = "workspace-template"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=80d4048c69a22c0af77b2f2e9b13b1004b2156e2#80d4048c69a22c0af77b2f2e9b13b1004b2156e2"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=a455c9de8e6448cec956da5a00ba5cc136ed7274#a455c9de8e6448cec956da5a00ba5cc136ed7274"
dependencies = [
"anyhow",
"async-trait",

View File

@ -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 = "80d4048c69a22c0af77b2f2e9b13b1004b2156e2" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "a455c9de8e6448cec956da5a00ba5cc136ed7274" }
# Please use the following script to update collab.
# Working directory: frontend
#

View File

@ -71,6 +71,23 @@ pub struct AppFlowyCollabBuilder {
device_id: String,
}
pub struct CollabBuilderConfig {
pub sync_enable: bool,
}
impl Default for CollabBuilderConfig {
fn default() -> Self {
Self { sync_enable: true }
}
}
impl CollabBuilderConfig {
pub fn sync_enable(mut self, sync_enable: bool) -> Self {
self.sync_enable = sync_enable;
self
}
}
impl AppFlowyCollabBuilder {
pub fn new<T: CollabStorageProvider>(storage_provider: T, device_id: String) -> Self {
Self {
@ -144,12 +161,21 @@ impl AppFlowyCollabBuilder {
uid: i64,
object_id: &str,
object_type: CollabType,
raw_data: CollabRawData,
doc_state: CollabRawData,
collab_db: Weak<RocksCollabDB>,
build_config: CollabBuilderConfig,
) -> Result<Arc<MutexCollab>, Error> {
let config = CollabPersistenceConfig::default();
let persistence_config = CollabPersistenceConfig::default();
self
.build_with_config(uid, object_id, object_type, collab_db, raw_data, &config)
.build_with_config(
uid,
object_id,
object_type,
collab_db,
doc_state,
&persistence_config,
build_config,
)
.await
}
@ -167,88 +193,92 @@ impl AppFlowyCollabBuilder {
/// - `raw_data`: The raw data of the collaboration object, defined by the [CollabRawData] type.
/// - `collab_db`: A weak reference to the [RocksCollabDB].
///
#[allow(clippy::too_many_arguments)]
pub async fn build_with_config(
&self,
uid: i64,
object_id: &str,
object_type: CollabType,
collab_db: Weak<RocksCollabDB>,
collab_raw_data: CollabRawData,
config: &CollabPersistenceConfig,
doc_state: CollabRawData,
persistence_config: &CollabPersistenceConfig,
build_config: CollabBuilderConfig,
) -> Result<Arc<MutexCollab>, Error> {
let collab = Arc::new(
CollabBuilder::new(uid, object_id)
.with_raw_data(collab_raw_data)
.with_raw_data(doc_state)
.with_plugin(RocksdbDiskPlugin::new_with_config(
uid,
collab_db.clone(),
config.clone(),
persistence_config.clone(),
self.rocksdb_backup.lock().clone(),
))
.with_device_id(self.device_id.clone())
.build()?,
);
{
let cloud_storage_type = self.cloud_storage.read().await.storage_source();
let collab_object = self.collab_object(uid, object_id, object_type)?;
let span = tracing::span!(tracing::Level::TRACE, "collab_builder", object_id = %object_id);
let _enter = span.enter();
match cloud_storage_type {
CollabDataSource::AppFlowyCloud => {
#[cfg(feature = "appflowy_cloud_integrate")]
{
trace!("init appflowy cloud collab plugins");
let local_collab = Arc::downgrade(&collab);
let plugins = self
.cloud_storage
.read()
.await
.get_plugins(CollabStorageProviderContext::AppFlowyCloud {
uid,
collab_object: collab_object.clone(),
local_collab,
})
.await;
if build_config.sync_enable {
let cloud_storage_type = self.cloud_storage.read().await.storage_source();
let span = tracing::span!(tracing::Level::TRACE, "collab_builder", object_id = %object_id);
let _enter = span.enter();
match cloud_storage_type {
CollabDataSource::AppFlowyCloud => {
#[cfg(feature = "appflowy_cloud_integrate")]
{
trace!("init appflowy cloud collab plugins");
let local_collab = Arc::downgrade(&collab);
let plugins = self
.cloud_storage
.read()
.await
.get_plugins(CollabStorageProviderContext::AppFlowyCloud {
uid,
collab_object: collab_object.clone(),
local_collab,
})
.await;
trace!("add appflowy cloud collab plugins: {}", plugins.len());
for plugin in plugins {
collab.lock().add_plugin(plugin);
trace!("add appflowy cloud collab plugins: {}", plugins.len());
for plugin in plugins {
collab.lock().add_plugin(plugin);
}
}
}
},
CollabDataSource::Supabase => {
#[cfg(feature = "supabase_integrate")]
{
trace!("init supabase collab plugins");
let local_collab = Arc::downgrade(&collab);
let local_collab_db = collab_db.clone();
let plugins = self
.cloud_storage
.read()
.await
.get_plugins(CollabStorageProviderContext::Supabase {
uid,
collab_object: collab_object.clone(),
local_collab,
local_collab_db,
})
.await;
for plugin in plugins {
collab.lock().add_plugin(plugin);
},
CollabDataSource::Supabase => {
#[cfg(feature = "supabase_integrate")]
{
trace!("init supabase collab plugins");
let local_collab = Arc::downgrade(&collab);
let local_collab_db = collab_db.clone();
let plugins = self
.cloud_storage
.read()
.await
.get_plugins(CollabStorageProviderContext::Supabase {
uid,
collab_object: collab_object.clone(),
local_collab,
local_collab_db,
})
.await;
for plugin in plugins {
collab.lock().add_plugin(plugin);
}
}
}
},
CollabDataSource::Local => {},
},
CollabDataSource::Local => {},
}
}
if let Some(snapshot_persistence) = self.snapshot_persistence.lock().as_ref() {
if config.enable_snapshot {
if persistence_config.enable_snapshot {
let snapshot_plugin = CollabSnapshotPlugin::new(
uid,
collab_object,
snapshot_persistence.clone(),
collab_db,
config.snapshot_per_update,
persistence_config.snapshot_per_update,
);
// tracing::trace!("add snapshot plugin: {}", object_id);
collab.lock().add_plugin(Arc::new(snapshot_plugin));

View File

@ -70,6 +70,13 @@ pub extern "C" fn init_sdk(data: *mut c_char) -> i64 {
DEFAULT_NAME.to_string(),
)
.log_filter("info", log_crates);
// Ensure that the database is closed before initialization. Also, verify that the init_sdk function can be called
// multiple times (is reentrant). Currently, only the database resource is exclusive.
if let Some(core) = &*APPFLOWY_CORE.0.lock() {
core.close_db();
}
*APPFLOWY_CORE.0.lock() = Some(AppFlowyCore::new(config));
0
}

View File

@ -18,7 +18,7 @@ use crate::EventIntegrationTest;
const TEXT_BLOCK_TY: &str = "paragraph";
pub struct DocumentEventTest {
inner: EventIntegrationTest,
event_test: EventIntegrationTest,
}
pub struct OpenDocumentData {
@ -29,15 +29,15 @@ pub struct OpenDocumentData {
impl DocumentEventTest {
pub async fn new() -> Self {
let sdk = EventIntegrationTest::new_with_guest_user().await;
Self { inner: sdk }
Self { event_test: sdk }
}
pub fn new_with_core(core: EventIntegrationTest) -> Self {
Self { inner: core }
Self { event_test: core }
}
pub async fn create_document(&self) -> ViewPB {
let core = &self.inner;
let core = &self.event_test;
let current_workspace = core.get_current_workspace().await;
let parent_id = current_workspace.id.clone();
@ -61,22 +61,12 @@ impl DocumentEventTest {
}
pub async fn open_document(&self, doc_id: String) -> OpenDocumentData {
let core = &self.inner;
let payload = OpenDocumentPayloadPB {
document_id: doc_id.clone(),
};
let data = EventBuilder::new(core.clone())
.event(DocumentEvent::OpenDocument)
.payload(payload)
.async_send()
.await
.parse::<DocumentDataPB>();
OpenDocumentData { id: doc_id, data }
self.event_test.open_document(doc_id).await
}
pub async fn get_block(&self, doc_id: &str, block_id: &str) -> Option<BlockPB> {
let document = self.open_document(doc_id.to_string()).await;
document.data.blocks.get(block_id).cloned()
let document_data = self.event_test.open_document(doc_id.to_string()).await;
document_data.data.blocks.get(block_id).cloned()
}
pub async fn get_page_id(&self, doc_id: &str) -> String {
@ -85,8 +75,8 @@ impl DocumentEventTest {
}
pub async fn get_document_data(&self, doc_id: &str) -> DocumentDataPB {
let document = self.open_document(doc_id.to_string()).await;
document.data
let document_data = self.event_test.open_document(doc_id.to_string()).await;
document_data.data
}
pub async fn get_block_children(&self, doc_id: &str, block_id: &str) -> Option<Vec<String>> {
@ -104,7 +94,7 @@ impl DocumentEventTest {
}
pub async fn apply_actions(&self, payload: ApplyActionPayloadPB) {
let core = &self.inner;
let core = &self.event_test;
EventBuilder::new(core.clone())
.event(DocumentEvent::ApplyAction)
.payload(payload)
@ -116,7 +106,7 @@ impl DocumentEventTest {
&self,
payload: ConvertDocumentPayloadPB,
) -> ConvertDocumentResponsePB {
let core = &self.inner;
let core = &self.event_test;
EventBuilder::new(core.clone())
.event(DocumentEvent::ConvertDocument)
.payload(payload)
@ -130,7 +120,7 @@ impl DocumentEventTest {
&self,
payload: ConvertDataToJsonPayloadPB,
) -> ConvertDataToJsonResponsePB {
let core = &self.inner;
let core = &self.event_test;
EventBuilder::new(core.clone())
.event(DocumentEvent::ConvertDataToJSON)
.payload(payload)
@ -140,7 +130,7 @@ impl DocumentEventTest {
}
pub async fn create_text(&self, payload: TextDeltaPayloadPB) {
let core = &self.inner;
let core = &self.event_test;
EventBuilder::new(core.clone())
.event(DocumentEvent::CreateText)
.payload(payload)
@ -149,7 +139,7 @@ impl DocumentEventTest {
}
pub async fn apply_text_delta(&self, payload: TextDeltaPayloadPB) {
let core = &self.inner;
let core = &self.event_test;
EventBuilder::new(core.clone())
.event(DocumentEvent::ApplyTextDeltaEvent)
.payload(payload)
@ -158,7 +148,7 @@ impl DocumentEventTest {
}
pub async fn undo(&self, doc_id: String) -> DocumentRedoUndoResponsePB {
let core = &self.inner;
let core = &self.event_test;
let payload = DocumentRedoUndoPayloadPB {
document_id: doc_id.clone(),
};
@ -171,7 +161,7 @@ impl DocumentEventTest {
}
pub async fn redo(&self, doc_id: String) -> DocumentRedoUndoResponsePB {
let core = &self.inner;
let core = &self.event_test;
let payload = DocumentRedoUndoPayloadPB {
document_id: doc_id.clone(),
};
@ -184,7 +174,7 @@ impl DocumentEventTest {
}
pub async fn can_undo_redo(&self, doc_id: String) -> DocumentRedoUndoResponsePB {
let core = &self.inner;
let core = &self.event_test;
let payload = DocumentRedoUndoPayloadPB {
document_id: doc_id.clone(),
};

View File

@ -17,7 +17,7 @@ use crate::event_builder::EventBuilder;
use crate::EventIntegrationTest;
impl EventIntegrationTest {
pub async fn create_document(
pub async fn create_and_open_document(
&self,
parent_id: &str,
name: String,
@ -86,11 +86,11 @@ impl EventIntegrationTest {
DocumentData::from(pb)
}
pub async fn get_document_update(&self, document_id: &str) -> Vec<u8> {
pub async fn get_document_doc_state(&self, document_id: &str) -> Vec<u8> {
let workspace_id = self.user_manager.workspace_id().unwrap();
let cloud_service = self.document_manager.get_cloud_service().clone();
let remote_updates = cloud_service
.get_document_updates(document_id, &workspace_id)
.get_document_doc_state(document_id, &workspace_id)
.await
.unwrap();
@ -107,10 +107,10 @@ impl EventIntegrationTest {
}
}
pub fn assert_document_data_equal(collab_update: &[u8], doc_id: &str, expected: DocumentData) {
pub fn assert_document_data_equal(doc_state: &[u8], doc_id: &str, expected: DocumentData) {
let collab = MutexCollab::new(CollabOrigin::Server, doc_id, vec![]);
collab.lock().with_origin_transact_mut(|txn| {
let update = Update::decode_v1(collab_update).unwrap();
let update = Update::decode_v1(doc_state).unwrap();
txn.apply_update(update);
});
let document = Document::open(Arc::new(collab)).unwrap();

View File

@ -75,6 +75,14 @@ impl EventIntegrationTest {
.parse::<ViewPB>()
}
pub async fn get_trash(&self) -> RepeatedTrashPB {
EventBuilder::new(self.clone())
.event(FolderEvent::ListTrashItems)
.async_send()
.await
.parse::<RepeatedTrashPB>()
}
pub async fn delete_view(&self, view_id: &str) {
let payload = RepeatedViewIdPB {
items: vec![view_id.to_string()],

View File

@ -1,13 +1,17 @@
use std::env::temp_dir;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use nanoid::nanoid;
use parking_lot::RwLock;
use tokio::select;
use tokio::time::sleep;
use flowy_core::config::AppFlowyCoreConfig;
use flowy_core::AppFlowyCore;
use flowy_notification::register_notification_sender;
use flowy_server::AppFlowyServer;
use flowy_user::entities::AuthenticatorPB;
use crate::user_event::TestNotificationSender;
@ -21,8 +25,8 @@ pub mod user_event;
#[derive(Clone)]
pub struct EventIntegrationTest {
pub auth_type: Arc<RwLock<AuthenticatorPB>>,
pub inner: AppFlowyCore,
pub authenticator: Arc<RwLock<AuthenticatorPB>>,
pub appflowy_core: AppFlowyCore,
#[allow(dead_code)]
cleaner: Arc<Cleaner>,
pub notification_sender: TestNotificationSender,
@ -34,6 +38,7 @@ impl EventIntegrationTest {
std::fs::create_dir_all(&temp_dir).unwrap();
Self::new_with_user_data_path(temp_dir, nanoid!(6)).await
}
pub async fn new_with_user_data_path(path_buf: PathBuf, name: String) -> Self {
let path = path_buf.to_str().unwrap().to_string();
let device_id = uuid::Uuid::new_v4().to_string();
@ -42,22 +47,61 @@ impl EventIntegrationTest {
vec![
"flowy_test".to_string(),
"tokio".to_string(),
"lib_dispatch".to_string(),
// "lib_dispatch".to_string(),
],
);
let inner = init_core(config).await;
let notification_sender = TestNotificationSender::new();
let auth_type = Arc::new(RwLock::new(AuthenticatorPB::Local));
let authenticator = Arc::new(RwLock::new(AuthenticatorPB::Local));
register_notification_sender(notification_sender.clone());
// In case of dropping the runtime that runs the core, we need to forget the dispatcher
std::mem::forget(inner.dispatcher());
Self {
inner,
auth_type,
appflowy_core: inner,
authenticator,
notification_sender,
cleaner: Arc::new(Cleaner(path_buf)),
}
}
pub fn get_appflowy_cloud_server(&self) -> Arc<dyn AppFlowyServer> {
self
.appflowy_core
.server_provider
.get_appflowy_cloud_server()
.unwrap()
}
pub async fn wait_ws_connected(&self) {
if self
.get_appflowy_cloud_server()
.get_ws_state()
.is_connected()
{
return;
}
let mut ws_state = self
.get_appflowy_cloud_server()
.subscribe_ws_state()
.unwrap();
loop {
select! {
_ = sleep(Duration::from_secs(20)) => {
panic!("wait_ws_connected timeout");
}
state = ws_state.recv() => {
if let Ok(state) = &state {
if state.is_connected() {
break;
}
}
}
}
}
}
}
#[cfg(feature = "single_thread")]
@ -79,7 +123,7 @@ impl std::ops::Deref for EventIntegrationTest {
type Target = AppFlowyCore;
fn deref(&self) -> &Self::Target {
&self.inner
&self.appflowy_core
}
}

View File

@ -66,7 +66,7 @@ impl EventIntegrationTest {
.unwrap();
let request = AFPluginRequest::new(SignUp).payload(payload);
let user_profile = AFPluginDispatcher::async_send(self.inner.dispatcher(), request)
let user_profile = AFPluginDispatcher::async_send(self.appflowy_core.dispatcher(), request)
.await
.parse::<UserProfilePB, FlowyError>()
.unwrap()
@ -88,7 +88,7 @@ impl EventIntegrationTest {
let map = third_party_sign_up_param(Uuid::new_v4().to_string());
let payload = OauthSignInPB {
map,
auth_type: AuthenticatorPB::Supabase,
authenticator: AuthenticatorPB::Supabase,
};
EventBuilder::new(self.clone())
@ -107,7 +107,7 @@ impl EventIntegrationTest {
}
pub fn set_auth_type(&self, auth_type: AuthenticatorPB) {
*self.auth_type.write() = auth_type;
*self.authenticator.write() = auth_type;
}
pub async fn init_anon_user(&self) -> UserProfilePB {
@ -133,7 +133,7 @@ impl EventIntegrationTest {
pub async fn af_cloud_sign_in_with_email(&self, email: &str) -> FlowyResult<UserProfilePB> {
let payload = SignInUrlPayloadPB {
email: email.to_string(),
auth_type: AuthenticatorPB::AppFlowyCloud,
authenticator: 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: AuthenticatorPB::AppFlowyCloud,
authenticator: AuthenticatorPB::AppFlowyCloud,
};
let user_profile = EventBuilder::new(self.clone())
@ -175,7 +175,7 @@ impl EventIntegrationTest {
);
let payload = OauthSignInPB {
map,
auth_type: AuthenticatorPB::Supabase,
authenticator: AuthenticatorPB::Supabase,
};
let user_profile = EventBuilder::new(self.clone())
@ -246,7 +246,7 @@ impl TestNotificationSender {
F: Fn(&T) -> bool + Send + 'static,
{
let id = id.to_string();
let (tx, rx) = tokio::sync::mpsc::channel::<T>(10);
let (tx, rx) = tokio::sync::mpsc::channel::<T>(1);
let mut receiver = self.sender.subscribe();
af_spawn(async move {
while let Ok(value) = receiver.recv().await {

View File

@ -1,34 +1,37 @@
use std::time::Duration;
use event_integration::document_event::assert_document_data_equal;
use event_integration::user_event::user_localhost_af_cloud;
use event_integration::EventIntegrationTest;
use flowy_document2::entities::DocumentSyncStatePB;
use crate::document::af_cloud_test::util::AFCloudDocumentTest;
use crate::util::receive_with_timeout;
#[tokio::test]
async fn af_cloud_edit_document_test() {
if let Some(test) = AFCloudDocumentTest::new().await {
let document_id = test.create_document().await;
let cloned_test = test.clone();
let cloned_document_id = document_id.clone();
test.inner.dispatcher().spawn(async move {
cloned_test
.insert_document_text(&cloned_document_id, "hello world", 0)
.await;
});
user_localhost_af_cloud().await;
let test = EventIntegrationTest::new().await;
test.af_cloud_sign_up().await;
test.wait_ws_connected().await;
// wait all update are send to the remote
let rx = test
.notification_sender
.subscribe_with_condition::<DocumentSyncStatePB, _>(&document_id, |pb| !pb.is_syncing);
receive_with_timeout(rx, Duration::from_secs(25))
.await
.unwrap();
// create document and then insert content
let current_workspace = test.get_current_workspace().await;
let view = test
.create_and_open_document(&current_workspace.id, "my document".to_string(), vec![])
.await;
test.insert_document_text(&view.id, "hello world", 0).await;
let document_data = test.get_document_data(&document_id).await;
let update = test.get_document_update(&document_id).await;
assert!(!update.is_empty());
assert_document_data_equal(&update, &document_id, document_data);
}
let document_id = view.id;
println!("document_id: {}", document_id);
// wait all update are send to the remote
let rx = test
.notification_sender
.subscribe_with_condition::<DocumentSyncStatePB, _>(&document_id, |pb| !pb.is_syncing);
let _ = receive_with_timeout(rx, Duration::from_secs(30)).await;
let document_data = test.get_document_data(&document_id).await;
let doc_state = test.get_document_doc_state(&document_id).await;
assert!(!doc_state.is_empty());
assert_document_data_equal(&doc_state, &document_id, document_data);
}

View File

@ -1,2 +1 @@
mod edit_test;
mod util;

View File

@ -1,33 +0,0 @@
use std::ops::Deref;
use crate::util::{generate_test_email, AFCloudTest};
pub struct AFCloudDocumentTest {
inner: AFCloudTest,
}
impl AFCloudDocumentTest {
pub async fn new() -> Option<Self> {
let inner = AFCloudTest::new().await?;
let email = generate_test_email();
let _ = inner.af_cloud_sign_in_with_email(&email).await.unwrap();
Some(Self { inner })
}
pub async fn create_document(&self) -> String {
let current_workspace = self.inner.get_current_workspace().await;
let view = self
.inner
.create_document(&current_workspace.id, "my document".to_string(), vec![])
.await;
view.id
}
}
impl Deref for AFCloudDocumentTest {
type Target = AFCloudTest;
fn deref(&self) -> &Self::Target {
&self.inner
}
}

View File

@ -14,7 +14,7 @@ async fn supabase_document_edit_sync_test() {
let cloned_test = test.clone();
let cloned_document_id = document_id.clone();
test.inner.dispatcher().spawn(async move {
test.appflowy_core.dispatcher().spawn(async move {
cloned_test
.insert_document_text(&cloned_document_id, "hello world", 0)
.await;
@ -29,7 +29,7 @@ async fn supabase_document_edit_sync_test() {
.unwrap();
let document_data = test.get_document_data(&document_id).await;
let update = test.get_document_update(&document_id).await;
let update = test.get_document_doc_state(&document_id).await;
assert_document_data_equal(&update, &document_id, document_data);
}
}
@ -55,7 +55,7 @@ async fn supabase_document_edit_sync_test2() {
.unwrap();
let document_data = test.get_document_data(&document_id).await;
let update = test.get_document_update(&document_id).await;
let update = test.get_document_doc_state(&document_id).await;
assert_document_data_equal(&update, &document_id, document_data);
}
}

View File

@ -23,7 +23,7 @@ impl FlowySupabaseDocumentTest {
let current_workspace = self.inner.get_current_workspace().await;
self
.inner
.create_document(&current_workspace.id, "my document".to_string(), vec![])
.create_and_open_document(&current_workspace.id, "my document".to_string(), vec![])
.await
}

View File

@ -24,7 +24,7 @@ async fn create_child_view_in_workspace_subscription_test() {
let cloned_test = test.clone();
let cloned_workspace_id = workspace.id.clone();
test.inner.dispatcher().spawn(async move {
test.appflowy_core.dispatcher().spawn(async move {
cloned_test
.create_view(&cloned_workspace_id, "workspace child view".to_string())
.await;
@ -50,7 +50,7 @@ async fn create_child_view_in_view_subscription_test() {
let cloned_test = test.clone();
let child_view_id = workspace_child_view.id.clone();
test.inner.dispatcher().spawn(async move {
test.appflowy_core.dispatcher().spawn(async move {
cloned_test
.create_view(
&child_view_id,
@ -82,7 +82,7 @@ async fn delete_view_subscription_test() {
let delete_view_id = workspace.views.first().unwrap().id.clone();
let cloned_delete_view_id = delete_view_id.clone();
test
.inner
.appflowy_core
.dispatcher()
.spawn(async move {
cloned_test.delete_view(&cloned_delete_view_id).await;
@ -91,7 +91,7 @@ async fn delete_view_subscription_test() {
.unwrap();
let update = test
.inner
.appflowy_core
.dispatcher()
.run_until(receive_with_timeout(rx, Duration::from_secs(30)))
.await
@ -114,7 +114,7 @@ async fn update_view_subscription_test() {
assert!(!view.is_favorite);
let update_view_id = view.id.clone();
test.inner.dispatcher().spawn(async move {
test.appflowy_core.dispatcher().spawn(async move {
cloned_test
.update_view(UpdateViewPayloadPB {
view_id: update_view_id,

View File

@ -1,5 +1,7 @@
use event_integration::user_event::user_localhost_af_cloud;
use event_integration::EventIntegrationTest;
use flowy_core::DEFAULT_NAME;
use flowy_user::entities::AuthenticatorPB;
use crate::util::unzip_history_user_db;
@ -32,45 +34,86 @@ async fn reading_039_anon_user_data_test() {
assert_eq!(third_level_views[0].name, "Grid1".to_string());
assert_eq!(third_level_views[1].name, "Grid2".to_string());
let trash_items = test.get_trash().await.items;
assert_eq!(trash_items.len(), 1);
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);
// }
#[tokio::test]
async fn migrate_anon_user_data_to_af_cloud_test() {
let (cleaner, user_db_path) = unzip_history_user_db("./tests/asset", "040_local").unwrap();
// In the 040_local, the structure is:
// workspace:
// view: Document1
// view: Document2
// view: Grid1
// view: Grid2
user_localhost_af_cloud().await;
let test =
EventIntegrationTest::new_with_user_data_path(user_db_path.clone(), DEFAULT_NAME.to_string())
.await;
let anon_trash = test.get_trash().await;
assert_eq!(anon_trash.items.len(), 1);
assert_eq!(
anon_trash.items[0].name,
"Local Getting started".to_string()
);
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 anon_third_level_views = test
.get_views(&anon_second_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;
let user_trash = test.get_trash().await;
let workspace = test.get_current_workspace().await;
println!("user workspace: {:?}", workspace.id);
assert_eq!(user.authenticator, AuthenticatorPB::AppFlowyCloud);
let user_first_level_views = test.get_all_workspace_views().await;
println!("user first level views: {:?}", user_first_level_views);
let user_second_level_views = test
.get_views(&user_first_level_views[0].id)
.await
.child_views;
println!("user second level views: {:?}", user_second_level_views);
let user_third_level_views = test
.get_views(&user_second_level_views[0].id)
.await
.child_views;
println!("user third level views: {:?}", user_third_level_views);
// check first level
assert_eq!(anon_first_level_views.len(), 1);
assert_eq!(user_first_level_views.len(), 1);
assert_ne!(anon_first_level_views[0].id, user_first_level_views[0].id);
assert_eq!(
anon_first_level_views[0].name,
user_first_level_views[0].name
);
// check second level
assert_eq!(anon_second_level_views.len(), user_second_level_views.len());
assert_ne!(anon_second_level_views[0].id, user_second_level_views[0].id);
assert_eq!(
anon_second_level_views[0].name,
user_second_level_views[0].name
);
// check third level
assert_eq!(anon_third_level_views.len(), 2);
assert_eq!(user_third_level_views[0].name, "Grid1".to_string());
assert_eq!(user_third_level_views[1].name, "Grid2".to_string());
drop(cleaner);
// check the trash
assert_eq!(user_trash.items.len(), 1);
assert_eq!(user_trash.items[0].name, anon_trash.items[0].name);
}

View File

@ -1,41 +1,40 @@
use event_integration::user_event::user_localhost_af_cloud;
use event_integration::EventIntegrationTest;
use flowy_user::entities::UpdateUserProfilePayloadPB;
use crate::util::{generate_test_email, get_af_cloud_config};
use crate::util::generate_test_email;
#[tokio::test]
async fn af_cloud_sign_up_test() {
if get_af_cloud_config().is_some() {
let test = EventIntegrationTest::new().await;
let email = generate_test_email();
let user = test.af_cloud_sign_in_with_email(&email).await.unwrap();
assert_eq!(user.email, email);
}
user_localhost_af_cloud().await;
let test = EventIntegrationTest::new().await;
let email = generate_test_email();
let user = test.af_cloud_sign_in_with_email(&email).await.unwrap();
assert_eq!(user.email, email);
}
#[tokio::test]
async fn af_cloud_update_user_metadata() {
if get_af_cloud_config().is_some() {
let test = EventIntegrationTest::new().await;
let user = test.af_cloud_sign_up().await;
user_localhost_af_cloud().await;
let test = EventIntegrationTest::new().await;
let user = test.af_cloud_sign_up().await;
let old_profile = test.get_user_profile().await.unwrap();
assert_eq!(old_profile.openai_key, "".to_string());
let old_profile = test.get_user_profile().await.unwrap();
assert_eq!(old_profile.openai_key, "".to_string());
test
.update_user_profile(UpdateUserProfilePayloadPB {
id: user.id,
openai_key: Some("new openai key".to_string()),
stability_ai_key: Some("new stability ai key".to_string()),
..Default::default()
})
.await;
test
.update_user_profile(UpdateUserProfilePayloadPB {
id: user.id,
openai_key: Some("new openai key".to_string()),
stability_ai_key: Some("new stability ai key".to_string()),
..Default::default()
})
.await;
let new_profile = test.get_user_profile().await.unwrap();
assert_eq!(new_profile.openai_key, "new openai key".to_string());
assert_eq!(
new_profile.stability_ai_key,
"new stability ai key".to_string()
);
}
let new_profile = test.get_user_profile().await.unwrap();
assert_eq!(new_profile.openai_key, "new openai key".to_string());
assert_eq!(
new_profile.stability_ai_key,
"new stability ai key".to_string()
);
}

View File

@ -1,50 +1,47 @@
use event_integration::user_event::user_localhost_af_cloud;
use event_integration::EventIntegrationTest;
use crate::util::get_af_cloud_config;
#[tokio::test]
async fn af_cloud_add_workspace_member_test() {
if get_af_cloud_config().is_some() {
let test_1 = EventIntegrationTest::new().await;
let user_1 = test_1.af_cloud_sign_up().await;
user_localhost_af_cloud().await;
let test_1 = EventIntegrationTest::new().await;
let user_1 = test_1.af_cloud_sign_up().await;
let test_2 = EventIntegrationTest::new().await;
let user_2 = test_2.af_cloud_sign_up().await;
let test_2 = EventIntegrationTest::new().await;
let user_2 = test_2.af_cloud_sign_up().await;
let members = test_1.get_workspace_members(&user_1.workspace_id).await;
assert_eq!(members.len(), 1);
assert_eq!(members[0].email, user_1.email);
let members = test_1.get_workspace_members(&user_1.workspace_id).await;
assert_eq!(members.len(), 1);
assert_eq!(members[0].email, user_1.email);
test_1
.add_workspace_member(&user_1.workspace_id, &user_2.email)
.await;
test_1
.add_workspace_member(&user_1.workspace_id, &user_2.email)
.await;
let members = test_1.get_workspace_members(&user_1.workspace_id).await;
assert_eq!(members.len(), 2);
assert_eq!(members[0].email, user_1.email);
assert_eq!(members[1].email, user_2.email);
}
let members = test_1.get_workspace_members(&user_1.workspace_id).await;
assert_eq!(members.len(), 2);
assert_eq!(members[0].email, user_1.email);
assert_eq!(members[1].email, user_2.email);
}
#[tokio::test]
async fn af_cloud_delete_workspace_member_test() {
if get_af_cloud_config().is_some() {
let test_1 = EventIntegrationTest::new().await;
let user_1 = test_1.af_cloud_sign_up().await;
user_localhost_af_cloud().await;
let test_1 = EventIntegrationTest::new().await;
let user_1 = test_1.af_cloud_sign_up().await;
let test_2 = EventIntegrationTest::new().await;
let user_2 = test_2.af_cloud_sign_up().await;
let test_2 = EventIntegrationTest::new().await;
let user_2 = test_2.af_cloud_sign_up().await;
test_1
.add_workspace_member(&user_1.workspace_id, &user_2.email)
.await;
test_1
.add_workspace_member(&user_1.workspace_id, &user_2.email)
.await;
test_1
.delete_workspace_member(&user_1.workspace_id, &user_2.email)
.await;
test_1
.delete_workspace_member(&user_1.workspace_id, &user_2.email)
.await;
let members = test_1.get_workspace_members(&user_1.workspace_id).await;
assert_eq!(members.len(), 1);
assert_eq!(members[0].email, user_1.email);
}
let members = test_1.get_workspace_members(&user_1.workspace_id).await;
assert_eq!(members.len(), 1);
assert_eq!(members[0].email, user_1.email);
}

View File

@ -35,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: AuthenticatorPB::Supabase,
authenticator: AuthenticatorPB::Supabase,
};
let response = EventBuilder::new(test.clone())
@ -79,7 +79,7 @@ async fn third_party_sign_up_with_duplicated_uuid() {
.event(OauthSignIn)
.payload(OauthSignInPB {
map: map.clone(),
auth_type: AuthenticatorPB::Supabase,
authenticator: AuthenticatorPB::Supabase,
})
.async_send()
.await
@ -90,7 +90,7 @@ async fn third_party_sign_up_with_duplicated_uuid() {
.event(OauthSignIn)
.payload(OauthSignInPB {
map: map.clone(),
auth_type: AuthenticatorPB::Supabase,
authenticator: AuthenticatorPB::Supabase,
})
.async_send()
.await

View File

@ -21,7 +21,7 @@ async fn initial_workspace_test() {
);
let payload = OauthSignInPB {
map,
auth_type: AuthenticatorPB::Supabase,
authenticator: AuthenticatorPB::Supabase,
};
let _ = EventBuilder::new(test.clone())

View File

@ -8,8 +8,8 @@ use std::time::Duration;
use anyhow::Error;
use collab_folder::FolderData;
use collab_plugins::cloud_storage::RemoteCollabStorage;
use nanoid::nanoid;
use tokio::sync::mpsc::Receiver;
use tokio::time::timeout;
use uuid::Uuid;
use zip::ZipArchive;
@ -21,11 +21,11 @@ use flowy_database_deps::cloud::DatabaseCloudService;
use flowy_folder_deps::cloud::{FolderCloudService, FolderSnapshot};
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::{AuthenticatorPB, UpdateUserProfilePayloadPB};
use flowy_user::errors::FlowyError;
use flowy_user::event_map::UserCloudServiceProvider;
use flowy_user::event_map::UserEvent::*;
use flowy_user_deps::cloud::UserCloudService;
use flowy_user_deps::entities::Authenticator;
@ -36,26 +36,26 @@ pub fn get_supabase_config() -> Option<SupabaseConfiguration> {
}
pub struct FlowySupabaseTest {
inner: EventIntegrationTest,
event_test: EventIntegrationTest,
}
impl FlowySupabaseTest {
pub async fn new() -> Option<Self> {
let _ = get_supabase_config()?;
let test = EventIntegrationTest::new().await;
test.set_auth_type(AuthenticatorPB::Supabase);
test
let event_test = EventIntegrationTest::new().await;
event_test.set_auth_type(AuthenticatorPB::Supabase);
event_test
.server_provider
.set_authenticator(Authenticator::Supabase);
Some(Self { inner: test })
Some(Self { event_test })
}
pub async fn update_user_profile(
&self,
payload: UpdateUserProfilePayloadPB,
) -> Option<FlowyError> {
EventBuilder::new(self.inner.clone())
EventBuilder::new(self.event_test.clone())
.event(UpdateUserProfile)
.payload(payload)
.async_send()
@ -68,16 +68,12 @@ impl Deref for FlowySupabaseTest {
type Target = EventIntegrationTest;
fn deref(&self) -> &Self::Target {
&self.inner
&self.event_test
}
}
pub async fn receive_with_timeout<T>(
mut receiver: Receiver<T>,
duration: Duration,
) -> Result<T, Box<dyn std::error::Error + Send>> {
let res = timeout(duration, receiver.recv()).await.unwrap().unwrap();
Ok(res)
pub async fn receive_with_timeout<T>(mut receiver: Receiver<T>, duration: Duration) -> Option<T> {
timeout(duration, receiver.recv()).await.ok()?
}
pub fn get_supabase_ci_config() -> Option<SupabaseConfiguration> {
@ -171,7 +167,7 @@ pub fn unzip_history_user_db(root: &str, folder_name: &str) -> std::io::Result<(
// Open the zip file
let zip_file_path = format!("{}/{}.zip", root, folder_name);
let reader = File::open(zip_file_path)?;
let output_folder_path = format!("{}/unit_test_{}", root, nanoid!(6));
let output_folder_path = format!("{}/unit_test_{}", root, Uuid::new_v4());
// Create a ZipArchive from the file
let mut archive = ZipArchive::new(reader)?;
@ -202,44 +198,6 @@ pub fn unzip_history_user_db(root: &str, folder_name: &str) -> std::io::Result<(
))
}
pub struct AFCloudTest {
inner: EventIntegrationTest,
}
impl AFCloudTest {
pub async fn new() -> Option<Self> {
let _ = get_af_cloud_config()?;
let test = EventIntegrationTest::new().await;
test.set_auth_type(AuthenticatorPB::AppFlowyCloud);
test
.server_provider
.set_authenticator(Authenticator::AppFlowyCloud);
Some(Self { inner: test })
}
}
impl Deref for AFCloudTest {
type Target = EventIntegrationTest;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
pub fn generate_test_email() -> String {
format!("{}@test.com", Uuid::new_v4())
}
/// To run the test, create a .env.ci file in the 'event-integration' directory and set the following environment variables:
///
/// - `APPFLOWY_CLOUD_BASE_URL=http://localhost:8000`
/// - `APPFLOWY_CLOUD_WS_BASE_URL=ws://localhost:8000/ws`
/// - `APPFLOWY_CLOUD_GOTRUE_URL=http://localhost:9998`
///
/// - `GOTRUE_ADMIN_EMAIL=admin@example.com`
/// - `GOTRUE_ADMIN_PASSWORD=password`
pub fn get_af_cloud_config() -> Option<AFCloudConfiguration> {
dotenv::from_filename("./.env.ci").ok()?;
AFCloudConfiguration::from_env().ok()
}

View File

@ -13,7 +13,6 @@ use flowy_server::{AppFlowyEncryption, AppFlowyServer, EncryptionImpl};
use flowy_server_config::af_cloud_config::AFCloudConfiguration;
use flowy_server_config::supabase_config::SupabaseConfiguration;
use flowy_sqlite::kv::StorePreferences;
use flowy_user::services::db::{get_user_profile, get_user_workspace, open_user_db};
use flowy_user_deps::entities::*;
use crate::AppFlowyCoreConfig;
@ -90,8 +89,13 @@ impl ServerProvider {
*self.server.write() = server_type;
}
pub fn get_appflowy_cloud_server(&self) -> FlowyResult<Arc<dyn AppFlowyServer>> {
let server = self.get_server(&Server::AppFlowyCloud)?;
Ok(server)
}
/// Returns a [AppFlowyServer] trait implementation base on the provider_type.
pub(crate) fn get_server(&self, server_type: &Server) -> FlowyResult<Arc<dyn AppFlowyServer>> {
pub fn get_server(&self, server_type: &Server) -> FlowyResult<Arc<dyn AppFlowyServer>> {
if let Some(provider) = self.providers.read().get(server_type) {
return Ok(provider.clone());
}
@ -169,19 +173,22 @@ pub fn current_server_type(store_preferences: &Arc<StorePreferences>) -> Server
}
struct LocalServerDBImpl {
#[allow(dead_code)]
storage_path: String,
}
impl LocalServerDB for LocalServerDBImpl {
fn get_user_profile(&self, uid: i64) -> Result<UserProfile, FlowyError> {
let sqlite_db = open_user_db(&self.storage_path, uid)?;
let user_profile = get_user_profile(&sqlite_db, uid)?;
Ok(user_profile)
fn get_user_profile(&self, _uid: i64) -> Result<UserProfile, FlowyError> {
Err(
FlowyError::local_version_not_support()
.with_context("LocalServer doesn't support get_user_profile"),
)
}
fn get_user_workspace(&self, uid: i64) -> Result<Option<UserWorkspace>, FlowyError> {
let sqlite_db = open_user_db(&self.storage_path, uid)?;
let user_workspace = get_user_workspace(&sqlite_db, uid)?;
Ok(user_workspace)
fn get_user_workspace(&self, _uid: i64) -> Result<Option<UserWorkspace>, FlowyError> {
Err(
FlowyError::local_version_not_support()
.with_context("LocalServer doesn't support get_user_workspace"),
)
}
}

View File

@ -261,7 +261,7 @@ impl DatabaseCloudService for ServerProvider {
}
impl DocumentCloudService for ServerProvider {
fn get_document_updates(
fn get_document_doc_state(
&self,
document_id: &str,
workspace_id: &str,
@ -272,7 +272,7 @@ impl DocumentCloudService for ServerProvider {
FutureResult::new(async move {
server?
.document_service()
.get_document_updates(&document_id, &workspace_id)
.get_document_doc_state(&document_id, &workspace_id)
.await
})
}

View File

@ -66,6 +66,10 @@ impl AppFlowyCore {
runtime.block_on(Self::init(config, cloned_runtime))
}
pub fn close_db(&self) {
self.user_manager.close_db();
}
#[instrument(skip(config, runtime))]
async fn init(config: AppFlowyCoreConfig, runtime: Arc<AFPluginRuntime>) -> Self {
#[allow(clippy::if_same_then_else)]

View File

@ -16,7 +16,7 @@ use lru::LruCache;
use tokio::sync::{Mutex, RwLock};
use tracing::{event, instrument, trace};
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabBuilderConfig};
use collab_integrate::{CollabPersistenceConfig, RocksCollabDB};
use flowy_database_deps::cloud::DatabaseCloudService;
use flowy_error::{internal_error, FlowyError, FlowyResult};
@ -457,6 +457,7 @@ impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
collab_db,
collab_raw_data,
config,
CollabBuilderConfig::default().sync_enable(true),
))
.unwrap()
}

View File

@ -496,8 +496,10 @@ fn merge_groups(
merge_result.new_groups.extend(new_group_map.into_values());
// The `No status` group index is initialized to 0
if !no_status_group_inserted && no_status_group.is_some() {
merge_result.all_groups.insert(0, no_status_group.unwrap());
if !no_status_group_inserted {
if let Some(group) = no_status_group {
merge_result.all_groups.insert(0, group);
}
}
merge_result
}

View File

@ -8,7 +8,7 @@ use lib_infra::future::FutureResult;
/// Each kind of server should implement this trait. Check out the [AppFlowyServerProvider] of
/// [flowy-server] crate for more information.
pub trait DocumentCloudService: Send + Sync + 'static {
fn get_document_updates(
fn get_document_doc_state(
&self,
document_id: &str,
workspace_id: &str,

View File

@ -3,6 +3,9 @@ use std::sync::Arc;
use std::sync::Weak;
use collab::core::collab::{CollabRawData, MutexCollab};
use collab::core::collab_plugin::EncodedCollabV1;
use collab::core::origin::CollabOrigin;
use collab::preclude::Collab;
use collab_document::blocks::DocumentData;
use collab_document::document::Document;
use collab_document::document_data::{default_document_collab_data, default_document_data};
@ -12,10 +15,10 @@ use lru::LruCache;
use parking_lot::Mutex;
use tracing::{event, instrument};
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabBuilderConfig};
use collab_integrate::RocksCollabDB;
use flowy_document_deps::cloud::DocumentCloudService;
use flowy_error::{internal_error, FlowyError, FlowyResult};
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
use flowy_storage::FileStorageService;
use crate::document::MutexDocument;
@ -88,16 +91,26 @@ impl DocumentManager {
uid: i64,
doc_id: &str,
data: Option<DocumentData>,
) -> FlowyResult<Arc<MutexDocument>> {
) -> FlowyResult<()> {
tracing::trace!("create a document: {:?}", doc_id);
if self.is_doc_exist(doc_id).unwrap_or(false) {
self.get_document(doc_id).await
Err(FlowyError::new(
ErrorCode::RecordAlreadyExists,
format!("document {} already exists", doc_id),
))
} else {
let collab = self.collab_for_document(uid, doc_id, vec![]).await?;
let data = data.unwrap_or_else(default_document_data);
let document = Arc::new(MutexDocument::create_with_data(collab, data)?);
Ok(document)
let encoded_collab_v1 =
doc_state_from_document_data(doc_id, data.unwrap_or_else(default_document_data))?;
let collab = self
.collab_for_document(
uid,
doc_id,
vec![encoded_collab_v1.doc_state.to_vec()],
false,
)
.await?;
collab.lock().flush();
Ok(())
}
}
@ -113,7 +126,7 @@ impl DocumentManager {
// Try to get the document from the cloud service
let result: Result<CollabRawData, FlowyError> = self
.cloud_service
.get_document_updates(doc_id, &self.user.workspace_id()?)
.get_document_doc_state(doc_id, &self.user.workspace_id()?)
.await;
updates = match result {
@ -138,7 +151,7 @@ impl DocumentManager {
let uid = self.user.user_id()?;
event!(tracing::Level::DEBUG, "Initialize document: {}", doc_id);
let collab = self.collab_for_document(uid, doc_id, updates).await?;
let collab = self.collab_for_document(uid, doc_id, updates, true).await?;
let document = Arc::new(MutexDocument::open(doc_id, collab)?);
// save the document to the memory and read it from the memory if we open the same document again.
@ -155,11 +168,13 @@ impl DocumentManager {
if !self.is_doc_exist(doc_id)? {
updates = self
.cloud_service
.get_document_updates(doc_id, &self.user.workspace_id()?)
.get_document_doc_state(doc_id, &self.user.workspace_id()?)
.await?;
}
let uid = self.user.user_id()?;
let collab = self.collab_for_document(uid, doc_id, updates).await?;
let collab = self
.collab_for_document(uid, doc_id, updates, false)
.await?;
Document::open(collab)?
.get_document_data()
.map_err(internal_error)
@ -218,12 +233,20 @@ impl DocumentManager {
&self,
uid: i64,
doc_id: &str,
updates: Vec<Vec<u8>>,
doc_state: Vec<Vec<u8>>,
sync_enable: bool,
) -> FlowyResult<Arc<MutexCollab>> {
let db = self.user.collab_db(uid)?;
let collab = self
.collab_builder
.build(uid, doc_id, CollabType::Document, updates, db)
.build(
uid,
doc_id,
CollabType::Document,
doc_state,
db,
CollabBuilderConfig::default().sync_enable(sync_enable),
)
.await?;
Ok(collab)
}
@ -249,3 +272,16 @@ impl DocumentManager {
&self.storage_service
}
}
fn doc_state_from_document_data(
doc_id: &str,
data: DocumentData,
) -> Result<EncodedCollabV1, FlowyError> {
let collab = Arc::new(MutexCollab::from_collab(Collab::new_with_origin(
CollabOrigin::Empty,
doc_id,
vec![],
)));
let _ = Document::create_with_data(collab.clone(), data).map_err(internal_error)?;
Ok(collab.encode_collab_v1())
}

View File

@ -14,11 +14,11 @@ async fn restore_document() {
let doc_id: String = gen_document_id();
let data = default_document_data();
let uid = test.user.user_id().unwrap();
let document_a = test
test
.create_document(uid, &doc_id, Some(data.clone()))
.await
.unwrap();
let data_a = document_a.lock().get_document_data().unwrap();
let data_a = test.get_document_data(&doc_id).await.unwrap();
assert_eq!(data_a, data);
let data_b = test

View File

@ -57,7 +57,13 @@ pub struct FakeUser {
impl FakeUser {
pub fn new() -> Self {
Self { collab_db: db() }
setup_log();
let tempdir = TempDir::new().unwrap();
let path = tempdir.into_path();
let collab_db = Arc::new(RocksCollabDB::open(path).unwrap());
Self { collab_db }
}
}
@ -79,7 +85,7 @@ impl DocumentUser for FakeUser {
}
}
pub fn db() -> Arc<RocksCollabDB> {
pub fn setup_log() {
static START: Once = Once::new();
START.call_once(|| {
std::env::set_var("RUST_LOG", "collab_persistence=trace");
@ -89,10 +95,6 @@ pub fn db() -> Arc<RocksCollabDB> {
.finish();
subscriber.try_init().unwrap();
});
let tempdir = TempDir::new().unwrap();
let path = tempdir.into_path();
Arc::new(RocksCollabDB::open(path).unwrap())
}
pub fn default_collab_builder() -> Arc<AppFlowyCollabBuilder> {
@ -129,7 +131,7 @@ pub fn gen_id() -> String {
pub struct LocalTestDocumentCloudServiceImpl();
impl DocumentCloudService for LocalTestDocumentCloudServiceImpl {
fn get_document_updates(
fn get_document_doc_state(
&self,
_document_id: &str,
_workspace_id: &str,

View File

@ -262,6 +262,9 @@ pub enum ErrorCode {
#[error("rocksdb internal error")]
RocksdbInternal = 87,
#[error("Local version not support")]
LocalVersionNotSupport = 88,
}
impl ErrorCode {

View File

@ -59,6 +59,10 @@ impl FlowyError {
self.code == ErrorCode::UserUnauthorized || self.code == ErrorCode::RecordNotFound
}
pub fn is_local_version_not_support(&self) -> bool {
self.code == ErrorCode::LocalVersionNotSupport
}
static_flowy_error!(internal, ErrorCode::Internal);
static_flowy_error!(record_not_found, ErrorCode::RecordNotFound);
static_flowy_error!(workspace_name, ErrorCode::WorkspaceNameInvalid);
@ -105,6 +109,7 @@ impl FlowyError {
static_flowy_error!(collab_not_sync, ErrorCode::CollabDataNotSync);
static_flowy_error!(server_error, ErrorCode::InternalServerError);
static_flowy_error!(not_support, ErrorCode::NotSupportYet);
static_flowy_error!(local_version_not_support, ErrorCode::LocalVersionNotSupport);
}
impl std::convert::From<ErrorCode> for FlowyError {

View File

@ -10,7 +10,7 @@ use collab_folder::{
use parking_lot::{Mutex, RwLock};
use tracing::{error, event, info, instrument, Level};
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabBuilderConfig};
use collab_integrate::{CollabPersistenceConfig, RocksCollabDB};
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_folder_deps::cloud::{gen_view_id, FolderCloudService};
@ -134,6 +134,7 @@ impl FolderManager {
collab_db,
raw_data,
&CollabPersistenceConfig::new().enable_snapshot(true),
CollabBuilderConfig::default().sync_enable(true),
)
.await?;
Ok(collab)

View File

@ -67,7 +67,7 @@ impl FolderManager {
},
FolderInitDataSource::Cloud(raw_data) => {
if raw_data.is_empty() {
event!(Level::INFO, "remote folder data is empty, open from local");
event!(Level::ERROR, "remote folder data is empty, open from local");
self
.open_local_folder(uid, &workspace_id, collab_db, folder_notifier)
.await?
@ -111,7 +111,11 @@ impl FolderManager {
collab_db: Weak<RocksCollabDB>,
folder_notifier: FolderNotify,
) -> Result<Folder, FlowyError> {
event!(Level::INFO, "Create folder with default folder builder");
event!(
Level::INFO,
"Create folder:{} with default folder builder",
workspace_id
);
let folder_data =
DefaultFolderBuilder::build(uid, workspace_id.to_string(), &self.operation_handlers).await;
let collab = self

View File

@ -16,7 +16,7 @@ impl<T> DocumentCloudService for AFCloudDocumentCloudServiceImpl<T>
where
T: AFServer,
{
fn get_document_updates(
fn get_document_doc_state(
&self,
document_id: &str,
workspace_id: &str,

View File

@ -232,7 +232,7 @@ where
collab_object: &CollabObject,
data: Vec<u8>,
override_if_exist: bool,
) -> FutureResult<(), Error> {
) -> FutureResult<(), FlowyError> {
let try_get_client = self.server.try_get_client();
let collab_object = collab_object.clone();
FutureResult::new(async move {

View File

@ -168,6 +168,14 @@ impl AppFlowyServer for AppFlowyCloudServer {
Arc::new(AFCloudDocumentCloudServiceImpl(server))
}
fn subscribe_ws_state(&self) -> Option<WSConnectStateReceiver> {
Some(self.ws_client.subscribe_connect_state())
}
fn get_ws_state(&self) -> ConnectState {
self.ws_client.get_state()
}
#[allow(clippy::type_complexity)]
fn collab_ws_channel(
&self,

View File

@ -7,7 +7,7 @@ use lib_infra::future::FutureResult;
pub(crate) struct LocalServerDocumentCloudServiceImpl();
impl DocumentCloudService for LocalServerDocumentCloudServiceImpl {
fn get_document_updates(
fn get_document_doc_state(
&self,
_document_id: &str,
_workspace_id: &str,

View File

@ -121,7 +121,10 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
fn open_workspace(&self, _workspace_id: &str) -> FutureResult<UserWorkspace, FlowyError> {
FutureResult::new(async {
Err(FlowyError::not_support().with_context("local server doesn't support open workspace"))
Err(
FlowyError::local_version_not_support()
.with_context("local server doesn't support open workspace"),
)
})
}
@ -142,7 +145,7 @@ impl UserCloudService for LocalServerUserAuthServiceImpl {
_collab_object: &CollabObject,
_data: Vec<u8>,
_override_if_exist: bool,
) -> FutureResult<(), Error> {
) -> FutureResult<(), FlowyError> {
FutureResult::new(async { Ok(()) })
}
}

View File

@ -2,7 +2,7 @@ use std::sync::Arc;
use anyhow::Error;
use client_api::collab_sync::collab_msg::CollabMessage;
use client_api::ws::{WSConnectStateReceiver, WebSocketChannel};
use client_api::ws::{ConnectState, WSConnectStateReceiver, WebSocketChannel};
use collab_entity::CollabObject;
use collab_plugins::cloud_storage::RemoteCollabStorage;
use parking_lot::RwLock;
@ -108,6 +108,14 @@ pub trait AppFlowyServer: Send + Sync + 'static {
None
}
fn subscribe_ws_state(&self) -> Option<WSConnectStateReceiver> {
None
}
fn get_ws_state(&self) -> ConnectState {
ConnectState::Closed
}
#[allow(clippy::type_complexity)]
fn collab_ws_channel(
&self,

View File

@ -28,7 +28,7 @@ where
T: SupabaseServerService,
{
#[tracing::instrument(level = "debug", skip(self))]
fn get_document_updates(
fn get_document_doc_state(
&self,
document_id: &str,
workspace_id: &str,

View File

@ -311,7 +311,7 @@ where
collab_object: &CollabObject,
data: Vec<u8>,
_override_if_exist: bool,
) -> FutureResult<(), Error> {
) -> FutureResult<(), FlowyError> {
let try_get_postgrest = self.server.try_get_weak_postgrest();
let cloned_collab_object = collab_object.clone();
let (tx, rx) = channel();

View File

@ -142,7 +142,7 @@ pub trait UserCloudService: Send + Sync + 'static {
collab_object: &CollabObject,
data: Vec<u8>,
override_if_exist: bool,
) -> FutureResult<(), Error>;
) -> FutureResult<(), FlowyError>;
}
pub type UserUpdateReceiver = tokio::sync::mpsc::Receiver<UserUpdate>;

Some files were not shown because too many files have changed in this diff Show More