Compare commits

..
21 Commits
Author SHA1 Message Date
Lucas.Xu 09f5317768 chore: disable team workspace (#5099) 2024-04-09 09:46:53 +08:00
hasanbeder b2f0c4f109 chore: update tr-TR.json (#5095)
This commit updates the Turkish translations for the AppFlowy application. 

Several improvements and fixes have been made to enhance the accuracy and consistency of the translations. Additionally, translations for new features and UI elements have been added.

This update aims to provide a better user experience for Turkish-speaking users of AppFlowy. 🇹🇷

chore(localization): Update Turkish translations
feat(localization): Update Turkish translations (tr-TR.json)
fix(localization): Improve Turkish translations for accuracy and consistency
docs(localization): Add Turkish translations for new features and UI elements
2024-04-09 09:00:46 +08:00
Lucas.Xu da5b369aec feat: get view ancestors (#5096) 2024-04-09 08:58:53 +08:00
Lucas.Xu a92f3d30c2 chore: update editor version & update CHANGELOG (#5094)
* chore: update editor version

* chore: update changelog
2024-04-08 21:40:09 +08:00
Nathan.fooo 5c96a2c5cb chore: fix open workspace (#5092)
* chore: fix open workspace

* chore: fix open workspace
2024-04-08 20:55:02 +08:00
hongttandLucas.Xu 31798959c7 chore: update Vietnamese translations (#5080)
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
2024-04-08 20:43:38 +08:00
Kilu.He 5479d3ec6e chore: web build size optimization (#5071)
* chore: deploy test web

fix: update nginx.conf

fix: support https

* fix: support wasm gzip

* chore: optimize web build size

* fix: code review
2024-04-08 20:09:15 +08:00
Lucas.Xu 5777830730 feat: doc auto refresh (#5088)
* feat: doc auto refresh

* chore: update editor version
2024-04-08 18:01:20 +08:00
Nathan.fooo 79ea485a27 chore: update client api (#5087) 2024-04-08 16:13:37 +08:00
Lucas.Xu f0d8eee8a0 fix: doc state refresh (#5086) 2024-04-08 14:06:05 +08:00
Kilu.He 83b18c4825 fix: tauri ci error (#5085) 2024-04-08 12:11:58 +08:00
Lucas.Xu 429892aefc fix: delta insert assert (#5083) 2024-04-08 10:00:00 +08:00
JulesDmn d56de308e1 chore: update French translations (#5077) 2024-04-08 09:34:32 +08:00
Juliano Penna 3171712380 chore: enable more editor text to be translated (#4426) 2024-04-08 09:33:45 +08:00
47d321b8c2 fix: twelve hour parsing issue (#4721)
* fix: twelve hour time format fixed

* fix: time format for 12hour

* feat: auto capitalize am-pm in formatter

* fix: time field placeholder based on user time format

* chore: bugfix + improvements

---------

Co-authored-by: Mathias Mogensen <mathias@appflowy.io>
Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
2024-04-08 09:33:18 +08:00
Lucas.Xu 9536cde789 feat: add a loading indicator when creating, deleting, or switching workspaces. (#5067) 2024-04-07 23:06:33 +08:00
Nathan.fooo 3e32fac876 chore: pass platform info to rust side (#5079)
* chore: pass platform info to rust side

* chore: pass platform info to rust side

* chore: fix test

* chore: fix test

* chore: fix test

* chore: enable ios log
2024-04-07 21:36:55 +08:00
Nathan.fooo 81594fa796 chore: bump client api (#5078) 2024-04-07 15:22:37 +08:00
Nathan.fooo db6767f61e chore: fix create workspace bugs (#5074) 2024-04-06 21:59:37 +08:00
nathan 5ceb132b0b chore: disable supabase 2024-04-05 13:58:40 +08:00
Nathan.fooo 587de161f6 chore: bump collab and client api (#5069)
* chore: bump collab that do not emit awareness by default

* chore: bump collab
2024-04-05 13:57:34 +08:00
168 changed files with 3023 additions and 1784 deletions

No files matched your search

+73
View File
@@ -0,0 +1,73 @@
name: Deploy Web (Test)
on:
push:
branches:
- build/test
- main
env:
NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0"
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
env:
SSH_PRIVATE_KEY: ${{ secrets.WEB_TEST_SSH_PRIVATE_KEY }}
REMOTE_HOST: ${{ secrets.WEB_TEST_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.WEB_TEST_REMOTE_USER }}
SSL_CERTIFICATE: ${{ secrets.WEB_TEST_SSL_CERTIFICATE }}
SSL_CERTIFICATE_KEY: ${{ secrets.WEB_TEST_SSL_CERTIFICATE_KEY }}
ENV_FILE: test.env
steps:
- uses: actions/checkout@v4
- name: setup node
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
- name: setup pnpm
uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Node_modules cache
uses: actions/cache@v2
with:
path: frontend/appflowy_web_app/node_modules
key: node-modules-${{ runner.os }}
- name: install frontend dependencies
working-directory: frontend/appflowy_web_app
run: |
pnpm install
- name: copy env file
working-directory: frontend/appflowy_web_app
run: |
cp ${{ env.ENV_FILE }} .env
- name: test and lint
working-directory: frontend/appflowy_web_app
run: |
pnpm run lint
- name: build
working-directory: frontend/appflowy_web_app
run: |
pnpm run build
- name: generate SSL certificate
run: |
echo "${{ env.SSL_CERTIFICATE }}" > nginx-signed.crt
echo "${{ env.SSL_CERTIFICATE_KEY }}" > nginx-signed.key
- name: Deploy to EC2
uses: easingthemes/ssh-deploy@main
with:
SSH_PRIVATE_KEY: ${{ env.SSH_PRIVATE_KEY }}
ARGS: "-rlgoDzvc -i"
SOURCE: "frontend/appflowy_web_app/dist frontend/appflowy_web_app/Dockerfile frontend/appflowy_web_app/nginx.conf frontend/appflowy_web_app/.env nginx-signed.crt nginx-signed.key"
REMOTE_HOST: ${{ env.REMOTE_HOST }}
REMOTE_USER: ${{ env.REMOTE_USER }}
EXCLUDE: "frontend/appflowy_web_app/dist/, frontend/appflowy_web_app/node_modules/"
SCRIPT_AFTER: |
docker build -t appflowy-web-app .
docker rm -f appflowy-web-app || true
docker run -d -p 80:80 -p 443:443 --name appflowy-web-app appflowy-web-app
+4 -3
View File
@@ -86,6 +86,7 @@ jobs:
model: 'iPhone 15'
shutdown_after_job: false
- name: Run integration tests
working-directory: frontend/appflowy_flutter
run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}
# enable it again if the 12 mins timeout is fixed
# - name: Run integration tests
# working-directory: frontend/appflowy_flutter
# run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}
+15 -2
View File
@@ -47,6 +47,7 @@ jobs:
with:
path: frontend/appflowy_web_app/node_modules
key: node-modules-${{ runner.os }}
- name: install frontend dependencies
working-directory: frontend/appflowy_web_app
run: |
@@ -55,7 +56,19 @@ jobs:
working-directory: frontend/appflowy_web_app
run: |
pnpm run lint
- name: build
- name: build and analyze
working-directory: frontend/appflowy_web_app
run: |
pnpm run build
pnpm run analyze >> analyze-size.txt
- name: Upload analyze-size.txt
uses: actions/upload-artifact@v4
with:
name: analyze-size.txt
path: frontend/appflowy_web_app/analyze-size.txt
retention-days: 30
- name: Upload stats.html
uses: actions/upload-artifact@v4
with:
name: stats.html
path: frontend/appflowy_web_app/dist/stats.html
retention-days: 30
+7 -2
View File
@@ -1,9 +1,14 @@
# Release Notes
## Version 0.5.4 - 04/08/2024
### New Features
- TBD
- Introduced support for displaying a synchronization indicator within documents and databases to enhance user awareness of data sync status
- Revamped the select option cell editor in database
- Improved translations for Spanish, German, Kurdish, and Vietnamese
- Supported Android 6 and newer versions
### Bug Fixes
- TBD
- Resolved an issue where twelve-hour time formats were not being parsed correctly in databases
- Fixed a bug affecting the user interface of the single select option filter
- Fixed various minor UI issues
## Version 0.5.3 - 03/21/2024
### New Features
@@ -4,6 +4,7 @@ import 'dart:io';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
@@ -51,33 +52,23 @@ void main() {
await tester.expectToSeeHomePageWithGetStartedPage();
const name = 'AppFlowy.IO';
// the workspace will be opened after created
await tester.createCollaborativeWorkspace(name);
// see the success message
var success = find.text(LocaleKeys.workspace_createSuccess.tr());
expect(success, findsOneWidget);
await tester.pumpUntilNotFound(success);
final loading = find.byType(Loading);
await tester.pumpUntilNotFound(loading);
// check the create result
Finder success;
// delete the newly created workspace
await tester.openCollaborativeWorkspaceMenu();
var items = find.byType(WorkspaceMenuItem);
final Finder items = find.byType(WorkspaceMenuItem);
expect(items, findsNWidgets(2));
expect(
tester.widget<WorkspaceMenuItem>(items.last).workspace.name,
name,
);
// open the newly created workspace
await tester.tapButton(items.last, milliseconds: 1000);
success = find.text(LocaleKeys.workspace_openSuccess.tr());
await tester.pumpUntilFound(success);
expect(success, findsOneWidget);
await tester.pumpUntilNotFound(success);
await tester.closeCollaborativeWorkspaceMenu();
// delete the newly created workspace
await tester.openCollaborativeWorkspaceMenu();
final secondWorkspace = find.byType(WorkspaceMenuItem).last;
await tester.hoverOnWidget(
secondWorkspace,
@@ -97,20 +88,11 @@ void main() {
await tester.tapButton(find.text(LocaleKeys.button_ok.tr()));
// delete success
success = find.text(LocaleKeys.workspace_createSuccess.tr());
await tester.pumpUntilFound(success);
expect(success, findsOneWidget);
await tester.pumpUntilNotFound(success);
},
);
// check the result
await tester.openCollaborativeWorkspaceMenu();
items = find.byType(WorkspaceMenuItem);
expect(items, findsOneWidget);
expect(
tester.widget<WorkspaceMenuItem>(items.last).workspace.name != name,
true,
);
await tester.closeCollaborativeWorkspaceMenu();
});
});
}
@@ -180,7 +180,11 @@ extension AppFlowyTestBase on WidgetTester {
buttons: buttons,
warnIfMissed: warnIfMissed,
);
await pumpAndSettle(Duration(milliseconds: milliseconds));
await pumpAndSettle(
Duration(milliseconds: milliseconds),
EnginePhase.sendSemanticsUpdate,
const Duration(seconds: 5),
);
}
Future<void> tapButtonWithName(
@@ -528,7 +528,7 @@ extension CommonOperations on WidgetTester {
final workspace = find.byType(SidebarWorkspace);
expect(workspace, findsOneWidget);
// click it
await tapButton(workspace);
await tapButton(workspace, milliseconds: 2000);
}
Future<void> closeCollaborativeWorkspaceMenu() async {
@@ -560,7 +560,6 @@ extension CommonOperations on WidgetTester {
// input the workspace name
await enterText(find.byType(TextField), name);
await pumpAndSettle();
await tapButtonWithName(LocaleKeys.button_ok.tr());
}
+2
View File
@@ -11,6 +11,7 @@ class AppFlowyConfiguration {
required this.custom_app_path,
required this.origin_app_path,
required this.device_id,
required this.platform,
required this.authenticator_type,
required this.supabase_config,
required this.appflowy_cloud_config,
@@ -25,6 +26,7 @@ class AppFlowyConfiguration {
final String custom_app_path;
final String origin_app_path;
final String device_id;
final String platform;
final int authenticator_type;
final SupabaseConfiguration supabase_config;
final AppFlowyCloudConfiguration appflowy_cloud_config;
@@ -69,7 +69,7 @@ class MobileFolders extends StatelessWidget {
...isCollaborativeWorkspace
? [
MobileSectionFolder(
title: LocaleKeys.sideBar_public.tr(),
title: LocaleKeys.sideBar_workspace.tr(),
categoryType: FolderCategoryType.public,
views: state.section.publicViews,
),
@@ -2,8 +2,8 @@ import 'dart:io';
import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
import 'package:appflowy/plugins/document/application/doc_listener.dart';
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
import 'package:appflowy/plugins/document/application/document_listener.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/shared/appflowy_network_image.dart';
import 'package:appflowy/workspace/application/view/prelude.dart';
@@ -31,6 +31,7 @@ class MobileWorkspaceMenu extends StatelessWidget {
final workspace = workspaces[i];
children.add(
_WorkspaceMenuItem(
key: ValueKey(workspace.workspaceId),
userProfile: userProfile,
workspace: workspace,
showTopBorder: i == 0,
@@ -47,6 +48,7 @@ class MobileWorkspaceMenu extends StatelessWidget {
class _WorkspaceMenuItem extends StatelessWidget {
const _WorkspaceMenuItem({
super.key,
required this.userProfile,
required this.workspace,
required this.showTopBorder,
@@ -30,9 +30,9 @@ class DatabaseSyncBloc extends Bloc<DatabaseSyncEvent, DatabaseSyncBlocState> {
.then((value) => value.fold((s) => s, (f) => null));
emit(
state.copyWith(
shouldShowIndicator:
userProfile?.authenticator != AuthenticatorPB.Local &&
databaseId != null,
shouldShowIndicator: userProfile?.authenticator ==
AuthenticatorPB.AppFlowyCloud &&
databaseId != null,
),
);
if (databaseId != null) {
@@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/application/row/row_document_bloc.dart';
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_page.dart';
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
import 'package:appflowy/workspace/application/view_info/view_info_bloc.dart';
@@ -10,6 +8,7 @@ import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class RowDocument extends StatelessWidget {
@@ -1,8 +1,8 @@
// This file is "main.dart"
import 'package:freezed_annotation/freezed_annotation.dart';
part 'doc_awareness_metadata.freezed.dart';
part 'doc_awareness_metadata.g.dart';
part 'document_awareness_metadata.freezed.dart';
part 'document_awareness_metadata.g.dart';
@freezed
class DocumentAwarenessMetadata with _$DocumentAwarenessMetadata {
@@ -1,12 +1,12 @@
import 'dart:async';
import 'dart:convert';
import 'package:appflowy/plugins/document/application/doc_awareness_metadata.dart';
import 'package:appflowy/plugins/document/application/doc_collab_adapter.dart';
import 'package:appflowy/plugins/document/application/doc_listener.dart';
import 'package:appflowy/plugins/document/application/doc_service.dart';
import 'package:appflowy/plugins/document/application/doc_sync_state_listener.dart';
import 'package:appflowy/plugins/document/application/document_awareness_metadata.dart';
import 'package:appflowy/plugins/document/application/document_collab_adapter.dart';
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
import 'package:appflowy/plugins/document/application/document_listener.dart';
import 'package:appflowy/plugins/document/application/document_service.dart';
import 'package:appflowy/plugins/document/application/editor_transaction_adapter.dart';
import 'package:appflowy/plugins/trash/application/trash_service.dart';
import 'package:appflowy/shared/feature_flags.dart';
@@ -16,7 +16,9 @@ import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/util/color_generator/color_generator.dart';
import 'package:appflowy/util/color_to_hex_string.dart';
import 'package:appflowy/util/debounce.dart';
import 'package:appflowy/util/throttle.dart';
import 'package:appflowy/workspace/application/view/view_listener.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
@@ -35,7 +37,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'doc_bloc.freezed.dart';
part 'document_bloc.freezed.dart';
class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
DocumentBloc({
@@ -66,7 +68,12 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
StreamSubscription? _transactionSubscription;
final _updateSelectionDebounce = Debounce();
final _syncDocDebounce = Debounce();
final _syncThrottle = Throttler(duration: const Duration(milliseconds: 500));
// The conflict handle logic is not fully implemented yet
// use the syncTimer to force to reload the document state when the conflict happens.
Timer? _syncTimer;
bool _shouldSync = false;
bool get isLocalMode {
final userProfilePB = state.userProfilePB;
@@ -81,6 +88,8 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
await _viewListener.stop();
await _transactionSubscription?.cancel();
await _documentService.closeDocument(view: view);
_syncTimer?.cancel();
_syncTimer = null;
state.editorState?.service.keyboardService?.closeKeyboard();
state.editorState?.dispose();
return super.close();
@@ -92,6 +101,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
) async {
await event.when(
initial: () async {
_resetSyncTimer();
final result = await _fetchDocumentState();
_onViewChanged();
_onDocumentChanged();
@@ -155,7 +165,7 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
/// subscribe to the document content change
void _onDocumentChanged() {
_documentListener.start(
onDocEventUpdate: _debounceSyncDoc,
onDocEventUpdate: _throttleSyncDoc,
onDocAwarenessUpdate: _onAwarenessStatesUpdate,
);
@@ -168,6 +178,19 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
);
}
void _resetSyncTimer() {
_syncTimer?.cancel();
_syncTimer = null;
_syncTimer = Timer.periodic(const Duration(seconds: 10), (_) {
if (!_shouldSync) {
return;
}
Log.debug('auto sync document');
// unawaited(_documentCollabAdapter.forceReload());
_shouldSync = false;
});
}
/// Fetch document
Future<FlowyResult<EditorState?, FlowyError>> _fetchDocumentState() async {
final result = await _documentService.openDocument(viewId: view.id);
@@ -207,6 +230,10 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
// ignore: invalid_use_of_visible_for_testing_member
emit(state.copyWith(isDocumentEmpty: editorState.document.isEmpty));
}
// reset the sync timer
_shouldSync = true;
_resetSyncTimer();
},
);
@@ -267,7 +294,9 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
return;
}
unawaited(_documentCollabAdapter.syncV3(docEvent));
unawaited(_documentCollabAdapter.syncV3(docEvent: docEvent));
_resetSyncTimer();
}
Future<void> _onAwarenessStatesUpdate(
@@ -290,8 +319,9 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
_updateSelectionDebounce.call(_onSelectionUpdate);
}
void _debounceSyncDoc(DocEventPB docEvent) {
_syncDocDebounce.call(() {
void _throttleSyncDoc(DocEventPB docEvent) {
_shouldSync = true;
_syncThrottle.call(() {
_onDocumentStateUpdate(docEvent);
});
}
@@ -1,6 +1,6 @@
import 'dart:convert';
import 'package:appflowy/plugins/document/application/doc_awareness_metadata.dart';
import 'package:appflowy/plugins/document/application/document_awareness_metadata.dart';
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
import 'package:appflowy/plugins/document/application/prelude.dart';
import 'package:appflowy/shared/list_extension.dart';
@@ -68,7 +68,7 @@ class DocumentCollabAdapter {
/// Sync version 3
///
/// Diff the local document with the remote document and apply the changes
Future<void> syncV3(DocEventPB docEvent) async {
Future<void> syncV3({DocEventPB? docEvent}) async {
final result = await _service.getDocument(viewId: docId);
final document = result.fold((s) => s.toDocument(), (f) => null);
if (document == null) {
@@ -77,17 +77,51 @@ class DocumentCollabAdapter {
final ops = diffNodes(editorState.document.root, document.root);
if (ops.isEmpty) {
debugPrint('[collab] received empty ops');
Log.info('Doc diff, no changes');
return;
}
debugPrint('[collab] received ops: $ops');
// Use for debugging, DO NOT REMOVE
// prettyPrintJson(ops.map((op) => op.toJson()).toList());
final transaction = editorState.transaction;
for (final op in ops) {
transaction.add(op);
}
await editorState.apply(transaction, isRemote: true);
// Use for debugging, DO NOT REMOVE
// assert(() {
// final local = editorState.document.root.toJson();
// final remote = document.root.toJson();
// if (!const DeepCollectionEquality().equals(local, remote)) {
// Log.error('Invalid diff status');
// Log.error('Local: $local');
// Log.error('Remote: $remote');
// return false;
// }
// return true;
// }());
}
Future<void> forceReload() async {
final result = await _service.getDocument(viewId: docId);
final document = result.fold((s) => s.toDocument(), (f) => null);
if (document == null) {
return;
}
final beforeSelection = editorState.selection;
final clear = editorState.transaction;
clear.deleteNodes(editorState.document.root.children);
await editorState.apply(clear, isRemote: true);
final insert = editorState.transaction;
insert.insertNodes([0], document.root.children);
await editorState.apply(insert, isRemote: true);
editorState.selection = beforeSelection;
}
Future<void> _syncUpdated(
@@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:convert';
import 'package:appflowy/plugins/document/application/doc_awareness_metadata.dart';
import 'package:appflowy/plugins/document/application/doc_listener.dart';
import 'package:appflowy/plugins/document/application/document_awareness_metadata.dart';
import 'package:appflowy/plugins/document/application/document_listener.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/startup/tasks/device_info_task.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
@@ -13,7 +13,7 @@ import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'doc_collaborators_bloc.freezed.dart';
part 'document_collaborators_bloc.freezed.dart';
bool _filterCurrentUser = false;
@@ -32,7 +32,7 @@ class DocumentCollaboratorsBloc
emit(
state.copyWith(
shouldShowIndicator:
userProfile?.authenticator != AuthenticatorPB.Local,
userProfile?.authenticator == AuthenticatorPB.AppFlowyCloud,
),
);
final deviceId = ApplicationInfo.deviceId;
@@ -8,10 +8,11 @@ import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'share_bloc.freezed.dart';
part 'document_share_bloc.freezed.dart';
class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
DocShareBloc({required this.view}) : super(const DocShareState.initial()) {
class DocumentShareBloc extends Bloc<DocumentShareEvent, DocumentShareState> {
DocumentShareBloc({required this.view})
: super(const DocumentShareState.initial()) {
on<ShareMarkdown>(_onShareMarkdown);
}
@@ -19,14 +20,14 @@ class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
Future<void> _onShareMarkdown(
ShareMarkdown event,
Emitter<DocShareState> emit,
Emitter<DocumentShareState> emit,
) async {
emit(const DocShareState.loading());
emit(const DocumentShareState.loading());
final documentExporter = DocumentExporter(view);
final result = await documentExporter.export(DocumentExportType.markdown);
emit(
DocShareState.finish(
DocumentShareState.finish(
result.fold(
(markdown) =>
FlowyResult.success(_saveMarkdownToPath(markdown, event.path)),
@@ -45,17 +46,17 @@ class DocShareBloc extends Bloc<DocShareEvent, DocShareState> {
}
@freezed
class DocShareEvent with _$DocShareEvent {
const factory DocShareEvent.shareMarkdown(String path) = ShareMarkdown;
const factory DocShareEvent.shareText() = ShareText;
const factory DocShareEvent.shareLink() = ShareLink;
class DocumentShareEvent with _$DocumentShareEvent {
const factory DocumentShareEvent.shareMarkdown(String path) = ShareMarkdown;
const factory DocumentShareEvent.shareText() = ShareText;
const factory DocumentShareEvent.shareLink() = ShareLink;
}
@freezed
class DocShareState with _$DocShareState {
const factory DocShareState.initial() = _Initial;
const factory DocShareState.loading() = _Loading;
const factory DocShareState.finish(
class DocumentShareState with _$DocumentShareState {
const factory DocumentShareState.initial() = _Initial;
const factory DocumentShareState.loading() = _Loading;
const factory DocumentShareState.finish(
FlowyResult<ExportDataPB, FlowyError> successOrFail,
) = _Finish;
}
@@ -11,7 +11,7 @@ import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'doc_sync_bloc.freezed.dart';
part 'document_sync_bloc.freezed.dart';
class DocumentSyncBloc extends Bloc<DocumentSyncEvent, DocumentSyncBlocState> {
DocumentSyncBloc({
@@ -31,7 +31,7 @@ class DocumentSyncBloc extends Bloc<DocumentSyncEvent, DocumentSyncBlocState> {
emit(
state.copyWith(
shouldShowIndicator:
userProfile?.authenticator != AuthenticatorPB.Local,
userProfile?.authenticator == AuthenticatorPB.AppFlowyCloud,
),
);
_syncStateListener.start(
@@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:convert';
import 'package:appflowy/plugins/document/application/doc_service.dart';
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
import 'package:appflowy/plugins/document/application/document_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart'
@@ -1,3 +1,3 @@
export 'doc_bloc.dart';
export 'doc_service.dart';
export 'share_bloc.dart';
export 'document_bloc.dart';
export 'document_service.dart';
export 'document_share_bloc.dart';
@@ -145,7 +145,7 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder
? [
DocumentCollaborators(
key: ValueKey('collaborators_${view.id}'),
width: 100,
width: 150,
height: 32,
view: view,
),
@@ -1,5 +1,5 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/banner.dart';
import 'package:appflowy/plugins/document/presentation/editor_notification.dart';
import 'package:appflowy/plugins/document/presentation/editor_page.dart';
@@ -39,17 +39,12 @@ class _DocumentPageState extends State<DocumentPage> {
@override
void initState() {
super.initState();
// The appflowy editor use Intl as localization, set the default language as fallback.
Intl.defaultLocale = 'en_US';
EditorNotification.addListener(_onEditorNotification);
}
@override
void dispose() {
EditorNotification.removeListener(_onEditorNotification);
super.dispose();
}
@@ -13,6 +13,7 @@ class CollaboratorAvatarStack extends StatelessWidget {
this.borderWidth,
this.borderColor,
this.backgroundColor,
required this.plusWidgetBuilder,
});
final List<Widget> avatars;
@@ -31,13 +32,16 @@ class CollaboratorAvatarStack extends StatelessWidget {
final Color? backgroundColor;
final Widget Function(int value, BorderSide border) plusWidgetBuilder;
@override
Widget build(BuildContext context) {
final settings = this.settings ??
RestrictedPositions(
maxCoverage: 0.3,
minCoverage: 0.1,
minCoverage: 0.2,
align: StackAlign.right,
laying: StackLaying.first,
);
final border = BorderSide(
@@ -45,27 +49,12 @@ class CollaboratorAvatarStack extends StatelessWidget {
width: borderWidth ?? 2.0,
);
Widget textInfoWidgetBuilder(surplus) => BorderedCircleAvatar(
border: border,
backgroundColor: backgroundColor,
child: FittedBox(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'+$surplus',
style: Theme.of(context).textTheme.titleLarge,
),
),
),
);
final infoWidgetBuilder = this.infoWidgetBuilder ?? textInfoWidgetBuilder;
return SizedBox(
height: height,
width: width,
child: WidgetStack(
positions: settings,
buildInfoWidget: infoWidgetBuilder,
buildInfoWidget: (value) => plusWidgetBuilder(value, border),
stackedWidgets: avatars
.map(
(avatar) => CircleAvatar(
@@ -1,7 +1,8 @@
import 'package:appflowy/plugins/document/application/doc_collaborators_bloc.dart';
import 'package:appflowy/plugins/document/application/document_collaborators_bloc.dart';
import 'package:appflowy/plugins/document/presentation/collaborator_avater_stack.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:avatar_stack/avatar_stack.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
@@ -41,8 +42,30 @@ class DocumentCollaborators extends StatelessWidget {
height: height,
width: width,
borderWidth: 1.0,
backgroundColor:
Theme.of(context).colorScheme.onSecondaryContainer,
plusWidgetBuilder: (value, border) {
final lastXCollaborators = collaborators.sublist(
collaborators.length - value,
);
return BorderedCircleAvatar(
border: border,
backgroundColor: Theme.of(context).hoverColor,
child: FittedBox(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FlowyTooltip(
message: lastXCollaborators
.map((e) => e.userName)
.join('\n'),
child: FlowyText(
'+$value',
fontSize: fontSize,
color: Colors.black,
),
),
),
),
);
},
avatars: collaborators
.map(
(c) => FlowyTooltip(
@@ -1,4 +1,4 @@
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/align_toolbar_item/custom_text_align_command.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/background_color/theme_background_color.dart';
@@ -1,5 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
final List<CommandShortcutEvent> customTextAlignCommands = [
@@ -19,7 +21,7 @@ final List<CommandShortcutEvent> customTextAlignCommands = [
final CommandShortcutEvent customTextLeftAlignCommand = CommandShortcutEvent(
key: 'Align text to the left',
command: 'ctrl+shift+l',
getDescription: () => 'Align text to the left',
getDescription: LocaleKeys.settings_shortcuts_commands_textAlignLeft.tr,
handler: (editorState) => _textAlignHandler(editorState, leftAlignmentKey),
);
@@ -34,7 +36,7 @@ final CommandShortcutEvent customTextLeftAlignCommand = CommandShortcutEvent(
final CommandShortcutEvent customTextCenterAlignCommand = CommandShortcutEvent(
key: 'Align text to the center',
command: 'ctrl+shift+e',
getDescription: () => 'Align text to the center',
getDescription: LocaleKeys.settings_shortcuts_commands_textAlignCenter.tr,
handler: (editorState) => _textAlignHandler(editorState, centerAlignmentKey),
);
@@ -49,7 +51,7 @@ final CommandShortcutEvent customTextCenterAlignCommand = CommandShortcutEvent(
final CommandShortcutEvent customTextRightAlignCommand = CommandShortcutEvent(
key: 'Align text to the right',
command: 'ctrl+shift+r',
getDescription: () => 'Align text to the right',
getDescription: LocaleKeys.settings_shortcuts_commands_textAlignRight.tr,
handler: (editorState) => _textAlignHandler(editorState, rightAlignmentKey),
);
@@ -1,5 +1,8 @@
import 'package:appflowy/generated/locale_keys.g.dart' show LocaleKeys;
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart'
show StringTranslateExtension;
import 'package:easy_localization/easy_localization.dart' hide TextDirection;
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -49,7 +52,7 @@ Node calloutNode({
// defining the callout block menu item in selection menu
SelectionMenuItem calloutItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_plugins_callout.tr(),
getName: LocaleKeys.document_plugins_callout.tr,
iconData: Icons.note,
keywords: [CalloutBlockKeys.type],
nodeBuilder: (editorState, context) =>
@@ -107,7 +107,7 @@ Node codeBlockNode({
// defining the callout block menu item for selection
SelectionMenuItem codeBlockItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_selectionMenu_codeBlock.tr(),
getName: LocaleKeys.document_selectionMenu_codeBlock.tr,
iconData: Icons.abc,
keywords: ['code', 'codeblock'],
nodeBuilder: (editorState, _) => codeBlockNode(),
@@ -1,5 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
final List<CharacterShortcutEvent> codeBlockCharacterEvents = [
@@ -59,7 +61,8 @@ final CommandShortcutEvent insertNewParagraphNextToCodeBlockCommand =
CommandShortcutEvent(
key: 'insert a new paragraph next to the code block',
command: 'shift+enter',
getDescription: () => 'Insert a new paragraph next to the code block',
getDescription:
LocaleKeys.settings_shortcuts_commands_codeBlockNewParagraph.tr,
handler: _insertNewParagraphNextToCodeBlockCommandHandler,
);
@@ -72,7 +75,8 @@ final CommandShortcutEvent tabToInsertSpacesInCodeBlockCommand =
CommandShortcutEvent(
key: 'tab to insert two spaces at the line start in code block',
command: 'tab',
getDescription: () => 'Insert two spaces at the line start in code block',
getDescription:
LocaleKeys.settings_shortcuts_commands_codeBlockAddTwoSpaces.tr,
handler: _tabToInsertSpacesInCodeBlockCommandHandler,
);
@@ -85,7 +89,8 @@ final CommandShortcutEvent tabToDeleteSpacesInCodeBlockCommand =
CommandShortcutEvent(
key: 'shift + tab to delete two spaces at the line start in code block',
command: 'shift+tab',
getDescription: () => 'Delete two spaces at the line start in code block',
getDescription:
LocaleKeys.settings_shortcuts_commands_codeBlockDeleteTwoSpaces.tr,
handler: _tabToDeleteSpacesInCodeBlockCommandHandler,
);
@@ -98,7 +103,7 @@ final CommandShortcutEvent selectAllInCodeBlockCommand = CommandShortcutEvent(
key: 'ctrl + a to select all content inside a code block',
command: 'ctrl+a',
macOSCommand: 'meta+a',
getDescription: () => 'Select all content inside a code block',
getDescription: LocaleKeys.settings_shortcuts_commands_codeBlockSelectAll.tr,
handler: _selectAllInCodeBlockCommandHandler,
);
@@ -111,7 +116,7 @@ final CommandShortcutEvent pasteInCodeblock = CommandShortcutEvent(
key: 'paste in codeblock',
command: 'ctrl+v',
macOSCommand: 'cmd+v',
getDescription: () => 'Paste text in codeblock',
getDescription: LocaleKeys.settings_shortcuts_commands_codeBlockPasteText.tr,
handler: _pasteInCodeBlock,
);
@@ -6,15 +6,15 @@ import 'package:easy_localization/easy_localization.dart';
final List<List<ContextMenuItem>> customContextMenuItems = [
[
ContextMenuItem(
getName: () => LocaleKeys.document_plugins_contextMenu_copy.tr(),
getName: LocaleKeys.document_plugins_contextMenu_copy.tr,
onPressed: (editorState) => customCopyCommand.execute(editorState),
),
ContextMenuItem(
getName: () => LocaleKeys.document_plugins_contextMenu_paste.tr(),
getName: LocaleKeys.document_plugins_contextMenu_paste.tr,
onPressed: (editorState) => customPasteCommand.execute(editorState),
),
ContextMenuItem(
getName: () => LocaleKeys.document_plugins_contextMenu_cut.tr(),
getName: LocaleKeys.document_plugins_contextMenu_cut.tr,
onPressed: (editorState) => customCutCommand.execute(editorState),
),
],
@@ -13,8 +13,8 @@ import 'package:flutter/material.dart';
/// - mobile
///
final CommandShortcutEvent customCopyCommand = CommandShortcutEvent(
key: 'copy the selected content (with formatting)',
getDescription: () => 'copy the selected content (with formatting)',
key: 'copy the selected content',
getDescription: () => AppFlowyEditorL10n.current.cmdCopySelection,
command: 'ctrl+c',
macOSCommand: 'cmd+c',
handler: _copyCommandHandler,
@@ -11,8 +11,8 @@ import 'package:flutter/material.dart';
/// - mobile
///
final CommandShortcutEvent customCutCommand = CommandShortcutEvent(
key: 'cut the selected content (with formatting)',
getDescription: () => 'cut the selected content (with formatting)',
key: 'cut the selected content',
getDescription: () => AppFlowyEditorL10n.current.cmdCutSelection,
command: 'ctrl+x',
macOSCommand: 'cmd+x',
handler: _cutCommandHandler,
@@ -18,8 +18,8 @@ import 'package:string_validator/string_validator.dart';
/// - mobile
///
final CommandShortcutEvent customPasteCommand = CommandShortcutEvent(
key: 'paste the content (with formatting)',
getDescription: () => 'paste the content (with formatting)',
key: 'paste the content',
getDescription: () => AppFlowyEditorL10n.current.cmdPasteContent,
command: 'ctrl+v',
macOSCommand: 'cmd+v',
handler: _pasteCommandHandler,
@@ -2,7 +2,7 @@ import 'dart:io';
import 'dart:typed_data';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_util.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/settings/application_data_storage.dart';
@@ -1,6 +1,6 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/insert_page_command.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/selectable_svg_widget.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
@@ -10,7 +10,7 @@ import 'package:easy_localization/easy_localization.dart';
SelectionMenuItem inlineGridMenuItem(DocumentBloc documentBloc) =>
SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_grid_createANewGrid.tr(),
getName: LocaleKeys.document_slashMenu_grid_createANewGrid.tr,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.grid_s,
isSelected: onSelected,
@@ -31,7 +31,7 @@ SelectionMenuItem inlineGridMenuItem(DocumentBloc documentBloc) =>
SelectionMenuItem inlineBoardMenuItem(DocumentBloc documentBloc) =>
SelectionMenuItem(
getName: () => LocaleKeys.document_slashMenu_board_createANewBoard.tr(),
getName: LocaleKeys.document_slashMenu_board_createANewBoard.tr,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.board_s,
isSelected: onSelected,
@@ -52,8 +52,7 @@ SelectionMenuItem inlineBoardMenuItem(DocumentBloc documentBloc) =>
SelectionMenuItem inlineCalendarMenuItem(DocumentBloc documentBloc) =>
SelectionMenuItem(
getName: () =>
LocaleKeys.document_slashMenu_calendar_createANewCalendar.tr(),
getName: LocaleKeys.document_slashMenu_calendar_createANewCalendar.tr,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.date_s,
isSelected: onSelected,
@@ -9,7 +9,7 @@ import 'package:easy_localization/easy_localization.dart';
// Document Reference
SelectionMenuItem referencedDocumentMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_plugins_referencedDocument.tr(),
getName: LocaleKeys.document_plugins_referencedDocument.tr,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.document_s,
isSelected: onSelected,
@@ -23,7 +23,7 @@ SelectionMenuItem referencedDocumentMenuItem = SelectionMenuItem(
// Database References
SelectionMenuItem referencedGridMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_plugins_referencedGrid.tr(),
getName: LocaleKeys.document_plugins_referencedGrid.tr,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.grid_s,
isSelected: onSelected,
@@ -35,7 +35,7 @@ SelectionMenuItem referencedGridMenuItem = SelectionMenuItem(
);
SelectionMenuItem referencedBoardMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_plugins_referencedBoard.tr(),
getName: LocaleKeys.document_plugins_referencedBoard.tr,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.board_s,
isSelected: onSelected,
@@ -47,7 +47,7 @@ SelectionMenuItem referencedBoardMenuItem = SelectionMenuItem(
);
SelectionMenuItem referencedCalendarMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_plugins_referencedCalendar.tr(),
getName: LocaleKeys.document_plugins_referencedCalendar.tr,
icon: (editorState, onSelected, style) => SelectableSvgWidget(
data: FlowySvgs.date_s,
isSelected: onSelected,
@@ -5,7 +5,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/image_util.dart';
@@ -36,7 +36,7 @@ Node mathEquationNode({
// defining the callout block menu item for selection
SelectionMenuItem mathEquationItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_plugins_mathEquation_name.tr(),
getName: LocaleKeys.document_plugins_mathEquation_name.tr,
iconData: Icons.text_fields_rounded,
keywords: ['tex, latex, katex', 'math equation', 'formula'],
nodeBuilder: (editorState, _) => mathEquationNode(),
@@ -1,11 +1,9 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart';
import 'package:appflowy/plugins/base/drag_handler.dart';
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
import 'package:appflowy/user/application/reminder/reminder_extension.dart';
@@ -27,6 +25,7 @@ import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:fixnum/fixnum.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:nanoid/non_secure.dart';
@@ -258,11 +257,11 @@ class _MentionDateBlockState extends State<MentionDateBlock> {
}
DateTime _parseTime(String timeStr, UserTimeFormatPB timeFormat) {
final twelveHourFormat = DateFormat('HH:mm a');
final twelveHourFormat = DateFormat('hh:mm a');
final twentyFourHourFormat = DateFormat('HH:mm');
try {
if (timeFormat == TimeFormatPB.TwelveHour) {
if (timeFormat == UserTimeFormatPB.TwelveHour) {
return twelveHourFormat.parseStrict(timeStr);
}
@@ -5,7 +5,7 @@ import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
SelectionMenuItem dateMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_plugins_date.tr(),
getName: LocaleKeys.document_plugins_insertDate.tr,
icon: (_, isSelected, style) => FlowySvg(
FlowySvgs.date_s,
color: isSelected
@@ -43,7 +43,7 @@ Node autoCompletionNode({
}
SelectionMenuItem autoGeneratorMenuItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_plugins_autoGeneratorMenuItemName.tr(),
getName: LocaleKeys.document_plugins_autoGeneratorMenuItemName.tr,
iconData: Icons.generating_tokens,
keywords: ['ai', 'openai' 'writer', 'autogenerator'],
nodeBuilder: (editorState, _) {
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
class Loading {
Loading(this.context);
late BuildContext loadingContext;
BuildContext? loadingContext;
final BuildContext context;
Future<void> start() async => showDialog<void>(
@@ -24,7 +24,12 @@ class Loading {
},
);
Future<void> stop() async => Navigator.of(loadingContext).pop();
Future<void> stop() async {
if (loadingContext != null) {
Navigator.of(loadingContext!).pop();
loadingContext = null;
}
}
}
class BarrierDialog {
@@ -19,7 +19,7 @@ class OutlineBlockKeys {
// defining the callout block menu item for selection
SelectionMenuItem outlineItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_selectionMenu_outline.tr(),
getName: LocaleKeys.document_selectionMenu_outline.tr,
iconData: Icons.list_alt,
keywords: ['outline', 'table of contents'],
nodeBuilder: (editorState, _) => outlineBlockNode(),
@@ -46,7 +46,7 @@ Node toggleListBlockNode({
// defining the toggle list block menu item
SelectionMenuItem toggleListBlockItem = SelectionMenuItem.node(
getName: () => LocaleKeys.document_plugins_toggleList.tr(),
getName: LocaleKeys.document_plugins_toggleList.tr,
iconData: Icons.arrow_right,
keywords: ['collapsed list', 'toggle list', 'list'],
nodeBuilder: (editorState, _) => toggleListBlockNode(),
@@ -110,7 +110,7 @@ CharacterShortcutEvent insertChildNodeInsideToggleList = CharacterShortcutEvent(
// toggle the todo list
final CommandShortcutEvent toggleToggleListCommand = CommandShortcutEvent(
key: 'toggle the toggle list',
getDescription: () => 'Toggle the toggle list',
getDescription: () => AppFlowyEditorL10n.current.cmdToggleTodoList,
command: 'ctrl+enter',
macOSCommand: 'cmd+enter',
handler: _toggleToggleListCommandHandler,
@@ -1,7 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/share_bloc.dart';
import 'package:appflowy/plugins/document/application/document_share_bloc.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/util/string_extension.dart';
import 'package:appflowy/workspace/application/view/view_listener.dart';
@@ -14,6 +12,7 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/file_picker/file_picker_service.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class DocumentShareButton extends StatelessWidget {
@@ -27,8 +26,8 @@ class DocumentShareButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<DocShareBloc>(param1: view),
child: BlocListener<DocShareBloc, DocShareState>(
create: (context) => getIt<DocumentShareBloc>(param1: view),
child: BlocListener<DocumentShareBloc, DocumentShareState>(
listener: (context, state) {
state.mapOrNull(
finish: (state) {
@@ -39,7 +38,7 @@ class DocumentShareButton extends StatelessWidget {
},
);
},
child: BlocBuilder<DocShareBloc, DocShareState>(
child: BlocBuilder<DocumentShareBloc, DocumentShareState>(
builder: (context, state) => ConstrainedBox(
constraints: const BoxConstraints.expand(
height: 30,
@@ -102,7 +101,7 @@ class ShareActionListState extends State<ShareActionList> {
@override
Widget build(BuildContext context) {
final docShareBloc = context.read<DocShareBloc>();
final docShareBloc = context.read<DocumentShareBloc>();
return PopoverActionList<ShareActionWrapper>(
direction: PopoverDirection.bottomWithCenterAligned,
offset: const Offset(0, 8),
@@ -126,7 +125,7 @@ class ShareActionListState extends State<ShareActionList> {
fileName: '${name.toFileName()}.md',
);
if (exportPath != null) {
docShareBloc.add(DocShareEvent.shareMarkdown(exportPath));
docShareBloc.add(DocumentShareEvent.shareMarkdown(exportPath));
}
break;
}
@@ -1,8 +1,6 @@
import 'package:flutter/material.dart';
import 'package:appflowy/date/date_service.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/string_extension.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
@@ -14,6 +12,7 @@ import 'package:appflowy_backend/protobuf/flowy-user/reminder.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:fixnum/fixnum.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:nanoid/nanoid.dart';
@@ -1,6 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/application/sync/database_sync_bloc.dart';
import 'package:appflowy/plugins/document/application/doc_sync_bloc.dart';
import 'package:appflowy/plugins/document/application/document_sync_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
@@ -4,6 +4,7 @@ import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
typedef FeatureFlagMap = Map<FeatureFlag, bool>;
@@ -83,14 +84,18 @@ enum FeatureFlag {
bool get isOn {
// release this feature in version 0.5.4
if ([
FeatureFlag.collaborativeWorkspace,
FeatureFlag.membersSettings,
// FeatureFlag.collaborativeWorkspace,
// FeatureFlag.membersSettings,
FeatureFlag.syncDatabase,
FeatureFlag.syncDocument,
].contains(this)) {
return true;
}
if (kReleaseMode) {
return false;
}
if (_values.containsKey(this)) {
return _values[this]!;
}
@@ -189,8 +189,8 @@ void _resolveHomeDeps(GetIt getIt) {
);
// share
getIt.registerFactoryParam<DocShareBloc, ViewPB, void>(
(view, _) => DocShareBloc(view: view),
getIt.registerFactoryParam<DocumentShareBloc, ViewPB, void>(
(view, _) => DocumentShareBloc(view: view),
);
getIt.registerSingleton<NotificationActionBloc>(NotificationActionBloc());
@@ -5,6 +5,7 @@ import 'package:appflowy/env/backend_env.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/user/application/auth/device_id.dart';
import 'package:appflowy_backend/appflowy_backend.dart';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
@@ -28,6 +29,7 @@ class InitRustSDKTask extends LaunchTask {
final dir = customApplicationPath ?? applicationPath;
final deviceId = await getDeviceId();
debugPrint('application path: ${applicationPath.path}');
// Pass the environment variables to the Rust SDK
final env = _makeAppFlowyConfiguration(
root.path,
@@ -59,6 +61,7 @@ AppFlowyConfiguration _makeAppFlowyConfiguration(
custom_app_path: customAppPath,
origin_app_path: originAppPath,
device_id: deviceId,
platform: Platform.operatingSystem,
authenticator_type: env.authenticatorType.value,
supabase_config: env.supabaseConfig,
appflowy_cloud_config: env.appflowyCloudConfig,
@@ -1,7 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
class Debounce {
Debounce({
this.duration = const Duration(milliseconds: 1000),
@@ -10,8 +8,9 @@ class Debounce {
final Duration duration;
Timer? _timer;
void call(VoidCallback action) {
void call(Function action) {
dispose();
_timer = Timer(duration, () {
action();
});
@@ -0,0 +1,23 @@
import 'dart:async';
class Throttler {
Throttler({
this.duration = const Duration(milliseconds: 1000),
});
final Duration duration;
Timer? _timer;
void call(Function callback) {
if (_timer?.isActive ?? false) return;
_timer = Timer(duration, () {
callback();
});
}
void dispose() {
_timer?.cancel();
_timer = null;
}
}
@@ -1,5 +1,9 @@
import 'dart:async';
import 'package:appflowy/startup/plugin/plugin.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/application/workspace/workspace_sections_listener.dart';
import 'package:appflowy/workspace/application/workspace/workspace_service.dart';
import 'package:appflowy_backend/log.dart';
@@ -152,6 +156,37 @@ class SidebarSectionsBloc
},
);
},
reload: (userProfile, workspaceId) async {
_initial(userProfile, workspaceId);
final sectionViews = await _getSectionViews();
if (sectionViews != null) {
emit(
state.copyWith(
section: sectionViews,
),
);
// try to open the fist view in public section or private section
if (sectionViews.publicViews.isNotEmpty) {
getIt<TabsBloc>().add(
TabsEvent.openPlugin(
plugin: sectionViews.publicViews.first.plugin(),
),
);
} else if (sectionViews.privateViews.isNotEmpty) {
getIt<TabsBloc>().add(
TabsEvent.openPlugin(
plugin: sectionViews.privateViews.first.plugin(),
),
);
} else {
getIt<TabsBloc>().add(
TabsEvent.openPlugin(
plugin: makePlugin(pluginType: PluginType.blank),
),
);
}
}
},
);
},
);
@@ -245,6 +280,10 @@ class SidebarSectionsEvent with _$SidebarSectionsEvent {
const factory SidebarSectionsEvent.receiveSectionViewsUpdate(
SectionViewsPB sectionViews,
) = _ReceiveSectionViewsUpdate;
const factory SidebarSectionsEvent.reload(
UserProfilePB userProfile,
String workspaceId,
) = _Reload;
}
@freezed
@@ -10,6 +10,8 @@ import 'package:appflowy/workspace/application/settings/appearance/base_appearan
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-user/date_time.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart'
show AppFlowyEditorLocalizations;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flutter/material.dart';
@@ -193,6 +195,9 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
Log.warn('Catch error in setLocale: $e}');
});
// Sync the app's locale with the editor (initialization and update)
AppFlowyEditorLocalizations.load(newLocale);
if (state.locale != newLocale) {
_appearanceSettings.locale.languageCode = newLocale.languageCode;
_appearanceSettings.locale.countryCode = newLocale.countryCode ?? "";
@@ -39,8 +39,10 @@ class ShortcutsCubit extends Cubit<ShortcutsState> {
commandShortcutEvents,
customizeShortcuts,
);
//sort the shortcuts
commandShortcutEvents.sort((a, b) => a.key.compareTo(b.key));
emit(
state.copyWith(
status: ShortcutsStatus.success,
@@ -40,7 +40,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
final currentWorkspace = result.$1;
final workspaces = result.$2;
final isCollabWorkspaceOn =
userProfile.authenticator != AuthenticatorPB.Local &&
userProfile.authenticator == AuthenticatorPB.AppFlowyCloud &&
FeatureFlag.collaborativeWorkspace.isOn;
if (currentWorkspace != null && result.$3 == true) {
final result = await _userService
@@ -71,6 +71,15 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
);
},
createWorkspace: (name) async {
emit(
state.copyWith(
actionResult: const UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.create,
isLoading: true,
result: null,
),
),
);
final result = await _userService.createUserWorkspace(name);
final workspaces = result.fold(
(s) => [...state.workspaces, s],
@@ -81,6 +90,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
workspaces: workspaces,
actionResult: UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.create,
isLoading: false,
result: result,
),
),
@@ -91,6 +101,15 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
});
},
deleteWorkspace: (workspaceId) async {
emit(
state.copyWith(
actionResult: const UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.delete,
isLoading: true,
result: null,
),
),
);
final remoteWorkspaces = await _fetchWorkspaces().then(
(value) => value.$2,
);
@@ -108,6 +127,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
actionResult: UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.delete,
result: result,
isLoading: false,
),
),
);
@@ -134,11 +154,21 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
actionResult: UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.delete,
result: result,
isLoading: false,
),
),
);
},
openWorkspace: (workspaceId) async {
emit(
state.copyWith(
actionResult: const UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.open,
isLoading: true,
result: null,
),
),
);
final result = await _userService.openWorkspace(workspaceId);
final currentWorkspace = result.fold(
(s) => state.workspaces.firstWhereOrNull(
@@ -157,6 +187,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
currentWorkspace: currentWorkspace,
actionResult: UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.open,
isLoading: false,
result: result,
),
),
@@ -188,6 +219,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
currentWorkspace: currentWorkspace,
actionResult: UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.rename,
isLoading: false,
result: result,
),
),
@@ -221,6 +253,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
currentWorkspace: currentWorkspace,
actionResult: UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.updateIcon,
isLoading: false,
result: result,
),
),
@@ -245,6 +278,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
workspaces: workspaces,
actionResult: UserWorkspaceActionResult(
actionType: UserWorkspaceActionType.leave,
isLoading: false,
result: result,
),
),
@@ -253,7 +287,11 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
updateWorkspaces: (workspaces) async {
emit(
state.copyWith(
workspaces: workspaces.items,
workspaces: workspaces.items
..sort(
(a, b) =>
a.createdAtTimestamp.compareTo(b.createdAtTimestamp),
),
),
);
},
@@ -359,11 +397,13 @@ enum UserWorkspaceActionType {
class UserWorkspaceActionResult {
const UserWorkspaceActionResult({
required this.actionType,
required this.isLoading,
required this.result,
});
final UserWorkspaceActionType actionType;
final FlowyResult<void, FlowyError> result;
final bool isLoading;
final FlowyResult<void, FlowyError>? result;
}
@freezed
@@ -6,11 +6,8 @@ import 'package:appflowy/plugins/database/grid/presentation/mobile_grid_page.dar
import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart';
import 'package:appflowy/plugins/document/document.dart';
import 'package:appflowy/startup/plugin/plugin.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter/material.dart';
enum FlowyPlugin {
@@ -84,29 +81,6 @@ extension ViewExtension on ViewPB {
};
FlowySvgData get iconData => layout.icon;
Future<List<ViewPB>> getAncestors({
bool includeSelf = false,
bool includeRoot = false,
}) async {
final ancestors = <ViewPB>[];
if (includeSelf) {
final self = await ViewBackendService.getView(id);
ancestors.add(self.fold((s) => s, (e) => this));
}
FlowyResult<ViewPB, FlowyError> parent =
await ViewBackendService.getView(parentViewId);
while (parent.isSuccess) {
// parent is not null
final view = parent.fold((s) => s, (e) => null);
if (view == null || (!includeRoot && view.parentViewId.isEmpty)) {
break;
}
ancestors.add(view);
parent = await ViewBackendService.getView(view.parentViewId);
}
return ancestors.reversed.toList();
}
}
extension ViewLayoutExtension on ViewLayoutPB {
@@ -260,12 +260,19 @@ class ViewBackendService {
}
static Future<FlowyResult<ViewPB, FlowyError>> getView(
String viewID,
String viewId,
) async {
final payload = ViewIdPB.create()..value = viewID;
final payload = ViewIdPB.create()..value = viewId;
return FolderEventGetView(payload).send();
}
static Future<FlowyResult<RepeatedViewPB, FlowyError>> getViewAncestors(
String viewId,
) async {
final payload = ViewIdPB.create()..value = viewId;
return FolderEventGetViewAncestors(payload).send();
}
Future<FlowyResult<ViewPB, FlowyError>> getChildView({
required String parentViewId,
required String childViewId,
@@ -1,6 +1,5 @@
import 'dart:async';
import 'package:appflowy/startup/plugin/plugin.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/favorite/prelude.dart';
@@ -106,21 +105,22 @@ class HomeSideBar extends StatelessWidget {
),
BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
listener: (context, state) {
context.read<TabsBloc>().add(
TabsEvent.openPlugin(
plugin: makePlugin(pluginType: PluginType.blank),
),
);
context.read<SidebarSectionsBloc>().add(
SidebarSectionsEvent.initial(
userProfile,
state.currentWorkspace?.workspaceId ??
workspaceSetting.workspaceId,
),
);
context.read<FavoriteBloc>().add(
const FavoriteEvent.fetchFavorites(),
);
final actionType = state.actionResult?.actionType;
if (actionType == UserWorkspaceActionType.create ||
actionType == UserWorkspaceActionType.delete ||
actionType == UserWorkspaceActionType.open) {
context.read<SidebarSectionsBloc>().add(
SidebarSectionsEvent.reload(
userProfile,
state.currentWorkspace?.workspaceId ??
workspaceSetting.workspaceId,
),
);
context.read<FavoriteBloc>().add(
const FavoriteEvent.fetchFavorites(),
);
}
},
),
],
@@ -103,10 +103,10 @@ class PublicSectionFolder extends SectionFolder {
super.key,
required super.views,
}) : super(
title: LocaleKeys.sideBar_public.tr(),
title: LocaleKeys.sideBar_workspace.tr(),
categoryType: FolderCategoryType.public,
expandButtonTooltip: LocaleKeys.sideBar_clickToHidePublic.tr(),
addButtonTooltip: LocaleKeys.sideBar_addAPageToPublic.tr(),
expandButtonTooltip: LocaleKeys.sideBar_clickToHideWorkspace.tr(),
addButtonTooltip: LocaleKeys.sideBar_addAPageToWorkspace.tr(),
);
}
@@ -1,5 +1,6 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_setting.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
@@ -16,7 +17,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class SidebarWorkspace extends StatelessWidget {
class SidebarWorkspace extends StatefulWidget {
const SidebarWorkspace({
super.key,
required this.userProfile,
@@ -24,9 +25,18 @@ class SidebarWorkspace extends StatelessWidget {
final UserProfilePB userProfile;
@override
State<SidebarWorkspace> createState() => _SidebarWorkspaceState();
}
class _SidebarWorkspaceState extends State<SidebarWorkspace> {
Loading? loadingIndicator;
@override
Widget build(BuildContext context) {
return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
listenWhen: (previous, current) =>
previous.actionResult != current.actionResult,
listener: _showResultDialog,
builder: (context, state) {
final currentWorkspace = state.currentWorkspace;
@@ -37,11 +47,11 @@ class SidebarWorkspace extends StatelessWidget {
children: [
Expanded(
child: SidebarSwitchWorkspaceButton(
userProfile: userProfile,
userProfile: widget.userProfile,
currentWorkspace: currentWorkspace,
),
),
UserSettingButton(userProfile: userProfile),
UserSettingButton(userProfile: widget.userProfile),
const HSpace(4),
const NotificationButton(),
],
@@ -58,6 +68,19 @@ class SidebarWorkspace extends StatelessWidget {
final actionType = actionResult.actionType;
final result = actionResult.result;
final isLoading = actionResult.isLoading;
if (isLoading) {
loadingIndicator ??= Loading(context)..start();
return;
} else {
loadingIndicator?.stop();
loadingIndicator = null;
}
if (result == null) {
return;
}
result.onFailure((f) {
Log.error(
@@ -193,6 +216,7 @@ class _SidebarSwitchWorkspaceButtonState
child: FlowyText.medium(
widget.currentWorkspace.name,
overflow: TextOverflow.ellipsis,
withTooltip: true,
),
),
const FlowySvg(FlowySvgs.drop_menu_show_m),
@@ -110,7 +110,6 @@ class _WorkspaceMoreActionWrapper extends CustomActionCell {
await showDialog(
context: context,
builder: (_) => NavigatorOkCancelDialog(
title: LocaleKeys.workspace_leaveCurrentWorkspace.tr(),
message: LocaleKeys.workspace_leaveCurrentWorkspacePrompt.tr(),
onOkPressed: () {
workspaceBloc.add(
@@ -9,6 +9,7 @@ import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -136,8 +137,10 @@ class WorkspaceMenuItem extends StatelessWidget {
PopoverContainer.of(context).closeAll();
}
},
margin:
const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
margin: const EdgeInsets.symmetric(
vertical: 8,
horizontal: 12,
),
iconPadding: 10.0,
leftIconSize: const Size.square(32),
leftIcon: const SizedBox.square(
@@ -146,12 +149,12 @@ class WorkspaceMenuItem extends StatelessWidget {
rightIcon: const HSpace(42.0),
text: Column(
crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.center,
children: [
FlowyText.medium(
workspace.name,
fontSize: 14.0,
overflow: TextOverflow.ellipsis,
withTooltip: true,
),
FlowyText(
state.isLoading
@@ -171,10 +174,14 @@ class WorkspaceMenuItem extends StatelessWidget {
left: 8,
child: SizedBox.square(
dimension: 32,
child: WorkspaceIcon(
workspace: workspace,
iconSize: 26,
enableEdit: true,
child: FlowyTooltip(
message:
LocaleKeys.document_plugins_cover_changeIcon.tr(),
child: WorkspaceIcon(
workspace: workspace,
iconSize: 26,
enableEdit: true,
),
),
),
),
@@ -62,6 +62,7 @@ class SettingsDialog extends StatelessWidget {
SizedBox(
width: 200,
child: SettingsMenu(
userProfile: user,
changeSelectedPage: (index) {
context
.read<SettingsDialogBloc>()
@@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
SelectionMenuItem emojiMenuItem = SelectionMenuItem(
getName: () => LocaleKeys.document_plugins_emoji.tr(),
getName: LocaleKeys.document_plugins_emoji.tr,
icon: (editorState, onSelected, style) => SelectableIconWidget(
icon: Icons.emoji_emotions_outlined,
isSelected: onSelected,
@@ -117,13 +117,14 @@ class CloudTypeSwitcher extends StatelessWidget {
Widget build(BuildContext context) {
final isDevelopMode = integrationMode().isDevelop;
// Only show the appflowyCloudDevelop in develop mode
final values = AuthenticatorType.values
.where(
(element) =>
isDevelopMode ||
element != AuthenticatorType.appflowyCloudDevelop,
)
.toList();
final values = AuthenticatorType.values.where((element) {
// Supabase will going to be removed in the future
if (element == AuthenticatorType.supabase) {
return false;
}
return isDevelopMode || element != AuthenticatorType.appflowyCloudDevelop;
}).toList();
return PlatformExtension.isDesktopOrWeb
? AppFlowyPopover(
direction: PopoverDirection.bottomWithRightAligned,
@@ -117,7 +117,7 @@ class ShortcutsListTile extends StatelessWidget {
Expanded(
child: FlowyText.medium(
key: Key(shortcutEvent.key),
shortcutEvent.key.capitalize(),
shortcutEvent.description!.capitalize(),
overflow: TextOverflow.ellipsis,
),
),
@@ -2,6 +2,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart';
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/foundation.dart';
@@ -12,10 +13,12 @@ class SettingsMenu extends StatelessWidget {
super.key,
required this.changeSelectedPage,
required this.currentPage,
required this.userProfile,
});
final Function changeSelectedPage;
final SettingsPage currentPage;
final UserProfilePB userProfile;
@override
Widget build(BuildContext context) {
@@ -72,7 +75,8 @@ class SettingsMenu extends StatelessWidget {
icon: Icons.cut,
changeSelectedPage: changeSelectedPage,
),
if (FeatureFlag.membersSettings.isOn)
if (FeatureFlag.membersSettings.isOn &&
userProfile.authenticator == AuthenticatorPB.AppFlowyCloud)
SettingsMenuElement(
page: SettingsPage.member,
selectedPage: currentPage,
@@ -174,85 +174,92 @@ class _AppFlowyDatePickerState extends State<AppFlowyDatePicker> {
}
Widget buildDesktopPicker() {
return Padding(
padding: const EdgeInsets.only(top: 18.0, bottom: 12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
StartTextField(
includeTime: widget.includeTime,
timeFormat: widget.timeFormat,
timeHintText: widget.timeHintText,
parseEndTimeError: widget.parseEndTimeError,
parseTimeError: widget.parseTimeError,
timeStr: widget.timeStr,
popoverMutex: widget.popoverMutex,
onSubmitted: widget.onStartTimeSubmitted,
),
EndTextField(
includeTime: widget.includeTime,
timeFormat: widget.timeFormat,
isRange: widget.isRange,
endTimeStr: widget.endTimeStr,
popoverMutex: widget.popoverMutex,
onSubmitted: widget.onEndTimeSubmitted,
),
DatePicker(
isRange: widget.isRange,
onDaySelected: (selectedDay, focusedDay) {
widget.onDaySelected?.call(selectedDay, focusedDay);
if (widget.rebuildOnDaySelected) {
setState(() => _selectedDay = selectedDay);
}
},
onRangeSelected: widget.onRangeSelected,
selectedDay:
widget.rebuildOnDaySelected ? _selectedDay : widget.selectedDay,
firstDay: widget.firstDay,
lastDay: widget.lastDay,
startDay: widget.startDay,
endDay: widget.endDay,
onCalendarCreated: widget.onCalendarCreated,
onPageChanged: widget.onPageChanged,
),
const TypeOptionSeparator(spacing: 12.0),
if (widget.enableRanges && widget.onIsRangeChanged != null) ...[
EndTimeButton(
// GestureDetector is a workaround to stop popover from closing
// when clicking on the date picker.
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {},
child: Padding(
padding: const EdgeInsets.only(top: 18.0, bottom: 12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
StartTextField(
includeTime: widget.includeTime,
timeFormat: widget.timeFormat,
timeHintText: widget.timeHintText,
parseEndTimeError: widget.parseEndTimeError,
parseTimeError: widget.parseTimeError,
timeStr: widget.timeStr,
popoverMutex: widget.popoverMutex,
onSubmitted: widget.onStartTimeSubmitted,
),
EndTextField(
includeTime: widget.includeTime,
timeFormat: widget.timeFormat,
isRange: widget.isRange,
onChanged: widget.onIsRangeChanged!,
endTimeStr: widget.endTimeStr,
popoverMutex: widget.popoverMutex,
onSubmitted: widget.onEndTimeSubmitted,
),
const VSpace(4.0),
],
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: IncludeTimeButton(
value: widget.includeTime,
onChanged: widget.onIncludeTimeChanged,
DatePicker(
isRange: widget.isRange,
onDaySelected: (selectedDay, focusedDay) {
widget.onDaySelected?.call(selectedDay, focusedDay);
if (widget.rebuildOnDaySelected) {
setState(() => _selectedDay = selectedDay);
}
},
onRangeSelected: widget.onRangeSelected,
selectedDay: widget.rebuildOnDaySelected
? _selectedDay
: widget.selectedDay,
firstDay: widget.firstDay,
lastDay: widget.lastDay,
startDay: widget.startDay,
endDay: widget.endDay,
onCalendarCreated: widget.onCalendarCreated,
onPageChanged: widget.onPageChanged,
),
const TypeOptionSeparator(spacing: 12.0),
if (widget.enableRanges && widget.onIsRangeChanged != null) ...[
EndTimeButton(
isRange: widget.isRange,
onChanged: widget.onIsRangeChanged!,
),
const VSpace(4.0),
],
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: IncludeTimeButton(
value: widget.includeTime,
onChanged: widget.onIncludeTimeChanged,
),
),
),
const _GroupSeparator(),
ReminderSelector(
mutex: widget.popoverMutex,
hasTime: widget.includeTime,
timeFormat: widget.timeFormat,
selectedOption: _selectedReminderOption,
onOptionSelected: (option) {
setState(() => _selectedReminderOption = option);
widget.onReminderSelected?.call(option);
},
),
if (widget.options?.isNotEmpty ?? false) ...[
const _GroupSeparator(),
ListView.separated(
shrinkWrap: true,
itemCount: widget.options!.length,
separatorBuilder: (_, __) => const _GroupSeparator(),
itemBuilder: (_, index) =>
_renderGroupOptions(widget.options![index].options),
ReminderSelector(
mutex: widget.popoverMutex,
hasTime: widget.includeTime,
timeFormat: widget.timeFormat,
selectedOption: _selectedReminderOption,
onOptionSelected: (option) {
setState(() => _selectedReminderOption = option);
widget.onReminderSelected?.call(option);
},
),
if (widget.options?.isNotEmpty ?? false) ...[
const _GroupSeparator(),
ListView.separated(
shrinkWrap: true,
itemCount: widget.options!.length,
separatorBuilder: (_, __) => const _GroupSeparator(),
itemBuilder: (_, index) =>
_renderGroupOptions(widget.options![index].options),
),
],
],
],
),
),
);
}
@@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:intl/intl.dart';
const _maxLengthTwelveHour = 8;
const _maxLengthTwentyFourHour = 5;
@@ -55,6 +56,13 @@ class _TimeTextFieldState extends State<TimeTextField> {
text = widget.endTimeStr!;
}
if (widget.timeFormat == TimeFormatPB.TwelveHour) {
final twentyFourHourFormat = DateFormat('HH:mm');
final twelveHourFormat = DateFormat('hh:mm a');
final date = twentyFourHourFormat.parse(text);
text = twelveHourFormat.format(date);
}
_focusNode.addListener(_focusNodeListener);
widget.popoverMutex?.listenOnPopoverChanged(_popoverListener);
}
@@ -86,6 +94,7 @@ class _TimeTextFieldState extends State<TimeTextField> {
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: FlowyTextField(
text: text,
keyboardType: TextInputType.datetime,
focusNode: _focusNode,
autoFocus: false,
controller: _textController,
@@ -97,7 +106,16 @@ class _TimeTextFieldState extends State<TimeTextField> {
? _maxLengthTwelveHour
: _maxLengthTwentyFourHour,
showCounter: false,
inputFormatters: [TimeInputFormatter(widget.timeFormat)],
inputFormatters: [
if (widget.timeFormat == TimeFormatPB.TwelveHour) ...[
// Allow for AM/PM if time format is 12-hour
FilteringTextInputFormatter.allow(RegExp('[0-9:aApPmM ]')),
] else ...[
// Default allow for hh:mm format
FilteringTextInputFormatter.allow(RegExp('[0-9:]')),
],
TimeInputFormatter(widget.timeFormat),
],
onSubmitted: widget.onSubmitted,
),
);
@@ -134,7 +152,20 @@ class TimeInputFormatter extends TextInputFormatter {
return _formatText(newText, spacePosition, ' ');
}
return newValue;
if (timeFormat == TimeFormatPB.TwentyFourHour &&
newValue.text.length == 5) {
final prefix = newValue.text.substring(0, 3);
final suffix = newValue.text.length > 5 ? newValue.text.substring(6) : '';
final minutes = int.tryParse(newValue.text.substring(3, 5));
if (minutes == null || minutes <= 0) {
return newValue.copyWith(text: '${prefix}00$suffix'.toUpperCase());
} else if (minutes > 59) {
return newValue.copyWith(text: '${prefix}59$suffix'.toUpperCase());
}
}
return newValue.copyWith(text: newText.toUpperCase());
}
TextEditingValue _formatText(String text, int index, String separator) {
@@ -1,15 +1,16 @@
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
import 'package:appflowy/startup/tasks/app_window_size_manager.dart';
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/application/view/view_listener.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy/workspace/presentation/widgets/rename_view_popover.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
// workspaces / ... / view_title
@@ -115,9 +116,8 @@ class _ViewTitleBarState extends State<ViewTitleBar> {
}
void _reloadAncestors() {
ancestors = widget.view.getAncestors(
includeSelf: true,
);
ancestors = ViewBackendService.getViewAncestors(widget.view.id)
.fold((s) => s.items, (f) => []);
}
}
@@ -1,10 +1,15 @@
export 'package:async/async.dart';
import 'dart:async';
import 'dart:convert';
import 'package:appflowy_backend/rust_stream.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'dart:ffi';
import 'ffi.dart' as ffi;
import 'package:ffi/ffi.dart';
import 'dart:isolate';
import 'dart:io';
import 'package:logger/logger.dart';
enum ExceptionType {
AppearanceSettingsIsEmpty,
@@ -27,10 +32,15 @@ class FlowySDK {
Future<void> dispose() async {}
Future<void> init(String configuration) async {
final port = RustStreamReceiver.shared.port;
ffi.set_stream_port(port);
ffi.set_stream_port(RustStreamReceiver.shared.port);
ffi.store_dart_post_cobject(NativeApi.postCObject);
// On iOS, VSCode can't print logs from Rust, so we need to use a different method to print logs.
// So we use a shared port to receive logs from Rust and print them using the logger. In release mode, we don't print logs.
if (Platform.isIOS && kDebugMode) {
ffi.set_log_stream_port(RustLogStreamReceiver.logShared.port);
}
// final completer = Completer<Uint8List>();
// // Create a SendPort that accepts only one message.
// final sendPort = singleCompletePort(completer);
@@ -42,3 +52,44 @@ class FlowySDK {
// return completer.future;
}
}
class RustLogStreamReceiver {
static RustLogStreamReceiver logShared = RustLogStreamReceiver._internal();
late RawReceivePort _ffiPort;
late StreamController<Uint8List> _streamController;
late StreamSubscription<Uint8List> _subscription;
int get port => _ffiPort.sendPort.nativePort;
late Logger _logger;
RustLogStreamReceiver._internal() {
_ffiPort = RawReceivePort();
_streamController = StreamController();
_ffiPort.handler = _streamController.add;
_logger = Logger(
printer: PrettyPrinter(
methodCount: 0, // number of method calls to be displayed
errorMethodCount: 8, // number of method calls if stacktrace is provided
lineLength: 120, // width of the output
colors: false, // Colorful log messages
printEmojis: false, // Print an emoji for each log message
printTime: false, // Should each log print contain a timestamp
),
level: kDebugMode ? Level.trace : Level.info,
);
_subscription = _streamController.stream.listen((data) {
String decodedString = utf8.decode(data);
_logger.i(decodedString);
});
}
factory RustLogStreamReceiver() {
return logShared;
}
Future<void> dispose() async {
await _streamController.close();
await _subscription.cancel();
_ffiPort.close();
}
}
@@ -110,6 +110,22 @@ typedef _set_stream_port_Dart = int Function(
int port,
);
/// C function `set log stream port`.
int set_log_stream_port(int port) {
return _set_log_stream_port(port);
}
final _set_log_stream_port_Dart _set_log_stream_port = _dart_ffi_lib
.lookupFunction<_set_log_stream_port_C, _set_log_stream_port_Dart>(
'set_log_stream_port');
typedef _set_log_stream_port_C = Int32 Function(
Int64 port,
);
typedef _set_log_stream_port_Dart = int Function(
int port,
);
/// C function `link_me_please`.
void link_me_please() {
_link_me_please();
@@ -1,6 +1,5 @@
// ignore: import_of_legacy_library_into_null_safe
import 'dart:ffi';
import 'package:ffi/ffi.dart' as ffi;
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
@@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:ffi';
import 'dart:isolate';
import 'dart:typed_data';
import 'package:appflowy_backend/log.dart';
import 'protobuf/flowy-notification/subject.pb.dart';
@@ -11,6 +11,8 @@ const uint8_t *sync_event(const uint8_t *input, uintptr_t len);
int32_t set_stream_port(int64_t port);
int32_t set_log_stream_port(int64_t port);
void link_me_please(void);
void rust_log(int64_t level, const char *data);
@@ -15,6 +15,7 @@ class FlowyText extends StatelessWidget {
final String? fontFamily;
final List<String>? fallbackFontFamily;
final double? lineHeight;
final bool withTooltip;
const FlowyText(
this.text, {
@@ -30,6 +31,7 @@ class FlowyText extends StatelessWidget {
this.fontFamily,
this.fallbackFontFamily,
this.lineHeight,
this.withTooltip = false,
});
FlowyText.small(
@@ -44,6 +46,7 @@ class FlowyText extends StatelessWidget {
this.fontFamily,
this.fallbackFontFamily,
this.lineHeight,
this.withTooltip = false,
}) : fontWeight = FontWeight.w400,
fontSize = (Platform.isIOS || Platform.isAndroid) ? 14 : 12;
@@ -60,6 +63,7 @@ class FlowyText extends StatelessWidget {
this.fontFamily,
this.fallbackFontFamily,
this.lineHeight,
this.withTooltip = false,
}) : fontWeight = FontWeight.w400;
const FlowyText.medium(
@@ -75,6 +79,7 @@ class FlowyText extends StatelessWidget {
this.fontFamily,
this.fallbackFontFamily,
this.lineHeight,
this.withTooltip = false,
}) : fontWeight = FontWeight.w500;
const FlowyText.semibold(
@@ -90,6 +95,7 @@ class FlowyText extends StatelessWidget {
this.fontFamily,
this.fallbackFontFamily,
this.lineHeight,
this.withTooltip = false,
}) : fontWeight = FontWeight.w600;
// Some emojis are not supported on Linux and Android, fallback to noto color emoji
@@ -104,14 +110,17 @@ class FlowyText extends StatelessWidget {
this.decoration,
this.selectable = false,
this.lineHeight,
this.withTooltip = false,
}) : fontWeight = FontWeight.w400,
fontFamily = 'noto color emoji',
fallbackFontFamily = null;
@override
Widget build(BuildContext context) {
Widget child;
if (selectable) {
return SelectableText(
child = SelectableText(
text,
maxLines: maxLines,
textAlign: textAlign,
@@ -126,7 +135,7 @@ class FlowyText extends StatelessWidget {
),
);
} else {
return Text(
child = Text(
text,
maxLines: maxLines,
textAlign: textAlign,
@@ -142,5 +151,14 @@ class FlowyText extends StatelessWidget {
),
);
}
if (withTooltip) {
child = Tooltip(
message: text,
child: child,
);
}
return child;
}
}
@@ -1,9 +1,10 @@
import 'dart:async';
import 'package:flowy_infra/size.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flowy_infra/size.dart';
class FlowyTextField extends StatefulWidget {
final String? hintText;
final String? text;
@@ -31,6 +32,7 @@ class FlowyTextField extends StatefulWidget {
final TextStyle? hintStyle;
final InputDecoration? decoration;
final TextAlignVertical? textAlignVertical;
final TextInputAction? textInputAction;
final TextInputType? keyboardType;
final List<TextInputFormatter>? inputFormatters;
@@ -62,6 +64,7 @@ class FlowyTextField extends StatefulWidget {
this.hintStyle,
this.decoration,
this.textAlignVertical,
this.textInputAction,
this.keyboardType = TextInputType.multiline,
this.inputFormatters,
});
+2 -2
View File
@@ -53,8 +53,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: b927ec0
resolved-ref: b927ec0685c870c731c5b6d9688a031d0cd31e76
ref: "6d12761"
resolved-ref: "6d127619294060999522be904a3e72a59dc270ca"
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git
version: "2.3.3"
+1 -1
View File
@@ -169,7 +169,7 @@ dependency_overrides:
appflowy_editor:
git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: "b927ec0"
ref: "6d12761"
sheet:
git:
@@ -1,4 +1,4 @@
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/workspace/application/home/home_bloc.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
@@ -1,4 +1,4 @@
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
+34 -130
View File
@@ -156,7 +156,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"bincode",
@@ -712,7 +712,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"again",
"anyhow",
@@ -733,7 +733,6 @@ dependencies = [
"getrandom 0.2.10",
"gotrue",
"gotrue-entity",
"governor",
"mime",
"parking_lot 0.12.1",
"prost",
@@ -752,14 +751,13 @@ dependencies = [
"url",
"uuid",
"wasm-bindgen-futures",
"workspace-template",
"yrs",
]
[[package]]
name = "client-websocket"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"futures-channel",
"futures-util",
@@ -833,7 +831,7 @@ dependencies = [
[[package]]
name = "collab"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"async-trait",
@@ -857,7 +855,7 @@ dependencies = [
[[package]]
name = "collab-database"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"async-trait",
@@ -887,7 +885,7 @@ dependencies = [
[[package]]
name = "collab-document"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"collab",
@@ -906,7 +904,7 @@ dependencies = [
[[package]]
name = "collab-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"bytes",
@@ -921,7 +919,7 @@ dependencies = [
[[package]]
name = "collab-folder"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"chrono",
@@ -959,7 +957,7 @@ dependencies = [
[[package]]
name = "collab-plugins"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"async-stream",
@@ -998,7 +996,7 @@ dependencies = [
[[package]]
name = "collab-rt-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"bincode",
@@ -1023,7 +1021,7 @@ dependencies = [
[[package]]
name = "collab-rt-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"bincode",
@@ -1037,7 +1035,7 @@ dependencies = [
[[package]]
name = "collab-user"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"collab",
@@ -1096,9 +1094,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "cookie"
version = "0.16.2"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
dependencies = [
"percent-encoding",
"time",
@@ -1107,12 +1105,12 @@ dependencies = [
[[package]]
name = "cookie_store"
version = "0.16.2"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa"
checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6"
dependencies = [
"cookie",
"idna 0.2.3",
"idna 0.3.0",
"log",
"publicsuffix",
"serde",
@@ -1371,7 +1369,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"app-error",
@@ -2352,12 +2350,6 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-timer"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]]
name = "futures-util"
version = "0.3.30"
@@ -2687,7 +2679,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"futures-util",
@@ -2704,7 +2696,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"app-error",
@@ -2715,24 +2707,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "governor"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4"
dependencies = [
"cfg-if",
"dashmap",
"futures",
"futures-timer",
"no-std-compat",
"nonzero_ext",
"parking_lot 0.12.1",
"quanta",
"rand 0.8.5",
"smallvec",
]
[[package]]
name = "gtk"
version = "0.15.5"
@@ -3027,17 +3001,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "idna"
version = "0.3.0"
@@ -3155,7 +3118,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"reqwest",
@@ -3399,6 +3362,7 @@ version = "0.1.0"
dependencies = [
"chrono",
"lazy_static",
"lib-infra",
"serde",
"serde_json",
"tracing",
@@ -3519,15 +3483,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "mach2"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
dependencies = [
"libc",
]
[[package]]
name = "macroific"
version = "1.3.1"
@@ -3788,12 +3743,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "no-std-compat"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
[[package]]
name = "nodrop"
version = "0.1.14"
@@ -3810,12 +3759,6 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nonzero_ext"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
[[package]]
name = "ntapi"
version = "0.4.1"
@@ -4759,22 +4702,6 @@ dependencies = [
"psl-types",
]
[[package]]
name = "quanta"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"
dependencies = [
"crossbeam-utils",
"libc",
"mach2",
"once_cell",
"raw-cpuid",
"wasi 0.11.0+wasi-snapshot-preview1",
"web-sys",
"winapi",
]
[[package]]
name = "quick-xml"
version = "0.28.2"
@@ -4891,15 +4818,6 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "raw-cpuid"
version = "10.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "raw-window-handle"
version = "0.5.2"
@@ -5013,9 +4931,9 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.11.23"
version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
"base64 0.21.5",
"bytes",
@@ -5044,6 +4962,7 @@ dependencies = [
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"system-configuration",
"tokio",
"tokio-native-tls",
@@ -5599,7 +5518,7 @@ dependencies = [
[[package]]
name = "shared-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"app-error",
@@ -5865,6 +5784,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sysinfo"
version = "0.30.5"
@@ -7050,9 +6975,9 @@ checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
[[package]]
name = "wasm-streams"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
"futures-util",
"js-sys",
@@ -7584,27 +7509,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "workspace-template"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
dependencies = [
"anyhow",
"async-trait",
"bytes",
"collab",
"collab-document",
"collab-entity",
"collab-folder",
"getrandom 0.2.10",
"indexmap 2.1.0",
"nanoid",
"serde",
"serde_json",
"tokio",
"uuid",
]
[[package]]
name = "wry"
version = "0.24.6"
+8 -8
View File
@@ -87,7 +87,7 @@ yrs = { git = "https://github.com/appflowy/y-crdt", rev = "3f25bb510ca5274e7657d
# Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "aa4df32f6d3b53bec5e3715f5abfe4fb9079021b" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b1c3d779badcd382e3d6e46c292042de70d38cdd" }
# Please use the following script to update collab.
# Working directory: frontend
#
@@ -97,10 +97,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "aa4
# To switch to the local path, run:
# scripts/tool/update_collab_source.sh
# ⚠️⚠️⚠️️
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
+16 -10
View File
@@ -9,19 +9,19 @@ pub fn read_env() {
dotenv().ok();
let env = if cfg!(debug_assertions) {
include_str!("../env.development")
include_str!("../env.development")
} else {
include_str!("../env.production")
include_str!("../env.production")
};
for line in env.lines() {
if let Some((key, value)) = line.split_once('=') {
// Check if the environment variable is not already set in the system
let current_value = std::env::var(key).unwrap_or_default();
if current_value.is_empty() {
std::env::set_var(key, value);
}
if let Some((key, value)) = line.split_once('=') {
// Check if the environment variable is not already set in the system
let current_value = std::env::var(key).unwrap_or_default();
if current_value.is_empty() {
std::env::set_var(key, value);
}
}
}
}
@@ -29,7 +29,12 @@ pub fn init_flowy_core() -> AppFlowyCore {
let config_json = include_str!("../tauri.conf.json");
let config: tauri_utils::config::Config = serde_json::from_str(config_json).unwrap();
let app_version = config.package.version.clone().map(|v| v.to_string()).unwrap_or_else(|| "0.0.0".to_string());
let app_version = config
.package
.version
.clone()
.map(|v| v.to_string())
.unwrap_or_else(|| "0.0.0".to_string());
let mut data_path = tauri::api::path::app_local_data_dir(&config).unwrap();
if cfg!(debug_assertions) {
data_path.push("data_dev");
@@ -49,11 +54,12 @@ pub fn init_flowy_core() -> AppFlowyCore {
custom_application_path,
application_path,
device_id,
"tauri".to_string(),
DEFAULT_NAME.to_string(),
)
.log_filter("trace", vec!["appflowy_tauri".to_string()]);
let runtime = Arc::new(AFPluginRuntime::new().unwrap());
let cloned_runtime = runtime.clone();
runtime.block_on(async move { AppFlowyCore::new(config, cloned_runtime).await })
runtime.block_on(async move { AppFlowyCore::new(config, cloned_runtime, None).await })
}
+37 -143
View File
@@ -215,7 +215,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]]
name = "app-error"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"bincode",
@@ -378,9 +378,9 @@ dependencies = [
[[package]]
name = "brotli"
version = "3.4.0"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f"
checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -541,7 +541,7 @@ dependencies = [
[[package]]
name = "client-api"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"again",
"anyhow",
@@ -562,7 +562,6 @@ dependencies = [
"getrandom 0.2.12",
"gotrue",
"gotrue-entity",
"governor",
"mime",
"parking_lot 0.12.1",
"prost",
@@ -587,7 +586,7 @@ dependencies = [
[[package]]
name = "client-websocket"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"futures-channel",
"futures-util",
@@ -631,7 +630,7 @@ dependencies = [
[[package]]
name = "collab"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"async-trait",
@@ -655,7 +654,7 @@ dependencies = [
[[package]]
name = "collab-document"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"collab",
@@ -674,7 +673,7 @@ dependencies = [
[[package]]
name = "collab-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"bytes",
@@ -689,7 +688,7 @@ dependencies = [
[[package]]
name = "collab-folder"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"chrono",
@@ -727,7 +726,7 @@ dependencies = [
[[package]]
name = "collab-plugins"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"async-stream",
@@ -765,7 +764,7 @@ dependencies = [
[[package]]
name = "collab-rt-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"bincode",
@@ -790,7 +789,7 @@ dependencies = [
[[package]]
name = "collab-rt-protocol"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"bincode",
@@ -804,7 +803,7 @@ dependencies = [
[[package]]
name = "collab-user"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
dependencies = [
"anyhow",
"collab",
@@ -851,9 +850,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "cookie"
version = "0.16.2"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
dependencies = [
"percent-encoding",
"time",
@@ -862,12 +861,12 @@ dependencies = [
[[package]]
name = "cookie_store"
version = "0.16.2"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa"
checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6"
dependencies = [
"cookie",
"idna 0.2.3",
"idna 0.3.0",
"log",
"publicsuffix",
"serde",
@@ -956,7 +955,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa",
"phf 0.11.2",
"phf 0.8.0",
"smallvec",
]
@@ -1001,7 +1000,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]]
name = "database-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"app-error",
@@ -1629,12 +1628,6 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-timer"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]]
name = "futures-util"
version = "0.3.30"
@@ -1769,7 +1762,7 @@ dependencies = [
[[package]]
name = "gotrue"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"futures-util",
@@ -1786,7 +1779,7 @@ dependencies = [
[[package]]
name = "gotrue-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"app-error",
@@ -1797,24 +1790,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "governor"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4"
dependencies = [
"cfg-if 1.0.0",
"dashmap",
"futures",
"futures-timer",
"no-std-compat",
"nonzero_ext",
"parking_lot 0.12.1",
"quanta",
"rand 0.8.5",
"smallvec",
]
[[package]]
name = "h2"
version = "0.3.24"
@@ -2022,17 +1997,6 @@ dependencies = [
"cc",
]
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "idna"
version = "0.3.0"
@@ -2116,7 +2080,7 @@ dependencies = [
[[package]]
name = "infra"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"reqwest",
@@ -2342,15 +2306,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "mach2"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
dependencies = [
"libc",
]
[[package]]
name = "macroific"
version = "1.3.1"
@@ -2412,12 +2367,6 @@ dependencies = [
"tendril",
]
[[package]]
name = "matches"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]]
name = "md5"
version = "0.7.0"
@@ -2517,12 +2466,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "no-std-compat"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
[[package]]
name = "nom"
version = "7.1.3"
@@ -2533,12 +2476,6 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nonzero_ext"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
[[package]]
name = "num-bigint"
version = "0.4.4"
@@ -2569,16 +2506,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "object"
version = "0.32.2"
@@ -2836,7 +2763,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",
]
@@ -2856,7 +2783,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",
]
@@ -2924,19 +2850,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.48",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
@@ -3247,22 +3160,6 @@ dependencies = [
"psl-types",
]
[[package]]
name = "quanta"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab"
dependencies = [
"crossbeam-utils",
"libc",
"mach2",
"once_cell",
"raw-cpuid",
"wasi 0.11.0+wasi-snapshot-preview1",
"web-sys",
"winapi",
]
[[package]]
name = "quote"
version = "1.0.35"
@@ -3353,15 +3250,6 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "raw-cpuid"
version = "10.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
@@ -3417,9 +3305,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "reqwest"
version = "0.11.23"
version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
"base64 0.21.7",
"bytes",
@@ -3448,6 +3336,7 @@ dependencies = [
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"system-configuration",
"tokio",
"tokio-native-tls",
@@ -3816,7 +3705,7 @@ dependencies = [
[[package]]
name = "shared-entity"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=aa4df32f6d3b53bec5e3715f5abfe4fb9079021b#aa4df32f6d3b53bec5e3715f5abfe4fb9079021b"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=b1c3d779badcd382e3d6e46c292042de70d38cdd#b1c3d779badcd382e3d6e46c292042de70d38cdd"
dependencies = [
"anyhow",
"app-error",
@@ -4009,6 +3898,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "system-configuration"
version = "0.5.1"
@@ -4190,7 +4085,6 @@ dependencies = [
"bytes",
"libc",
"mio",
"num_cpus",
"pin-project-lite",
"socket2",
"tokio-macros",
@@ -4738,9 +4632,9 @@ dependencies = [
[[package]]
name = "wasm-streams"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
"futures-util",
"js-sys",
@@ -5073,4 +4967,4 @@ dependencies = [
[[patch.unused]]
name = "collab-database"
version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5f66f8c921646d7d8762cafc8bbec72d56c2e157#5f66f8c921646d7d8762cafc8bbec72d56c2e157"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=352c55199449fbe321965fd42d2ff09ff54cf3f1#352c55199449fbe321965fd42d2ff09ff54cf3f1"
+8 -8
View File
@@ -55,7 +55,7 @@ codegen-units = 1
# Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "aa4df32f6d3b53bec5e3715f5abfe4fb9079021b" }
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "b1c3d779badcd382e3d6e46c292042de70d38cdd" }
# Please use the following script to update collab.
# Working directory: frontend
#
@@ -65,10 +65,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "aa4
# To switch to the local path, run:
# scripts/tool/update_collab_source.sh
# ⚠️⚠️⚠️️
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5f66f8c921646d7d8762cafc8bbec72d56c2e157" }
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "352c55199449fbe321965fd42d2ff09ff54cf3f1" }
@@ -14,7 +14,7 @@ flowy-user-pub = { workspace = true }
strum_macros = "0.25.2"
tracing.workspace = true
lib-infra = { workspace = true }
collab = { workspace = true, features = ["async-plugin"] }
collab = { workspace = true }
collab-entity.workspace = true
collab-user.workspace = true
collab-integrate = { workspace = true }
@@ -30,7 +30,7 @@ flowy-error = { workspace = true, features = ["impl_from_dispatch_error", "web_t
flowy-document = { workspace = true, features = ["web_ts"] }
flowy-folder = { workspace = true, features = ["web_ts"] }
lib-infra = { workspace = true }
collab = { workspace = true, features = ["async-plugin"] }
collab = { workspace = true }
web-sys = "0.3"
wasm-bindgen-futures.workspace = true
uuid.workspace = true
+2 -1
View File
@@ -3,4 +3,5 @@ dist/
src-tauri/
.eslintrc.cjs
tsconfig.json
**/backend/**
**/backend/**
vite.config.ts
+2 -1
View File
@@ -3,4 +3,5 @@ dist/
src-tauri/
.eslintrc.cjs
tsconfig.json
src/application/services/tauri-services/
src/application/services/tauri-services/
vite.config.ts
+23
View File
@@ -0,0 +1,23 @@
FROM node:latest
RUN apt-get update && \
apt-get install -y nginx
RUN addgroup --system nginx && \
adduser --system --no-create-home --disabled-login --ingroup nginx nginx
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
COPY dist/ /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/nginx.conf
COPY nginx-signed.crt /etc/ssl/certs/nginx-signed.crt
COPY nginx-signed.key /etc/ssl/private/nginx-signed.key
RUN chown -R nginx:nginx /etc/ssl/certs/nginx-signed.crt /etc/ssl/private/nginx-signed.key
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
+71
View File
@@ -194,6 +194,77 @@ Don't modify the theme file in `frontend/appflowy_web_app/src/styles/variables`
}
```
### 📦 Deployment
Use the AppFlowy CI/CD pipeline to deploy the application to the test and production environments.
- Push the changes to the main branch
- Deploy Test Environment
- Automatically, the test environment will be deployed if merged to the main branch or build/test branch
- Deploy Production Environment
- Navigate to the Actions tab
- Click on the workflow and select the Run workflow
- Enter the options
- Click on the Run workflow button
#### 📦 Deployment (Self-Hosted)
##### Pre-requisites
Please ensure you have learned about:
- [Deploy Web application on AWS Cloud using EC2 Instance](https://www.youtube.com/watch?v=gWVIIU1ev0Y)
- [How to Install and Use Rsync Command](https://operavps.com/docs/install-rsync-command-in-linux/)
- [How to Use ssh-keygen to Generate a New SSH Key?](https://www.ssh.com/academy/ssh/keygen)
- [Linux post-installation steps for Docker Engine](https://docs.docker.com/engine/install/linux-postinstall/)
- [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html)
And then follow the steps below:
1. Ensure you have the following installed on your server:
- Docker: [Install Docker](https://docs.docker.com/engine/install/)
- Rsync: [Install Rsync](https://operavps.com/docs/install-rsync-command-in-linux/)
2. Create a new user for deploy, and generate an SSH key for the user
```bash
sudo adduser appflowy(or any name)
sudo su - appflowy
mkdir ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t rsa
chmod 600 ~/.ssh/authorized_keys
# add the user to the docker group, to run docker commands without sudo
sudo usermod -aG docker ${USER}
```
- visit the `~/.ssh/id_rsa` and `~/.ssh/id_rsa.pub` to get the private and public key respectively
- add the public key to the `~/.ssh/authorized_keys` file
- ensure the private key is kept safe
- exit and login back to the server with the new
user: `ssh -i your-existing-key.pem ec2-user@your-instance-public-dns`
3. Clone the AppFlowy repository
4. Set the following secrets in your
repository, have to
know [Using secrets in GitHub Actions](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions)
> Note: Test Environment: prefix the secret with `WEB_TEST_` and Production Environment: prefix the secret with `WEB_`
> for example, `WEB_TEST_SSH_PRIVATE_KEY` and `WEB_SSH_PRIVATE_KEY`
- `SSH_PRIVATE_KEY`: The private key generated in step 2: cat ~/.ssh/id_rsa
- `REMOTE_HOST`: The host of the server: `your-instance-public-dns` or `your-instance-ip`
- `REMOTE_USER`: The user created in step 2: `appflowy`
- `SSL_CERTIFICATE`: The SSL certificate for the
server - [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html)
- `SSL_CERTIFICATE_KEY`: The SSL certificate key for the
server - [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html)
5. Run the deployment workflow to deploy the application(production or test environment)
> Note: the test server will **automatically** deploy if merged to the main branch or build/test branch
### 🧪 Testing
> To be Continued...
+3
View File
@@ -0,0 +1,3 @@
AF_WS_URL=wss://beta.appflowy.cloud/ws/v1
AF_BASE_URL=https://beta.appflowy.cloud
AF_GOTRUE_URL=https://beta.appflowy.cloud/gotrue
+78
View File
@@ -0,0 +1,78 @@
# nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
gzip on;
gzip_static on;
gzip_http_version 1.0;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/wasm;
# Existing server block for HTTP
server {
listen 80;
server_name localhost;
#server_name appflowy.com *.appflowy.com;
location / {
return 301 https://$host$request_uri;
}
}
# Additional server block for HTTPS
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name localhost;
#server_name appflowy.com *.appflowy.com;
ssl_certificate /etc/ssl/certs/nginx-signed.crt;
ssl_certificate_key /etc/ssl/private/nginx-signed.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
+7 -2
View File
@@ -14,7 +14,8 @@
"tauri:dev": "tauri dev",
"css:variables": "node style-dictionary/config.cjs",
"sync:i18n": "node scripts/i18n.cjs",
"link:client-api": "rm -rf node_modules/.vite && node scripts/create-symlink.cjs"
"link:client-api": "rm -rf node_modules/.vite && node scripts/create-symlink.cjs",
"analyze": "ANALYZE_MODE=true vite build"
},
"dependencies": {
"@appflowyinc/client-api-wasm": "^0.0.2",
@@ -117,6 +118,7 @@
"postcss": "^8.4.21",
"prettier": "2.8.4",
"prettier-plugin-tailwindcss": "^0.2.2",
"rollup-plugin-visualizer": "^5.12.0",
"style-dictionary": "^3.9.2",
"tailwindcss": "^3.2.7",
"ts-jest": "^29.1.1",
@@ -125,7 +127,10 @@
"typescript": "4.9.5",
"uuid": "^9.0.0",
"vite": "^5.2.0",
"vite-plugin-compression2": "^1.0.0",
"vite-plugin-importer": "^0.2.5",
"vite-plugin-svgr": "^3.2.0",
"vite-plugin-terminal": "^1.2.0"
"vite-plugin-terminal": "^1.2.0",
"vite-plugin-total-bundle-size": "^1.0.7"
}
}
Loaded 100 of 168 files, more files were not shown because too many files have changed in this diff. Show more