fix: search launch review (#5169)

* fix: support filtering results by workspace

* feat: add search button to sidebar

* fix: reduce view/recent view fetching across application

* feat: add channel to search listener

* feat: clean + localization

* chore: remove redundant code

* fix: disable search

* chore: trigger ci

* chore: disable search in backend

* test: disable search tests for now

* feat: temp disable reliance on folder search

* fix: add debounce to inline actions

* chore: complete future if disposed

* fix: clean code

* chore: disable unused bloc with feature flag

* fix: recent views lazy read

* chore: revert podilfe change

* chore: update logs

* chore: update client api and collab

* chore: fix tst

* chore: fix test & update collab commit

* chore: update collab commit

* test: fix unit tests

* chore: update rust toolchain 1.77

* chore: use opt-level 1

* fix: code review

* chore: clippy

---------

Co-authored-by: nathan <nathan@appflowy.io>
Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
Mathias Mogensen 2024-04-23 15:46:57 +02:00 committed by GitHub
parent bf64b0d2fa
commit 275d0b2ac4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
91 changed files with 1057 additions and 848 deletions

View File

@ -20,7 +20,7 @@
# env: # env:
# CARGO_TERM_COLOR: always # CARGO_TERM_COLOR: always
# FLUTTER_VERSION: "3.19.0" # FLUTTER_VERSION: "3.19.0"
# RUST_TOOLCHAIN: "1.75" # RUST_TOOLCHAIN: "1.77.2"
# CARGO_MAKE_VERSION: "0.36.6" # CARGO_MAKE_VERSION: "0.36.6"
# concurrency: # concurrency:

View File

@ -26,7 +26,7 @@ on:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
FLUTTER_VERSION: "3.19.0" FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.75" RUST_TOOLCHAIN: "1.77.2"
CARGO_MAKE_VERSION: "0.36.6" CARGO_MAKE_VERSION: "0.36.6"
concurrency: concurrency:
@ -39,7 +39,7 @@ jobs:
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
os: [ubuntu-latest] os: [ ubuntu-latest ]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
flutter_profile: development-linux-x86_64 flutter_profile: development-linux-x86_64
@ -73,7 +73,7 @@ jobs:
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
os: [windows-latest] os: [ windows-latest ]
include: include:
- os: windows-latest - os: windows-latest
flutter_profile: development-windows-x86 flutter_profile: development-windows-x86
@ -99,7 +99,7 @@ jobs:
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
os: [macos-latest] os: [ macos-latest ]
include: include:
- os: macos-latest - os: macos-latest
flutter_profile: development-mac-x86_64 flutter_profile: development-mac-x86_64
@ -121,12 +121,12 @@ jobs:
flutter_profile: ${{ matrix.flutter_profile }} flutter_profile: ${{ matrix.flutter_profile }}
unit_test: unit_test:
needs: [prepare-linux] needs: [ prepare-linux ]
if: github.event.pull_request.draft != true if: github.event.pull_request.draft != true
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest] os: [ ubuntu-latest ]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
flutter_profile: development-linux-x86_64 flutter_profile: development-linux-x86_64
@ -212,11 +212,11 @@ jobs:
shell: bash shell: bash
cloud_integration_test: cloud_integration_test:
needs: [prepare-linux] needs: [ prepare-linux ]
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest] os: [ ubuntu-latest ]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
flutter_profile: development-linux-x86_64 flutter_profile: development-linux-x86_64
@ -301,12 +301,12 @@ jobs:
# split the integration tests into different machines to minimize the time # split the integration tests into different machines to minimize the time
integration_test_1: integration_test_1:
needs: [prepare-linux] needs: [ prepare-linux ]
if: github.event.pull_request.draft != true if: github.event.pull_request.draft != true
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest] os: [ ubuntu-latest ]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
target: 'x86_64-unknown-linux-gnu' target: 'x86_64-unknown-linux-gnu'
@ -325,12 +325,12 @@ jobs:
rust_target: ${{ matrix.target }} rust_target: ${{ matrix.target }}
integration_test_2: integration_test_2:
needs: [prepare-linux] needs: [ prepare-linux ]
if: github.event.pull_request.draft != true if: github.event.pull_request.draft != true
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest] os: [ ubuntu-latest ]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
target: 'x86_64-unknown-linux-gnu' target: 'x86_64-unknown-linux-gnu'
@ -349,12 +349,12 @@ jobs:
rust_target: ${{ matrix.target }} rust_target: ${{ matrix.target }}
integration_test_3: integration_test_3:
needs: [prepare-linux] needs: [ prepare-linux ]
if: github.event.pull_request.draft != true if: github.event.pull_request.draft != true
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest] os: [ ubuntu-latest ]
include: include:
- os: ubuntu-latest - os: ubuntu-latest
target: 'x86_64-unknown-linux-gnu' target: 'x86_64-unknown-linux-gnu'

View File

@ -19,7 +19,7 @@ on:
env: env:
FLUTTER_VERSION: "3.19.0" FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.75" RUST_TOOLCHAIN: "1.77.2"
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@ -31,7 +31,7 @@ jobs:
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
os: [macos-14] os: [ macos-14 ]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
@ -86,7 +86,7 @@ jobs:
model: 'iPhone 15' model: 'iPhone 15'
shutdown_after_job: false shutdown_after_job: false
# enable it again if the 12 mins timeout is fixed # enable it again if the 12 mins timeout is fixed
# - name: Run integration tests # - name: Run integration tests
# working-directory: frontend/appflowy_flutter # working-directory: frontend/appflowy_flutter
# run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }} # run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}

View File

@ -7,7 +7,7 @@ on:
env: env:
FLUTTER_VERSION: "3.19.0" FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.75" RUST_TOOLCHAIN: "1.77.2"
jobs: jobs:
create-release: create-release:
@ -232,10 +232,10 @@ jobs:
matrix: matrix:
job: job:
- { - {
targets: "aarch64-apple-darwin,x86_64-apple-darwin", targets: "aarch64-apple-darwin,x86_64-apple-darwin",
os: macos-11, os: macos-11,
extra-build-args: "", extra-build-args: "",
} }
steps: steps:
- name: Checkout source code - name: Checkout source code
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -336,12 +336,12 @@ jobs:
matrix: matrix:
job: job:
- { - {
arch: x86_64, arch: x86_64,
target: x86_64-unknown-linux-gnu, target: x86_64-unknown-linux-gnu,
os: ubuntu-20.04, os: ubuntu-20.04,
extra-build-args: "", extra-build-args: "",
flutter_profile: production-linux-x86_64, flutter_profile: production-linux-x86_64,
} }
steps: steps:
- name: Checkout source code - name: Checkout source code
uses: actions/checkout@v4 uses: actions/checkout@v4

View File

@ -19,7 +19,7 @@ on:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
RUST_TOOLCHAIN: "1.75" RUST_TOOLCHAIN: "1.77.2"
jobs: jobs:
test-on-ubuntu: test-on-ubuntu:

View File

@ -11,7 +11,7 @@ on:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
FLUTTER_VERSION: "3.19.0" FLUTTER_VERSION: "3.19.0"
RUST_TOOLCHAIN: "1.75" RUST_TOOLCHAIN: "1.77.2"
jobs: jobs:
tests: tests:

View File

@ -10,7 +10,7 @@ on:
env: env:
NODE_VERSION: "18.16.0" NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0" PNPM_VERSION: "8.5.0"
RUST_TOOLCHAIN: "1.75" RUST_TOOLCHAIN: "1.77.2"
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}

View File

@ -10,7 +10,7 @@ on:
env: env:
NODE_VERSION: "18.16.0" NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0" PNPM_VERSION: "8.5.0"
RUST_TOOLCHAIN: "1.75" RUST_TOOLCHAIN: "1.77.2"
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@ -22,7 +22,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [ubuntu-20.04] platform: [ ubuntu-20.04 ]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}

View File

@ -14,7 +14,7 @@ on:
env: env:
NODE_VERSION: "18.16.0" NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0" PNPM_VERSION: "8.5.0"
RUST_TOOLCHAIN: "1.75" RUST_TOOLCHAIN: "1.77.2"
jobs: jobs:

View File

@ -12,7 +12,7 @@ env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
NODE_VERSION: "18.16.0" NODE_VERSION: "18.16.0"
PNPM_VERSION: "8.5.0" PNPM_VERSION: "8.5.0"
RUST_TOOLCHAIN: "1.75" RUST_TOOLCHAIN: "1.77.2"
CARGO_MAKE_VERSION: "0.36.6" CARGO_MAKE_VERSION: "0.36.6"
jobs: jobs:

View File

@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-notification/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-search/entities.pbenum.dart'; import 'package:appflowy_backend/protobuf/flowy-search/notification.pbenum.dart';
import 'package:appflowy_backend/rust_stream.dart'; import 'package:appflowy_backend/rust_stream.dart';
import 'package:appflowy_result/appflowy_result.dart'; import 'package:appflowy_result/appflowy_result.dart';
@ -23,9 +23,11 @@ class SearchNotificationParser
SearchNotificationParser({ SearchNotificationParser({
super.id, super.id,
required super.callback, required super.callback,
String? channel,
}) : super( }) : super(
tyParser: (ty, source) => tyParser: (ty, source) => source == "$_source$channel"
source == _source ? SearchNotification.valueOf(ty) : null, ? SearchNotification.valueOf(ty)
: null,
errorParser: (bytes) => FlowyError.fromBuffer(bytes), errorParser: (bytes) => FlowyError.fromBuffer(bytes),
); );
} }
@ -39,7 +41,12 @@ class SearchNotificationListener {
SearchNotificationListener({ SearchNotificationListener({
required String objectId, required String objectId,
required SearchNotificationHandler handler, required SearchNotificationHandler handler,
}) : _parser = SearchNotificationParser(id: objectId, callback: handler) { String? channel,
}) : _parser = SearchNotificationParser(
id: objectId,
callback: handler,
channel: channel,
) {
_subscription = _subscription =
RustStreamReceiver.listen((observable) => _parser?.parse(observable)); RustStreamReceiver.listen((observable) => _parser?.parse(observable));
} }

View File

@ -1,12 +1,14 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:appflowy/mobile/presentation/database/board/mobile_board_screen.dart'; import 'package:appflowy/mobile/presentation/database/board/mobile_board_screen.dart';
import 'package:appflowy/mobile/presentation/database/mobile_calendar_screen.dart'; import 'package:appflowy/mobile/presentation/database/mobile_calendar_screen.dart';
import 'package:appflowy/mobile/presentation/database/mobile_grid_screen.dart'; import 'package:appflowy/mobile/presentation/database/mobile_grid_screen.dart';
import 'package:appflowy/mobile/presentation/presentation.dart'; import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/workspace/application/recent/recent_service.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
extension MobileRouter on BuildContext { extension MobileRouter on BuildContext {
@ -17,7 +19,7 @@ extension MobileRouter on BuildContext {
queryParameters: view.queryParameters(arguments), queryParameters: view.queryParameters(arguments),
).toString(), ).toString(),
).then((value) { ).then((value) {
RecentService().updateRecentViews([view.id], true); getIt<CachedRecentService>().updateRecentViews([view.id], true);
}); });
} }
} }

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
@ -8,7 +10,6 @@ import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';

View File

@ -102,10 +102,7 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
late final InlineActionsService inlineActionsService = InlineActionsService( late final InlineActionsService inlineActionsService = InlineActionsService(
context: context, context: context,
handlers: [ handlers: [
InlinePageReferenceService( InlinePageReferenceService(currentViewId: documentBloc.view.id),
currentViewId: documentBloc.view.id,
limitResults: 5,
),
DateReferenceService(context), DateReferenceService(context),
ReminderReferenceService(context), ReminderReferenceService(context),
], ],

View File

@ -11,28 +11,27 @@ import 'package:appflowy/plugins/inline_actions/inline_actions_menu.dart';
import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart'; import 'package:appflowy/plugins/inline_actions/inline_actions_result.dart';
import 'package:appflowy/plugins/inline_actions/service_handler.dart'; import 'package:appflowy/plugins/inline_actions/service_handler.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart'; import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart'; import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/application/view/view_service.dart'; import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy/workspace/application/workspace/workspace_listener.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart'; import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_infra_ui/widget/error_page.dart';
// const _channel = "InlinePageReference";
// TODO(Mathias): Clean up and use folder search instead
class InlinePageReferenceService extends InlineActionsDelegate { class InlinePageReferenceService extends InlineActionsDelegate {
InlinePageReferenceService({ InlinePageReferenceService({
required this.currentViewId, required this.currentViewId,
this.viewLayout, this.viewLayout,
this.customTitle, this.customTitle,
this.insertPage = false, this.insertPage = false,
this.limitResults = 0, this.limitResults = 5,
}) { }) : assert(limitResults > 0, 'limitResults must be greater than 0') {
init(); init();
} }
@ -48,147 +47,102 @@ class InlinePageReferenceService extends InlineActionsDelegate {
/// ///
final bool insertPage; final bool insertPage;
/// Defaults to 0 where there are no limits /// Defaults to 5
/// Anything above 0 will limit the page reference results /// Will limit the page reference results
/// to [limitResults]. /// to [limitResults].
/// ///
final int limitResults; final int limitResults;
final ViewBackendService service = ViewBackendService(); late final CachedRecentService _recentService;
List<InlineActionsMenuItem> _items = [];
List<InlineActionsMenuItem> _filtered = [];
UserProfilePB? _user; bool _recentViewsInitialized = false;
String? _workspaceId; late final List<InlineActionsMenuItem> _recentViews;
WorkspaceListener? _listener;
Future<void> init() async { Future<List<InlineActionsMenuItem>> _getRecentViews() async {
_items = await _generatePageItems(currentViewId, viewLayout); if (_recentViewsInitialized) {
_filtered = limitResults > 0 ? _items.take(limitResults).toList() : _items; return _recentViews;
}
await _initWorkspaceListener(); _recentViewsInitialized = true;
_initCompleter.complete(); final views =
} (await _recentService.recentViews()).reversed.toSet().toList();
Future<void> _initWorkspaceListener() async { // Filter by viewLayout
final snapshot = await Future.wait([ views.retainWhere(
FolderEventGetCurrentWorkspaceSetting().send(), (i) =>
getIt<AuthService>().getUser(), currentViewId != i.id &&
]); (viewLayout == null || i.layout == viewLayout),
final (workspaceSettings, userProfile) = (snapshot.first, snapshot.last);
_workspaceId = workspaceSettings.fold(
(s) => (s as WorkspaceSettingPB).workspaceId,
(e) => null,
); );
_user = userProfile.fold((s) => s as UserProfilePB, (e) => null); // Map to InlineActionsMenuItem, then take 5 items
return _recentViews = views.map(_fromView).take(5).toList();
}
if (_user != null && _workspaceId != null) { bool _viewsInitialized = false;
_listener = WorkspaceListener( late final List<ViewPB> _allViews;
user: _user!,
workspaceId: _workspaceId!, Future<List<ViewPB>> _getViews() async {
); if (_viewsInitialized) {
_listener!.start( return _allViews;
appsChanged: (_) async {
_items = await _generatePageItems(currentViewId, viewLayout);
_filtered =
limitResults > 0 ? _items.take(limitResults).toList() : _items;
},
);
} }
_viewsInitialized = true;
final viewResult = await ViewBackendService.getAllViews();
return _allViews = viewResult
.toNullable()
?.items
.where((v) => viewLayout == null || v.layout == viewLayout)
.toList() ??
const [];
}
Future<void> init() async {
_recentService = getIt<CachedRecentService>();
// _searchListener.start(onResultsClosed: _onResults);
}
@override
Future<void> dispose() async {
if (!_initCompleter.isCompleted) {
_initCompleter.complete();
}
await super.dispose();
} }
@override @override
Future<InlineActionsResult> search([ Future<InlineActionsResult> search([
String? search, String? search,
]) async { ]) async {
_filtered = await _filterItems(search); final isSearching = search != null && search.isNotEmpty;
late List<InlineActionsMenuItem> items;
if (isSearching) {
final allViews = await _getViews();
items = allViews
.where(
(view) => view.name.toLowerCase().contains(search.toLowerCase()),
)
.take(limitResults)
.map((view) => _fromView(view))
.toList();
} else {
items = await _getRecentViews();
}
return InlineActionsResult( return InlineActionsResult(
title: customTitle?.isNotEmpty == true title: customTitle?.isNotEmpty == true
? customTitle! ? customTitle!
: LocaleKeys.inlineActions_pageReference.tr(), : isSearching
results: _filtered, ? LocaleKeys.inlineActions_pageReference.tr()
: LocaleKeys.inlineActions_recentPages.tr(),
results: items,
); );
} }
@override
Future<void> dispose() async {
await _listener?.stop();
}
Future<List<InlineActionsMenuItem>> _filterItems(String? search) async {
await _initCompleter.future;
final items = (search == null || search.isEmpty)
? _items
: _items.where(
(item) =>
item.keywords != null &&
item.keywords!.isNotEmpty &&
item.keywords!.any(
(keyword) => keyword.contains(search.toLowerCase()),
),
);
return limitResults > 0
? items.take(limitResults).toList()
: items.toList();
}
Future<List<InlineActionsMenuItem>> _generatePageItems(
String currentViewId,
ViewLayoutPB? viewLayout,
) async {
late List<ViewPB> views;
if (viewLayout != null) {
views = await service.fetchViewsWithLayoutType(viewLayout);
} else {
views = await service.fetchViews();
}
if (views.isEmpty) {
return [];
}
final List<InlineActionsMenuItem> pages = [];
views.sort((a, b) => b.createTime.compareTo(a.createTime));
for (final view in views) {
if (view.id == currentViewId) {
continue;
}
final pageSelectionMenuItem = InlineActionsMenuItem(
keywords: [view.name.toLowerCase()],
label: view.name,
icon: (onSelected) => view.icon.value.isNotEmpty
? EmojiText(
emoji: view.icon.value,
fontSize: 12,
textAlign: TextAlign.center,
lineHeight: 1.3,
)
: view.defaultIcon(),
onSelected: (context, editorState, menuService, replace) => insertPage
? _onInsertPageRef(view, context, editorState, replace)
: _onInsertLinkRef(
view,
context,
editorState,
menuService,
replace,
),
);
pages.add(pageSelectionMenuItem);
}
return pages;
}
Future<void> _onInsertPageRef( Future<void> _onInsertPageRef(
ViewPB view, ViewPB view,
BuildContext context, BuildContext context,
@ -268,4 +222,32 @@ class InlinePageReferenceService extends InlineActionsDelegate {
await editorState.apply(transaction); await editorState.apply(transaction);
} }
InlineActionsMenuItem _fromView(ViewPB view) => InlineActionsMenuItem(
keywords: [view.name.toLowerCase()],
label: view.name,
icon: (onSelected) => view.icon.value.isNotEmpty
? EmojiText(
emoji: view.icon.value,
fontSize: 12,
textAlign: TextAlign.center,
lineHeight: 1.3,
)
: view.defaultIcon(),
onSelected: (context, editorState, menu, replace) => insertPage
? _onInsertPageRef(view, context, editorState, replace)
: _onInsertLinkRef(view, context, editorState, menu, replace),
);
// Future<InlineActionsMenuItem?> _fromSearchResult(
// SearchResultPB result,
// ) async {
// final viewRes = await ViewBackendService.getView(result.viewId);
// final view = viewRes.toNullable();
// if (view == null) {
// return null;
// }
// return _fromView(view);
// }
} }

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -79,6 +81,8 @@ class _InlineActionsHandlerState extends State<InlineActionsHandler> {
final _focusNode = FocusNode(debugLabel: 'inline_actions_menu_handler'); final _focusNode = FocusNode(debugLabel: 'inline_actions_menu_handler');
final _scrollController = ScrollController(); final _scrollController = ScrollController();
Timer? _debounce;
late List<InlineActionsResult> results = widget.results; late List<InlineActionsResult> results = widget.results;
int invalidCounter = 0; int invalidCounter = 0;
late int startOffset; late int startOffset;
@ -86,7 +90,8 @@ class _InlineActionsHandlerState extends State<InlineActionsHandler> {
String _search = ''; String _search = '';
set search(String search) { set search(String search) {
_search = search; _search = search;
_doSearch(); _debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 200), _doSearch);
} }
Future<void> _doSearch() async { Future<void> _doSearch() async {
@ -138,6 +143,7 @@ class _InlineActionsHandlerState extends State<InlineActionsHandler> {
void dispose() { void dispose() {
_scrollController.dispose(); _scrollController.dispose();
_focusNode.dispose(); _focusNode.dispose();
_debounce?.cancel();
super.dispose(); super.dispose();
} }

View File

@ -29,6 +29,9 @@ enum FeatureFlag {
// if it's on, the collaborators will show in the database // if it's on, the collaborators will show in the database
syncDatabase, syncDatabase,
// used for the search feature
search,
// used for ignore the conflicted feature flag // used for ignore the conflicted feature flag
unknown; unknown;
@ -98,15 +101,13 @@ enum FeatureFlag {
switch (this) { switch (this) {
case FeatureFlag.collaborativeWorkspace: case FeatureFlag.collaborativeWorkspace:
return false;
case FeatureFlag.membersSettings: case FeatureFlag.membersSettings:
return false; case FeatureFlag.search:
case FeatureFlag.syncDocument:
return true;
case FeatureFlag.syncDatabase:
return true;
case FeatureFlag.unknown: case FeatureFlag.unknown:
return false; return false;
case FeatureFlag.syncDocument:
case FeatureFlag.syncDatabase:
return true;
} }
} }
@ -120,6 +121,8 @@ enum FeatureFlag {
return 'if it\'s on, the document will be synced in real-time'; return 'if it\'s on, the document will be synced in real-time';
case FeatureFlag.syncDatabase: case FeatureFlag.syncDatabase:
return 'if it\'s on, the collaborators will show in the database'; return 'if it\'s on, the collaborators will show in the database';
case FeatureFlag.search:
return 'if it\'s on, the command palette and search button will be available';
case FeatureFlag.unknown: case FeatureFlag.unknown:
return ''; return '';
} }

View File

@ -21,6 +21,7 @@ import 'package:appflowy/user/presentation/router.dart';
import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart'; import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart';
import 'package:appflowy/workspace/application/edit_panel/edit_panel_bloc.dart'; import 'package:appflowy/workspace/application/edit_panel/edit_panel_bloc.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart'; import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart'; import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:appflowy/workspace/application/settings/appearance/desktop_appearance.dart'; import 'package:appflowy/workspace/application/settings/appearance/desktop_appearance.dart';
import 'package:appflowy/workspace/application/settings/appearance/mobile_appearance.dart'; import 'package:appflowy/workspace/application/settings/appearance/mobile_appearance.dart';
@ -171,6 +172,7 @@ void _resolveUserDeps(GetIt getIt, IntegrationMode mode) {
getIt.registerFactory<EditPanelBloc>(() => EditPanelBloc()); getIt.registerFactory<EditPanelBloc>(() => EditPanelBloc());
getIt.registerFactory<SplashBloc>(() => SplashBloc()); getIt.registerFactory<SplashBloc>(() => SplashBloc());
getIt.registerLazySingleton<NetworkListener>(() => NetworkListener()); getIt.registerLazySingleton<NetworkListener>(() => NetworkListener());
getIt.registerLazySingleton<CachedRecentService>(() => CachedRecentService());
} }
void _resolveHomeDeps(GetIt getIt) { void _resolveHomeDeps(GetIt getIt) {
@ -203,12 +205,10 @@ void _resolveHomeDeps(GetIt getIt) {
} }
void _resolveFolderDeps(GetIt getIt) { void _resolveFolderDeps(GetIt getIt) {
//workspace // Workspace
getIt.registerFactoryParam<WorkspaceListener, UserProfilePB, String>( getIt.registerFactoryParam<WorkspaceListener, UserProfilePB, String>(
(user, workspaceId) => WorkspaceListener( (user, workspaceId) =>
user: user, WorkspaceListener(user: user, workspaceId: workspaceId),
workspaceId: workspaceId,
),
); );
getIt.registerFactoryParam<ViewBloc, ViewPB, void>( getIt.registerFactoryParam<ViewBloc, ViewPB, void>(
@ -217,21 +217,23 @@ void _resolveFolderDeps(GetIt getIt) {
), ),
); );
//Settings // Settings
getIt.registerFactoryParam<SettingsDialogBloc, UserProfilePB, void>( getIt.registerFactoryParam<SettingsDialogBloc, UserProfilePB, void>(
(user, _) => SettingsDialogBloc(user), (user, _) => SettingsDialogBloc(user),
); );
//User // User
getIt.registerFactoryParam<SettingsUserViewBloc, UserProfilePB, void>( getIt.registerFactoryParam<SettingsUserViewBloc, UserProfilePB, void>(
(user, _) => SettingsUserViewBloc(user), (user, _) => SettingsUserViewBloc(user),
); );
// trash // Trash
getIt.registerLazySingleton<TrashService>(() => TrashService()); getIt.registerLazySingleton<TrashService>(() => TrashService());
getIt.registerLazySingleton<TrashListener>(() => TrashListener()); getIt.registerLazySingleton<TrashListener>(() => TrashListener());
getIt.registerFactory<TrashBloc>( getIt.registerFactory<TrashBloc>(
() => TrashBloc(), () => TrashBloc(),
); );
// Favorite
getIt.registerFactory<FavoriteBloc>(() => FavoriteBloc()); getIt.registerFactory<FavoriteBloc>(() => FavoriteBloc());
} }

View File

@ -1,12 +1,13 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/env/cloud_env.dart'; import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/startup/tasks/feature_flag_task.dart'; import 'package:appflowy/startup/tasks/feature_flag_task.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart'; import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy_backend/appflowy_backend.dart'; import 'package:appflowy_backend/appflowy_backend.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
@ -136,6 +137,7 @@ class FlowyRunner {
if (isAppFlowyCloudEnabled) InitAppFlowyCloudTask(), if (isAppFlowyCloudEnabled) InitAppFlowyCloudTask(),
const InitAppWidgetTask(), const InitAppWidgetTask(),
const InitPlatformServiceTask(), const InitPlatformServiceTask(),
const RecentServiceTask(),
], ],
], ],
); );

View File

@ -5,11 +5,13 @@ import 'package:flutter/services.dart';
import 'package:appflowy/mobile/application/mobile_router.dart'; import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart'; import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart'; import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
import 'package:appflowy/user/application/user_settings_service.dart'; import 'package:appflowy/user/application/user_settings_service.dart';
import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart'; import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart';
import 'package:appflowy/workspace/application/action_navigation/navigation_action.dart'; import 'package:appflowy/workspace/application/action_navigation/navigation_action.dart';
import 'package:appflowy/workspace/application/command_palette/command_palette_bloc.dart';
import 'package:appflowy/workspace/application/notification/notification_service.dart'; import 'package:appflowy/workspace/application/notification/notification_service.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart'; import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/notifications/notification_settings_cubit.dart'; import 'package:appflowy/workspace/application/settings/notifications/notification_settings_cubit.dart';
@ -126,18 +128,27 @@ class ApplicationWidget extends StatefulWidget {
class _ApplicationWidgetState extends State<ApplicationWidget> { class _ApplicationWidgetState extends State<ApplicationWidget> {
late final GoRouter routerConfig; late final GoRouter routerConfig;
final _commandPaletteNotifier = ValueNotifier<bool>(false);
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// Avoid rebuild routerConfig when the appTheme is changed.
// avoid rebuild routerConfig when the appTheme is changed.
routerConfig = generateRouter(widget.child); routerConfig = generateRouter(widget.child);
} }
@override
void dispose() {
_commandPaletteNotifier.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
if (FeatureFlag.search.isOn)
BlocProvider<CommandPaletteBloc>(create: (_) => CommandPaletteBloc()),
BlocProvider<AppearanceSettingsCubit>( BlocProvider<AppearanceSettingsCubit>(
create: (_) => AppearanceSettingsCubit( create: (_) => AppearanceSettingsCubit(
widget.appearanceSetting, widget.appearanceSetting,
@ -152,10 +163,7 @@ class _ApplicationWidgetState extends State<ApplicationWidget> {
create: (_) => DocumentAppearanceCubit()..fetch(), create: (_) => DocumentAppearanceCubit()..fetch(),
), ),
BlocProvider.value(value: getIt<RenameViewBloc>()), BlocProvider.value(value: getIt<RenameViewBloc>()),
BlocProvider.value( BlocProvider.value(value: getIt<ActionNavigationBloc>()),
value: getIt<ActionNavigationBloc>()
..add(const ActionNavigationEvent.initialize()),
),
BlocProvider.value( BlocProvider.value(
value: getIt<ReminderBloc>()..add(const ReminderEvent.started()), value: getIt<ReminderBloc>()..add(const ReminderEvent.started()),
), ),
@ -196,10 +204,12 @@ class _ApplicationWidgetState extends State<ApplicationWidget> {
), ),
child: overlayManagerBuilder( child: overlayManagerBuilder(
context, context,
CommandPalette( FeatureFlag.search.isOn
toggleNotifier: ValueNotifier<bool>(false), ? CommandPalette(
child: child, toggleNotifier: _commandPaletteNotifier,
), child: child,
)
: child,
), ),
), ),
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,

View File

@ -12,3 +12,4 @@ export 'platform_service.dart';
export 'rust_sdk.dart'; export 'rust_sdk.dart';
export 'supabase_task.dart'; export 'supabase_task.dart';
export 'windows.dart'; export 'windows.dart';
export 'recent_service_task.dart';

View File

@ -0,0 +1,14 @@
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/recent/prelude.dart';
import 'package:appflowy_backend/log.dart';
class RecentServiceTask extends LaunchTask {
const RecentServiceTask();
@override
Future<void> initialize(LaunchContext context) async =>
Log.info('[CachedRecentService] Initialized');
@override
Future<void> dispose() async => getIt<CachedRecentService>().dispose();
}

View File

@ -1,10 +1,5 @@
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/workspace/application/action_navigation/navigation_action.dart'; import 'package:appflowy/workspace/application/action_navigation/navigation_action.dart';
import 'package:appflowy/workspace/application/view/view_service.dart'; import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy/workspace/application/workspace/workspace_listener.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
@ -15,15 +10,21 @@ class ActionNavigationBloc
ActionNavigationBloc() : super(const ActionNavigationState.initial()) { ActionNavigationBloc() : super(const ActionNavigationState.initial()) {
on<ActionNavigationEvent>((event, emit) async { on<ActionNavigationEvent>((event, emit) async {
await event.when( await event.when(
initialize: () async { performAction: (action, nextActions) async {
final views = await ViewBackendService().fetchViews(); NavigationAction currentAction = action;
emit(state.copyWith(views: views)); if (currentAction.arguments?[ActionArgumentKeys.view] == null &&
await initializeListeners(); action.type == ActionType.openView) {
}, final result = await ViewBackendService.getView(action.objectId);
viewsChanged: (views) { final view = result.toNullable();
emit(state.copyWith(views: views)); if (view != null) {
}, if (currentAction.arguments == null) {
performAction: (action, nextActions) { currentAction = currentAction.copyWith(arguments: {});
}
action.arguments?.addAll({ActionArgumentKeys.view: view});
}
}
emit(state.copyWith(action: action, nextActions: nextActions)); emit(state.copyWith(action: action, nextActions: nextActions));
if (nextActions.isNotEmpty) { if (nextActions.isNotEmpty) {
@ -43,92 +44,38 @@ class ActionNavigationBloc
); );
}); });
} }
WorkspaceListener? _workspaceListener;
@override
Future<void> close() async {
await _workspaceListener?.stop();
return super.close();
}
Future<void> initializeListeners() async {
if (_workspaceListener != null) {
return;
}
final userOrFailure = await getIt<AuthService>().getUser();
final user = userOrFailure.fold((s) => s, (f) => null);
if (user == null) {
_workspaceListener = null;
return;
}
final workspaceSettingsOrFailure =
await FolderEventGetCurrentWorkspaceSetting().send();
final workspaceId = workspaceSettingsOrFailure.fold(
(s) => s.workspaceId,
(f) => null,
);
if (workspaceId == null) {
_workspaceListener = null;
return;
}
_workspaceListener = WorkspaceListener(
user: user,
workspaceId: workspaceId,
);
_workspaceListener?.start(
appsChanged: (_) async {
final views = await ViewBackendService().fetchViews();
add(ActionNavigationEvent.viewsChanged(views));
},
);
}
} }
@freezed @freezed
class ActionNavigationEvent with _$ActionNavigationEvent { class ActionNavigationEvent with _$ActionNavigationEvent {
const factory ActionNavigationEvent.initialize() = _Initialize;
const factory ActionNavigationEvent.performAction({ const factory ActionNavigationEvent.performAction({
required NavigationAction action, required NavigationAction action,
@Default([]) List<NavigationAction> nextActions, @Default([]) List<NavigationAction> nextActions,
}) = _PerformAction; }) = _PerformAction;
const factory ActionNavigationEvent.viewsChanged(List<ViewPB> views) =
_ViewsChanged;
} }
class ActionNavigationState { class ActionNavigationState {
const ActionNavigationState.initial() const ActionNavigationState.initial()
: action = null, : action = null,
nextActions = const [], nextActions = const [];
views = const [];
const ActionNavigationState({ const ActionNavigationState({
required this.action, required this.action,
this.nextActions = const [], this.nextActions = const [],
this.views = const [],
}); });
final NavigationAction? action; final NavigationAction? action;
final List<NavigationAction> nextActions; final List<NavigationAction> nextActions;
final List<ViewPB> views;
ActionNavigationState copyWith({ ActionNavigationState copyWith({
NavigationAction? action, NavigationAction? action,
List<NavigationAction>? nextActions, List<NavigationAction>? nextActions,
List<ViewPB>? views,
}) => }) =>
ActionNavigationState( ActionNavigationState(
action: action ?? this.action, action: action ?? this.action,
nextActions: nextActions ?? this.nextActions, nextActions: nextActions ?? this.nextActions,
views: views ?? this.views,
); );
ActionNavigationState setNoAction() => ActionNavigationState setNoAction() =>
ActionNavigationState(action: null, nextActions: [], views: views); const ActionNavigationState(action: null);
} }

View File

@ -7,12 +7,14 @@ import 'package:appflowy/plugins/trash/application/trash_service.dart';
import 'package:appflowy/workspace/application/command_palette/search_listener.dart'; import 'package:appflowy/workspace/application/command_palette/search_listener.dart';
import 'package:appflowy/workspace/application/command_palette/search_service.dart'; import 'package:appflowy/workspace/application/command_palette/search_service.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/trash.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/trash.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-search/result.pb.dart';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
part 'command_palette_bloc.freezed.dart'; part 'command_palette_bloc.freezed.dart';
const _searchChannel = 'CommandPalette';
class CommandPaletteBloc class CommandPaletteBloc
extends Bloc<CommandPaletteEvent, CommandPaletteState> { extends Bloc<CommandPaletteEvent, CommandPaletteState> {
CommandPaletteBloc() : super(CommandPaletteState.initial()) { CommandPaletteBloc() : super(CommandPaletteState.initial()) {
@ -27,9 +29,12 @@ class CommandPaletteBloc
Timer? _debounceOnChanged; Timer? _debounceOnChanged;
final TrashService _trashService = TrashService(); final TrashService _trashService = TrashService();
final SearchListener _searchListener = SearchListener(); final SearchListener _searchListener = SearchListener(
channel: _searchChannel,
);
final TrashListener _trashListener = TrashListener(); final TrashListener _trashListener = TrashListener();
String? _oldQuery; String? _oldQuery;
String? _workspaceId;
@override @override
Future<void> close() { Future<void> close() {
@ -44,8 +49,7 @@ class CommandPaletteBloc
searchChanged: _debounceOnSearchChanged, searchChanged: _debounceOnSearchChanged,
trashChanged: (trash) async { trashChanged: (trash) async {
if (trash != null) { if (trash != null) {
emit(state.copyWith(trash: trash)); return emit(state.copyWith(trash: trash));
return;
} }
final trashOrFailure = await _trashService.readTrash(); final trashOrFailure = await _trashService.readTrash();
@ -59,10 +63,14 @@ class CommandPaletteBloc
} }
}, },
performSearch: (search) async { performSearch: (search) async {
if (search.isNotEmpty) { if (search.isNotEmpty && search != state.query) {
_oldQuery = state.query; _oldQuery = state.query;
emit(state.copyWith(query: search, isLoading: true)); emit(state.copyWith(query: search, isLoading: true));
await SearchBackendService.performSearch(search); await SearchBackendService.performSearch(
search,
workspaceId: _workspaceId,
channel: _searchChannel,
);
} else { } else {
emit(state.copyWith(query: null, isLoading: false, results: [])); emit(state.copyWith(query: null, isLoading: false, results: []));
} }
@ -82,6 +90,10 @@ class CommandPaletteBloc
), ),
); );
}, },
workspaceChanged: (workspaceId) {
_workspaceId = workspaceId;
emit(state.copyWith(results: [], query: '', isLoading: false));
},
); );
}); });
} }
@ -162,6 +174,10 @@ class CommandPaletteEvent with _$CommandPaletteEvent {
const factory CommandPaletteEvent.trashChanged({ const factory CommandPaletteEvent.trashChanged({
@Default(null) List<TrashPB>? trash, @Default(null) List<TrashPB>? trash,
}) = _TrashChanged; }) = _TrashChanged;
const factory CommandPaletteEvent.workspaceChanged({
@Default(null) String? workspaceId,
}) = _WorkspaceChanged;
} }
@freezed @freezed

View File

@ -4,7 +4,8 @@ import 'dart:typed_data';
import 'package:appflowy/core/notification/search_notification.dart'; import 'package:appflowy/core/notification/search_notification.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-search/notification.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-search/result.pb.dart';
import 'package:appflowy_result/appflowy_result.dart'; import 'package:appflowy_result/appflowy_result.dart';
import 'package:flowy_infra/notifier.dart'; import 'package:flowy_infra/notifier.dart';
@ -12,7 +13,15 @@ import 'package:flowy_infra/notifier.dart';
const _searchObjectId = "SEARCH_IDENTIFIER"; const _searchObjectId = "SEARCH_IDENTIFIER";
class SearchListener { class SearchListener {
SearchListener(); SearchListener({this.channel});
/// Use this to filter out search results from other channels.
///
/// If null, it will receive search results from all
/// channels, otherwise it will only receive search results from the specified
/// channel.
///
final String? channel;
PublishNotifier<RepeatedSearchResultPB>? _updateNotifier = PublishNotifier(); PublishNotifier<RepeatedSearchResultPB>? _updateNotifier = PublishNotifier();
PublishNotifier<RepeatedSearchResultPB>? _updateDidCloseNotifier = PublishNotifier<RepeatedSearchResultPB>? _updateDidCloseNotifier =
@ -20,14 +29,21 @@ class SearchListener {
SearchNotificationListener? _listener; SearchNotificationListener? _listener;
void start({ void start({
required void Function(RepeatedSearchResultPB) onResultsChanged, void Function(RepeatedSearchResultPB)? onResultsChanged,
required void Function(RepeatedSearchResultPB) onResultsClosed, void Function(RepeatedSearchResultPB)? onResultsClosed,
}) { }) {
_updateNotifier?.addPublishListener(onResultsChanged); if (onResultsChanged != null) {
_updateDidCloseNotifier?.addPublishListener(onResultsClosed); _updateNotifier?.addPublishListener(onResultsChanged);
}
if (onResultsClosed != null) {
_updateDidCloseNotifier?.addPublishListener(onResultsClosed);
}
_listener = SearchNotificationListener( _listener = SearchNotificationListener(
objectId: _searchObjectId, objectId: _searchObjectId,
handler: _handler, handler: _handler,
channel: channel,
); );
} }

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-search/result.pb.dart';
extension GetIcon on SearchResultPB { extension GetIcon on SearchResultPB {
Widget? getIcon() { Widget? getIcon() {

View File

@ -1,13 +1,21 @@
import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-search/query.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-search/search_filter.pb.dart';
import 'package:appflowy_result/appflowy_result.dart'; import 'package:appflowy_result/appflowy_result.dart';
class SearchBackendService { class SearchBackendService {
static Future<FlowyResult<void, FlowyError>> performSearch( static Future<FlowyResult<void, FlowyError>> performSearch(
String keyword, String keyword, {
) async { String? workspaceId,
final request = SearchQueryPB(search: keyword); String? channel,
}) async {
final filter = SearchFilterPB(workspaceId: workspaceId);
final request = SearchQueryPB(
search: keyword,
filter: filter,
channel: channel,
);
return SearchEventSearch(request).send(); return SearchEventSearch(request).send();
} }

View File

@ -1,15 +0,0 @@
import 'dart:async';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
class HomeService {
static Future<FlowyResult<ViewPB, FlowyError>> readApp({
required String appId,
}) {
final payload = ViewIdPB.create()..value = appId;
return FolderEventGetView(payload).send();
}
}

View File

@ -0,0 +1,87 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/recent/recent_listener.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
/// This is a lazy-singleton to share recent views across the application.
///
/// Use-cases:
/// - Desktop: Command Palette recent view history
/// - Desktop: (Documents) Inline-page reference recent view history
/// - Mobile: Recent view history on home screen
///
/// See the related [LaunchTask] in [RecentServiceTask].
///
class CachedRecentService {
CachedRecentService();
Completer<void> _completer = Completer();
ValueNotifier<List<ViewPB>> notifier = ValueNotifier(const []);
List<ViewPB> _recentViews = const [];
final _listener = RecentViewsListener();
Future<List<ViewPB>> recentViews() async {
if (_isInitialized) return _recentViews;
_isInitialized = true;
_listener.start(recentViewsUpdated: _recentViewsUpdated);
final result = await _readRecentViews();
_recentViews = result.toNullable()?.items ?? const [];
notifier.value = _recentViews;
_completer.complete();
return _recentViews;
}
/// Updates the recent views history
Future<FlowyResult<void, FlowyError>> updateRecentViews(
List<String> viewIds,
bool addInRecent,
) async {
return FolderEventUpdateRecentViews(
UpdateRecentViewPayloadPB(viewIds: viewIds, addInRecent: addInRecent),
).send();
}
Future<FlowyResult<RepeatedViewPB, FlowyError>> _readRecentViews() =>
FolderEventReadRecentViews().send();
bool _isInitialized = false;
Future<void> reset() async {
await _listener.stop();
_resetCompleter();
_isInitialized = false;
_recentViews = const [];
}
Future<void> dispose() async {
await _listener.stop();
}
void _recentViewsUpdated(
FlowyResult<RepeatedViewIdPB, FlowyError> result,
) {
final viewIds = result.toNullable();
if (viewIds != null) {
_readRecentViews().then(
(views) => _recentViews = views.toNullable()?.items ?? const [],
);
}
}
void _resetCompleter() {
if (!_completer.isCompleted) {
_completer.complete();
}
_completer = Completer<void>();
}
}

View File

@ -1,2 +1,2 @@
export 'recent_service.dart'; export 'cached_recent_service.dart';
export 'recent_views_bloc.dart'; export 'recent_views_bloc.dart';

View File

@ -1,19 +0,0 @@
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_result/appflowy_result.dart';
class RecentService {
Future<FlowyResult<void, FlowyError>> updateRecentViews(
List<String> viewIds,
bool addInRecent,
) async {
return FolderEventUpdateRecentViews(
UpdateRecentViewPayloadPB(viewIds: viewIds, addInRecent: addInRecent),
).send();
}
Future<FlowyResult<RepeatedViewPB, FlowyError>> readRecentViews() {
return FolderEventReadRecentViews().send();
}
}

View File

@ -1,9 +1,6 @@
import 'package:appflowy/workspace/application/recent/recent_listener.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/recent/recent_service.dart'; import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
@ -11,15 +8,15 @@ part 'recent_views_bloc.freezed.dart';
class RecentViewsBloc extends Bloc<RecentViewsEvent, RecentViewsState> { class RecentViewsBloc extends Bloc<RecentViewsEvent, RecentViewsState> {
RecentViewsBloc() : super(RecentViewsState.initial()) { RecentViewsBloc() : super(RecentViewsState.initial()) {
_service = getIt<CachedRecentService>();
_dispatch(); _dispatch();
} }
final _service = RecentService(); late final CachedRecentService _service;
final _listener = RecentViewsListener();
@override @override
Future<void> close() async { Future<void> close() async {
await _listener.stop(); _service.notifier.removeListener(_onRecentViewsUpdated);
return super.close(); return super.close();
} }
@ -28,9 +25,7 @@ class RecentViewsBloc extends Bloc<RecentViewsEvent, RecentViewsState> {
(event, emit) async { (event, emit) async {
await event.map( await event.map(
initial: (e) async { initial: (e) async {
_listener.start( _service.notifier.addListener(_onRecentViewsUpdated);
recentViewsUpdated: (result) => _onRecentViewsUpdated(result),
);
add(const RecentViewsEvent.fetchRecentViews()); add(const RecentViewsEvent.fetchRecentViews());
}, },
addRecentViews: (e) async { addRecentViews: (e) async {
@ -40,22 +35,15 @@ class RecentViewsBloc extends Bloc<RecentViewsEvent, RecentViewsState> {
await _service.updateRecentViews(e.viewIds, false); await _service.updateRecentViews(e.viewIds, false);
}, },
fetchRecentViews: (e) async { fetchRecentViews: (e) async {
final result = await _service.readRecentViews(); emit(state.copyWith(views: await _service.recentViews()));
result.fold(
(views) => emit(state.copyWith(views: views.items)),
(error) => Log.error(error),
);
}, },
); );
}, },
); );
} }
void _onRecentViewsUpdated( void _onRecentViewsUpdated() =>
FlowyResult<RepeatedViewIdPB, FlowyError> result, add(const RecentViewsEvent.fetchRecentViews());
) {
add(const RecentViewsEvent.fetchRecentViews());
}
} }
@freezed @freezed
@ -74,7 +62,5 @@ class RecentViewsState with _$RecentViewsState {
required List<ViewPB> views, required List<ViewPB> views,
}) = _RecentViewsState; }) = _RecentViewsState;
factory RecentViewsState.initial() => const RecentViewsState( factory RecentViewsState.initial() => const RecentViewsState(views: []);
views: [],
);
} }

View File

@ -1,12 +1,14 @@
import 'package:flutter/foundation.dart';
import 'package:appflowy/plugins/util.dart'; import 'package:appflowy/plugins/util.dart';
import 'package:appflowy/startup/plugin/plugin.dart'; import 'package:appflowy/startup/plugin/plugin.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart'; import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/presentation/home/home_stack.dart'; import 'package:appflowy/workspace/presentation/home/home_stack.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart'; import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
part 'tabs_bloc.freezed.dart'; part 'tabs_bloc.freezed.dart';
@ -81,11 +83,15 @@ class TabsBloc extends Bloc<TabsEvent, TabsState> {
void openPlugin( void openPlugin(
ViewPB view, { ViewPB view, {
Map<String, dynamic> arguments = const {}, Map<String, dynamic> arguments = const {},
}) => }) {
add( add(
TabsEvent.openPlugin( TabsEvent.openPlugin(
plugin: view.plugin(arguments: arguments), plugin: view.plugin(arguments: arguments),
view: view, view: view,
), ),
); );
// Update recent views
getIt<CachedRecentService>().updateRecentViews([view.id], true);
}
} }

View File

@ -4,7 +4,7 @@ import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/config/kv_keys.dart'; import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/favorite/favorite_listener.dart'; import 'package:appflowy/workspace/application/favorite/favorite_listener.dart';
import 'package:appflowy/workspace/application/recent/recent_service.dart'; import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
import 'package:appflowy/workspace/application/view/view_listener.dart'; import 'package:appflowy/workspace/application/view/view_listener.dart';
import 'package:appflowy/workspace/application/view/view_service.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-error/errors.pb.dart';
@ -88,9 +88,7 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
await _setViewIsExpanded(view, e.isExpanded); await _setViewIsExpanded(view, e.isExpanded);
}, },
viewDidUpdate: (e) async { viewDidUpdate: (e) async {
final result = await ViewBackendService.getView( final result = await ViewBackendService.getView(view.id);
view.id,
);
final view_ = result.fold((l) => l, (r) => null); final view_ = result.fold((l) => l, (r) => null);
e.result.fold( e.result.fold(
(view) async { (view) async {
@ -146,7 +144,10 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
), ),
), ),
); );
await RecentService().updateRecentViews([view.id], false); await getIt<CachedRecentService>().updateRecentViews(
[view.id],
false,
);
}, },
duplicate: (e) async { duplicate: (e) async {
final result = await ViewBackendService.duplicate(view: view); final result = await ViewBackendService.duplicate(view: view);
@ -313,9 +314,7 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
} }
if (update.updateChildViews.isNotEmpty) { if (update.updateChildViews.isNotEmpty) {
final view = await ViewBackendService.getView( final view = await ViewBackendService.getView(update.parentViewId);
update.parentViewId,
);
final childViews = view.fold((l) => l.childViews, (r) => []); final childViews = view.fold((l) => l.childViews, (r) => []);
bool isSameOrder = true; bool isSameOrder = true;
if (childViews.length == update.updateChildViews.length) { if (childViews.length == update.updateChildViews.length) {

View File

@ -99,9 +99,7 @@ class ViewBackendService {
layoutType: layoutType, layoutType: layoutType,
parentViewId: parentViewId, parentViewId: parentViewId,
name: name, name: name,
ext: { ext: {'database_id': databaseId},
'database_id': databaseId,
},
); );
} }
@ -215,49 +213,13 @@ class ViewBackendService {
return FolderEventMoveNestedView(payload).send(); return FolderEventMoveNestedView(payload).send();
} }
Future<List<ViewPB>> fetchViewsWithLayoutType( /// Fetches a flattened list of all Views.
ViewLayoutPB? layoutType, ///
) async { /// Views do not contain their children in this list, as they all exist
final views = await fetchViews(); /// in the same level in this version.
if (layoutType == null) { ///
return views; static Future<FlowyResult<RepeatedViewPB, FlowyError>> getAllViews() async {
} return FolderEventGetAllViews().send();
return views
.where(
(element) => layoutType == element.layout,
)
.toList();
}
Future<List<ViewPB>> fetchViews() async {
final result = <ViewPB>[];
return FolderEventReadCurrentWorkspace().send().then((value) async {
final workspace = value.toNullable();
if (workspace != null) {
final views = workspace.views;
for (final view in views) {
result.add(view);
final childViews = await getAllViews(view);
result.addAll(childViews);
}
}
return result;
});
}
Future<List<ViewPB>> getAllViews(ViewPB view) async {
final result = <ViewPB>[];
final childViews = await getChildViews(viewId: view.id).then(
(value) => value.toNullable(),
);
if (childViews != null && childViews.isNotEmpty) {
result.addAll(childViews);
final views = await Future.wait(
childViews.map((e) async => getAllViews(e)),
);
result.addAll(views.expand((element) => element));
}
return result;
} }
static Future<FlowyResult<ViewPB, FlowyError>> getView( static Future<FlowyResult<ViewPB, FlowyError>> getView(

View File

@ -61,7 +61,6 @@ class _CommandPaletteController extends StatefulWidget {
} }
class _CommandPaletteControllerState extends State<_CommandPaletteController> { class _CommandPaletteControllerState extends State<_CommandPaletteController> {
late final CommandPaletteBloc _commandPaletteBloc;
late ValueNotifier<bool> _toggleNotifier = widget.toggleNotifier; late ValueNotifier<bool> _toggleNotifier = widget.toggleNotifier;
bool _isOpen = false; bool _isOpen = false;
@ -86,31 +85,28 @@ class _CommandPaletteControllerState extends State<_CommandPaletteController> {
void initState() { void initState() {
super.initState(); super.initState();
_toggleNotifier.addListener(_onToggle); _toggleNotifier.addListener(_onToggle);
_commandPaletteBloc = CommandPaletteBloc();
} }
@override @override
void dispose() { void dispose() {
_toggleNotifier.removeListener(_onToggle); _toggleNotifier.removeListener(_onToggle);
_toggleNotifier.dispose();
_commandPaletteBloc.close();
super.dispose(); super.dispose();
} }
void _onToggle() { void _onToggle() {
if (widget.toggleNotifier.value && !_isOpen) { if (_toggleNotifier.value && !_isOpen) {
_isOpen = true; _isOpen = true;
FlowyOverlay.show( FlowyOverlay.show(
context: context, context: context,
builder: (_) => BlocProvider.value( builder: (_) => BlocProvider.value(
value: _commandPaletteBloc, value: context.read<CommandPaletteBloc>(),
child: CommandPaletteModal(shortcutBuilder: _buildShortcut), child: CommandPaletteModal(shortcutBuilder: _buildShortcut),
), ),
).then((_) { ).then((_) {
_isOpen = false; _isOpen = false;
widget.toggleNotifier.value = false; _toggleNotifier.value = false;
}); });
} else if (!widget.toggleNotifier.value && _isOpen) { } else if (!_toggleNotifier.value && _isOpen) {
FlowyOverlay.pop(context); FlowyOverlay.pop(context);
_isOpen = false; _isOpen = false;
} }
@ -148,52 +144,48 @@ class CommandPaletteModal extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<CommandPaletteBloc, CommandPaletteState>( return BlocBuilder<CommandPaletteBloc, CommandPaletteState>(
builder: (context, state) { builder: (context, state) => FlowyDialog(
return FlowyDialog( alignment: Alignment.topCenter,
alignment: Alignment.topCenter, insetPadding: const EdgeInsets.only(top: 100),
insetPadding: const EdgeInsets.only(top: 100), constraints: const BoxConstraints(maxHeight: 420, maxWidth: 510),
constraints: const BoxConstraints(maxHeight: 420, maxWidth: 510), expandHeight: false,
expandHeight: false, child: shortcutBuilder(
child: shortcutBuilder( Column(
Column( mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, children: [
children: [ SearchField(query: state.query, isLoading: state.isLoading),
SearchField(query: state.query, isLoading: state.isLoading), if ((state.query?.isEmpty ?? true) ||
if ((state.query?.isEmpty ?? true) || state.isLoading && state.results.isEmpty) ...[
state.isLoading && state.results.isEmpty) ...[ const Divider(height: 0),
const Divider(height: 0), Flexible(
Flexible( child: RecentViewsList(
child: RecentViewsList( onSelected: () => FlowyOverlay.pop(context),
onSelected: () => FlowyOverlay.pop(context),
),
), ),
],
if (state.results.isNotEmpty) ...[
const Divider(height: 0),
Flexible(
child: SearchResultsList(
trash: state.trash,
results: state.results,
),
),
],
_CommandPaletteFooter(
shouldShow: state.results.isNotEmpty &&
(state.query?.isNotEmpty ?? false),
), ),
], ],
), if (state.results.isNotEmpty) ...[
const Divider(height: 0),
Flexible(
child: SearchResultsList(
trash: state.trash,
results: state.results,
),
),
],
_CommandPaletteFooter(
shouldShow: state.results.isNotEmpty &&
(state.query?.isNotEmpty ?? false),
),
],
), ),
); ),
}, ),
); );
} }
} }
class _CommandPaletteFooter extends StatelessWidget { class _CommandPaletteFooter extends StatelessWidget {
const _CommandPaletteFooter({ const _CommandPaletteFooter({required this.shouldShow});
required this.shouldShow,
});
final bool shouldShow; final bool shouldShow;
@ -204,38 +196,22 @@ class _CommandPaletteFooter extends StatelessWidget {
} }
return Container( return Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
horizontal: 16,
vertical: 4,
),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(top: BorderSide(color: Theme.of(context).dividerColor)),
top: BorderSide(
color: Theme.of(context).dividerColor,
),
),
), ),
child: Row( child: Row(
children: [ children: [
Container( Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 1),
horizontal: 5,
vertical: 1,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AFThemeExtension.of(context).lightGreyHover, color: AFThemeExtension.of(context).lightGreyHover,
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
), ),
child: const FlowyText.semibold( child: const FlowyText.semibold('TAB', fontSize: 10),
'TAB',
fontSize: 10,
),
), ),
const HSpace(4), const HSpace(4),
FlowyText( FlowyText(LocaleKeys.commandPalette_navigateHint.tr(), fontSize: 11),
LocaleKeys.commandPalette_navigateHint.tr(),
fontSize: 11,
),
], ],
), ),
); );

View File

@ -5,7 +5,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart'; import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart';
import 'package:appflowy/workspace/application/action_navigation/navigation_action.dart'; import 'package:appflowy/workspace/application/action_navigation/navigation_action.dart';
import 'package:appflowy/workspace/application/command_palette/search_result_ext.dart'; import 'package:appflowy/workspace/application/command_palette/search_result_ext.dart';
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-search/result.pb.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/presentation/command_palette/widgets/search_result_tile.dart'; import 'package:appflowy/workspace/presentation/command_palette/widgets/search_result_tile.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/trash.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/trash.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-search/result.pb.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';

View File

@ -6,12 +6,12 @@ import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart'; import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart'; import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/home/home_bloc.dart'; import 'package:appflowy/workspace/application/home/home_bloc.dart';
import 'package:appflowy/workspace/application/home/home_service.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart'; import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart'; import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart'; import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart'; import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy/workspace/presentation/home/errors/workspace_failed_screen.dart'; import 'package:appflowy/workspace/presentation/home/errors/workspace_failed_screen.dart';
import 'package:appflowy/workspace/presentation/home/hotkeys.dart'; import 'package:appflowy/workspace/presentation/home/hotkeys.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar.dart';
@ -298,8 +298,8 @@ class DesktopHomeScreenStackAdaptor extends HomeStackDelegate {
@override @override
void didDeleteStackWidget(ViewPB view, int? index) { void didDeleteStackWidget(ViewPB view, int? index) {
HomeService.readApp(appId: view.parentViewId).then((result) { ViewBackendService.getView(view.parentViewId).then(
result.fold( (result) => result.fold(
(parentView) { (parentView) {
final List<ViewPB> views = parentView.childViews; final List<ViewPB> views = parentView.childViews;
if (views.isNotEmpty) { if (views.isNotEmpty) {
@ -316,7 +316,7 @@ class DesktopHomeScreenStackAdaptor extends HomeStackDelegate {
.add(TabsEvent.openPlugin(plugin: BlankPagePlugin())); .add(TabsEvent.openPlugin(plugin: BlankPagePlugin()));
}, },
(err) => Log.error(err), (err) => Log.error(err),
); ),
}); );
} }
} }

View File

@ -1,14 +1,22 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart'; import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart';
import 'package:appflowy/workspace/application/action_navigation/navigation_action.dart'; import 'package:appflowy/workspace/application/action_navigation/navigation_action.dart';
import 'package:appflowy/workspace/application/command_palette/command_palette_bloc.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart'; import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/favorite/prelude.dart'; import 'package:appflowy/workspace/application/favorite/prelude.dart';
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart'; import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
import 'package:appflowy/workspace/application/recent/cached_recent_service.dart';
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart'; import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart'; import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart'; import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy/workspace/presentation/command_palette/command_palette.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_folder.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_folder.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_new_page_button.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_top_menu.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_top_menu.dart';
@ -19,8 +27,10 @@ import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart' import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
show UserProfilePB; show UserProfilePB;
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
/// Home Sidebar is the left side bar of the home page. /// Home Sidebar is the left side bar of the home page.
@ -58,7 +68,23 @@ class HomeSideBar extends StatelessWidget {
// +-- Public Or Private Section: control the sections of the workspace // +-- Public Or Private Section: control the sections of the workspace
// | // |
// +-- Trash Section // +-- Trash Section
return BlocBuilder<UserWorkspaceBloc, UserWorkspaceState>( return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
listenWhen: (previous, current) =>
previous.currentWorkspace?.workspaceId !=
current.currentWorkspace?.workspaceId,
listener: (context, state) {
if (FeatureFlag.search.isOn) {
// Notify command palette that workspace has changed
context.read<CommandPaletteBloc>().add(
CommandPaletteEvent.workspaceChanged(
workspaceId: state.currentWorkspace?.workspaceId,
),
);
}
// Re-initialize workspace-specific services
getIt<CachedRecentService>().reset();
},
// Rebuild the whole sidebar when the current workspace changes // Rebuild the whole sidebar when the current workspace changes
buildWhen: (previous, current) => buildWhen: (previous, current) =>
previous.currentWorkspace?.workspaceId != previous.currentWorkspace?.workspaceId !=
@ -130,11 +156,9 @@ class HomeSideBar extends StatelessWidget {
) { ) {
final action = state.action; final action = state.action;
if (action?.type == ActionType.openView) { if (action?.type == ActionType.openView) {
final view = state.views.findView(action!.objectId); final view = action!.arguments?[ActionArgumentKeys.view];
if (view != null) { if (view != null) {
final Map<String, dynamic> arguments = {}; final Map<String, dynamic> arguments = {};
final nodePath = action.arguments?[ActionArgumentKeys.nodePath]; final nodePath = action.arguments?[ActionArgumentKeys.nodePath];
if (nodePath != null) { if (nodePath != null) {
arguments[PluginArgumentKeys.selection] = Selection.collapsed( arguments[PluginArgumentKeys.selection] = Selection.collapsed(
@ -186,6 +210,7 @@ class _SidebarState extends State<_Sidebar> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
const menuHorizontalInset = EdgeInsets.symmetric(horizontal: 12); const menuHorizontalInset = EdgeInsets.symmetric(horizontal: 12);
final userState = context.read<UserWorkspaceBloc>().state;
return DecoratedBox( return DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceVariant, color: Theme.of(context).colorScheme.surfaceVariant,
@ -206,21 +231,17 @@ class _SidebarState extends State<_Sidebar> {
padding: menuHorizontalInset, padding: menuHorizontalInset,
child: child:
// if the workspaces are empty, show the user profile instead // if the workspaces are empty, show the user profile instead
context.read<UserWorkspaceBloc>().state.isCollabWorkspaceOn && userState.isCollabWorkspaceOn && userState.workspaces.isNotEmpty
context ? SidebarWorkspace(userProfile: widget.userProfile)
.read<UserWorkspaceBloc>() : SidebarUser(userProfile: widget.userProfile),
.state
.workspaces
.isNotEmpty
? SidebarWorkspace(
userProfile: widget.userProfile,
)
: SidebarUser(
userProfile: widget.userProfile,
),
), ),
if (FeatureFlag.search.isOn) ...[
const VSpace(20), const VSpace(8),
const Padding(
padding: menuHorizontalInset,
child: _SidebarSearchButton(),
),
],
// scrollable document list // scrollable document list
Expanded( Expanded(
child: Padding( child: Padding(
@ -263,3 +284,16 @@ class _SidebarState extends State<_Sidebar> {
} }
} }
} }
class _SidebarSearchButton extends StatelessWidget {
const _SidebarSearchButton();
@override
Widget build(BuildContext context) {
return FlowyButton(
onTap: () => CommandPalette.of(context).toggle(),
leftIcon: const FlowySvg(FlowySvgs.search_s),
text: FlowyText(LocaleKeys.search_label.tr()),
);
}
}

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.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/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
@ -14,7 +16,6 @@ import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class SidebarWorkspace extends StatefulWidget { class SidebarWorkspace extends StatefulWidget {
@ -147,7 +148,7 @@ class _SidebarWorkspaceState extends State<SidebarWorkspace> {
} }
} }
class SidebarSwitchWorkspaceButton extends StatefulWidget { class SidebarSwitchWorkspaceButton extends StatelessWidget {
const SidebarSwitchWorkspaceButton({ const SidebarSwitchWorkspaceButton({
super.key, super.key,
required this.userProfile, required this.userProfile,
@ -157,26 +158,15 @@ class SidebarSwitchWorkspaceButton extends StatefulWidget {
final UserWorkspacePB currentWorkspace; final UserWorkspacePB currentWorkspace;
final UserProfilePB userProfile; final UserProfilePB userProfile;
@override
State<SidebarSwitchWorkspaceButton> createState() =>
_SidebarSwitchWorkspaceButtonState();
}
class _SidebarSwitchWorkspaceButtonState
extends State<SidebarSwitchWorkspaceButton> {
final controller = PopoverController();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AppFlowyPopover( return AppFlowyPopover(
direction: PopoverDirection.bottomWithCenterAligned, direction: PopoverDirection.bottomWithCenterAligned,
offset: const Offset(0, 10), offset: const Offset(0, 10),
constraints: const BoxConstraints(maxWidth: 260, maxHeight: 600), constraints: const BoxConstraints(maxWidth: 260, maxHeight: 600),
onOpen: () { onOpen: () => context
context.read<UserWorkspaceBloc>().add( .read<UserWorkspaceBloc>()
const UserWorkspaceEvent.fetchWorkspaces(), .add(const UserWorkspaceEvent.fetchWorkspaces()),
);
},
popupBuilder: (_) { popupBuilder: (_) {
return BlocProvider<UserWorkspaceBloc>.value( return BlocProvider<UserWorkspaceBloc>.value(
value: context.read<UserWorkspaceBloc>(), value: context.read<UserWorkspaceBloc>(),
@ -188,7 +178,7 @@ class _SidebarSwitchWorkspaceButtonState
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return WorkspacesMenu( return WorkspacesMenu(
userProfile: widget.userProfile, userProfile: userProfile,
currentWorkspace: currentWorkspace, currentWorkspace: currentWorkspace,
workspaces: workspaces, workspaces: workspaces,
); );
@ -197,8 +187,6 @@ class _SidebarSwitchWorkspaceButtonState
); );
}, },
child: FlowyButton( child: FlowyButton(
onTap: () => controller.show(),
useIntrinsicWidth: true,
margin: const EdgeInsets.symmetric(vertical: 8), margin: const EdgeInsets.symmetric(vertical: 8),
text: Row( text: Row(
children: [ children: [
@ -206,7 +194,7 @@ class _SidebarSwitchWorkspaceButtonState
SizedBox.square( SizedBox.square(
dimension: 30.0, dimension: 30.0,
child: WorkspaceIcon( child: WorkspaceIcon(
workspace: widget.currentWorkspace, workspace: currentWorkspace,
iconSize: 20, iconSize: 20,
enableEdit: false, enableEdit: false,
), ),
@ -214,7 +202,7 @@ class _SidebarSwitchWorkspaceButtonState
const HSpace(6), const HSpace(6),
Expanded( Expanded(
child: FlowyText.medium( child: FlowyText.medium(
widget.currentWorkspace.name, currentWorkspace.name,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
withTooltip: true, withTooltip: true,
), ),

View File

@ -14,6 +14,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-search/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_result/appflowy_result.dart'; import 'package:appflowy_result/appflowy_result.dart';
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
@ -25,8 +26,6 @@ import '../protobuf/flowy-config/entities.pb.dart';
import '../protobuf/flowy-config/event_map.pb.dart'; import '../protobuf/flowy-config/event_map.pb.dart';
import '../protobuf/flowy-date/entities.pb.dart'; import '../protobuf/flowy-date/entities.pb.dart';
import '../protobuf/flowy-date/event_map.pb.dart'; import '../protobuf/flowy-date/event_map.pb.dart';
import '../protobuf/flowy-search/entities.pb.dart';
import '../protobuf/flowy-search/event_map.pb.dart';
import 'error.dart'; import 'error.dart';

View File

@ -75,14 +75,14 @@ void main() {
..add(const ViewEvent.initial()); ..add(const ViewEvent.initial());
await blocResponseFuture(); await blocResponseFuture();
deleteViewBloc.add(const ViewEvent.delete()); deleteViewBloc.add(const ViewEvent.delete());
await blocResponseFuture(); await blocResponseFuture(millisecond: 1000);
assert(context.viewBloc.state.view.childViews.length == 2); assert(context.viewBloc.state.view.childViews.length == 2);
assert(trashBloc.state.objects.length == 1); assert(trashBloc.state.objects.length == 1);
assert(trashBloc.state.objects.first.id == deletedView.id); assert(trashBloc.state.objects.first.id == deletedView.id);
// put back // put back
trashBloc.add(TrashEvent.putback(deletedView.id)); trashBloc.add(TrashEvent.putback(deletedView.id));
await blocResponseFuture(); await blocResponseFuture(millisecond: 1000);
assert(context.viewBloc.state.view.childViews.length == 3); assert(context.viewBloc.state.view.childViews.length == 3);
assert(trashBloc.state.objects.isEmpty); assert(trashBloc.state.objects.isEmpty);
@ -92,8 +92,7 @@ void main() {
..add(const ViewEvent.initial()); ..add(const ViewEvent.initial());
await blocResponseFuture(); await blocResponseFuture();
deleteViewBloc.add(const ViewEvent.delete()); deleteViewBloc.add(const ViewEvent.delete());
await blocResponseFuture(); await blocResponseFuture(millisecond: 1000);
await blocResponseFuture();
} }
expect(trashBloc.state.objects[0].id, context.allViews[0].id); expect(trashBloc.state.objects[0].id, context.allViews[0].id);
expect(trashBloc.state.objects[1].id, context.allViews[1].id); expect(trashBloc.state.objects[1].id, context.allViews[1].id);
@ -101,12 +100,12 @@ void main() {
// delete a view permanently // delete a view permanently
trashBloc.add(TrashEvent.delete(trashBloc.state.objects[0])); trashBloc.add(TrashEvent.delete(trashBloc.state.objects[0]));
await blocResponseFuture(); await blocResponseFuture(millisecond: 1000);
expect(trashBloc.state.objects.length, 2); expect(trashBloc.state.objects.length, 2);
// delete all view permanently // delete all view permanently
trashBloc.add(const TrashEvent.deleteAll()); trashBloc.add(const TrashEvent.deleteAll());
await blocResponseFuture(); await blocResponseFuture(millisecond: 1000);
assert( assert(
trashBloc.state.objects.isEmpty, trashBloc.state.objects.isEmpty,
"but receive ${trashBloc.state.objects.length}", "but receive ${trashBloc.state.objects.length}",

View File

@ -49,7 +49,7 @@ void main() {
const ViewEvent.initial(), const ViewEvent.initial(),
); );
childViewBloc.add(const ViewEvent.duplicate()); childViewBloc.add(const ViewEvent.duplicate());
await blocResponseFuture(); await blocResponseFuture(millisecond: 1000);
expect(viewBloc.state.view.childViews.length, 2); expect(viewBloc.state.view.childViews.length, 2);
}); });
@ -220,7 +220,7 @@ void main() {
section: ViewSectionPB.Public, section: ViewSectionPB.Public,
), ),
); );
await blocResponseFuture(); await blocResponseFuture(millisecond: 1000);
expect(viewBloc.state.view.childViews.length, i + 1); expect(viewBloc.state.view.childViews.length, i + 1);
expect(viewBloc.state.view.childViews.last.name, 'Test $layout'); expect(viewBloc.state.view.childViews.last.name, 'Test $layout');
expect(viewBloc.state.view.childViews.last.layout, layout); expect(viewBloc.state.view.childViews.last.layout, layout);

View File

@ -134,9 +134,9 @@ dependencies = [
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.18" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]] [[package]]
name = "android-tzdata" name = "android-tzdata"
@ -162,7 +162,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]] [[package]]
name = "app-error" name = "app-error"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -191,6 +191,7 @@ dependencies = [
"flowy-document", "flowy-document",
"flowy-error", "flowy-error",
"flowy-notification", "flowy-notification",
"flowy-search",
"flowy-user", "flowy-user",
"lib-dispatch", "lib-dispatch",
"serde", "serde",
@ -205,9 +206,9 @@ dependencies = [
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
version = "1.7.1" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
@ -739,7 +740,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"again", "again",
"anyhow", "anyhow",
@ -785,7 +786,7 @@ dependencies = [
[[package]] [[package]]
name = "client-websocket" name = "client-websocket"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
@ -859,7 +860,7 @@ dependencies = [
[[package]] [[package]]
name = "collab" name = "collab"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -883,7 +884,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-database" name = "collab-database"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -913,7 +914,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-document" name = "collab-document"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -932,7 +933,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-entity" name = "collab-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -947,7 +948,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-folder" name = "collab-folder"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@ -985,7 +986,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-plugins" name = "collab-plugins"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
@ -1024,7 +1025,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-entity" name = "collab-rt-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1049,7 +1050,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-protocol" name = "collab-rt-protocol"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1063,7 +1064,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-user" name = "collab-user"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -1403,7 +1404,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -1583,9 +1584,9 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]] [[package]]
name = "downcast-rs" name = "downcast-rs"
version = "1.2.1" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]] [[package]]
name = "dtoa" name = "dtoa"
@ -1721,9 +1722,9 @@ dependencies = [
[[package]] [[package]]
name = "fastdivide" name = "fastdivide"
version = "0.4.1" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59668941c55e5c186b8b58c391629af56774ec768f73c08bbcd56f09348eb00b" checksum = "25c7df09945d65ea8d70b3321547ed414bbc540aad5bac6883d021b970f35b04"
[[package]] [[package]]
name = "fastrand" name = "fastrand"
@ -2134,8 +2135,8 @@ dependencies = [
"protobuf", "protobuf",
"serde", "serde",
"serde_json", "serde_json",
"strsim 0.11.1", "strsim 0.11.0",
"strum_macros 0.26.2", "strum_macros 0.26.1",
"tantivy", "tantivy",
"tempfile", "tempfile",
"tokio", "tokio",
@ -2769,7 +2770,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -2786,7 +2787,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -3218,7 +3219,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -3493,9 +3494,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -3608,9 +3609,9 @@ dependencies = [
[[package]] [[package]]
name = "lz4_flex" name = "lz4_flex"
version = "0.11.3" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15"
[[package]] [[package]]
name = "mac" name = "mac"
@ -3838,9 +3839,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]] [[package]]
name = "murmurhash32" name = "murmurhash32"
version = "0.3.1" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" checksum = "d9380db4c04d219ac5c51d14996bbf2c2e9a15229771b53f8671eb6c83cf44df"
[[package]] [[package]]
name = "nanoid" name = "nanoid"
@ -4721,7 +4722,7 @@ checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2"
dependencies = [ dependencies = [
"bytes", "bytes",
"heck 0.4.1", "heck 0.4.1",
"itertools 0.10.5", "itertools 0.11.0",
"log", "log",
"multimap", "multimap",
"once_cell", "once_cell",
@ -4742,7 +4743,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"itertools 0.10.5", "itertools 0.11.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.47", "syn 2.0.47",
@ -5046,6 +5047,15 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.4.3" version = "0.4.3"
@ -5285,9 +5295,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.33" version = "0.38.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3cc72858054fcff6d7dea32df2aeaee6a7c24227366d7ea429aada2f26b16ad" checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.0",
"errno", "errno",
@ -5697,7 +5707,7 @@ dependencies = [
[[package]] [[package]]
name = "shared-entity" name = "shared-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -5915,9 +5925,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]] [[package]]
name = "strum" name = "strum"
@ -5952,9 +5962,9 @@ dependencies = [
[[package]] [[package]]
name = "strum_macros" name = "strum_macros"
version = "0.26.2" version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18"
dependencies = [ dependencies = [
"heck 0.4.1", "heck 0.4.1",
"proc-macro2", "proc-macro2",
@ -6486,12 +6496,13 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.10.1" version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
"redox_syscall 0.4.1",
"rustix", "rustix",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]

View File

@ -60,6 +60,7 @@ flowy-error = { path = "../../rust-lib/flowy-error", features = [
"impl_from_serde", "impl_from_serde",
"tauri_ts", "tauri_ts",
] } ] }
flowy-search = { path = "../../rust-lib/flowy-search", features = ["tauri_ts"] }
flowy-document = { path = "../../rust-lib/flowy-document", features = [ flowy-document = { path = "../../rust-lib/flowy-document", features = [
"tauri_ts", "tauri_ts",
] } ] }
@ -87,7 +88,7 @@ yrs = { git = "https://github.com/appflowy/y-crdt", rev = "3f25bb510ca5274e7657d
# Run the script: # Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ca70c426311fc6fb87ecccfa66e3927b36e96795" } client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "1019b8c5b6ffb548253dc2c7819afb84d242ab7b" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #
@ -97,10 +98,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ca7
# To switch to the local path, run: # To switch to the local path, run:
# scripts/tool/update_collab_source.sh # scripts/tool/update_collab_source.sh
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }

View File

@ -1,2 +1,2 @@
[toolchain] [toolchain]
channel = "1.75" channel = "1.77.2"

View File

@ -215,7 +215,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]] [[package]]
name = "app-error" name = "app-error"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -541,7 +541,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"again", "again",
"anyhow", "anyhow",
@ -587,7 +587,7 @@ dependencies = [
[[package]] [[package]]
name = "client-websocket" name = "client-websocket"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
@ -631,7 +631,7 @@ dependencies = [
[[package]] [[package]]
name = "collab" name = "collab"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -655,7 +655,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-document" name = "collab-document"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -674,7 +674,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-entity" name = "collab-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -689,7 +689,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-folder" name = "collab-folder"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@ -727,7 +727,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-plugins" name = "collab-plugins"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
@ -765,7 +765,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-entity" name = "collab-rt-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -790,7 +790,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-protocol" name = "collab-rt-protocol"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -804,7 +804,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-user" name = "collab-user"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -1001,7 +1001,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -1774,7 +1774,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -1791,7 +1791,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -2092,7 +2092,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -3732,7 +3732,7 @@ dependencies = [
[[package]] [[package]]
name = "shared-entity" name = "shared-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -4994,4 +4994,4 @@ dependencies = [
[[patch.unused]] [[patch.unused]]
name = "collab-database" name = "collab-database"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"

View File

@ -55,7 +55,7 @@ codegen-units = 1
# Run the script: # Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ca70c426311fc6fb87ecccfa66e3927b36e96795" } client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "1019b8c5b6ffb548253dc2c7819afb84d242ab7b" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #
@ -65,10 +65,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ca7
# To switch to the local path, run: # To switch to the local path, run:
# scripts/tool/update_collab_source.sh # scripts/tool/update_collab_source.sh
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }

View File

@ -1,2 +1,2 @@
[toolchain] [toolchain]
channel = "1.75" channel = "1.77.2"

View File

@ -153,7 +153,7 @@ checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
[[package]] [[package]]
name = "app-error" name = "app-error"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -714,7 +714,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"again", "again",
"anyhow", "anyhow",
@ -760,7 +760,7 @@ dependencies = [
[[package]] [[package]]
name = "client-websocket" name = "client-websocket"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
@ -843,7 +843,7 @@ dependencies = [
[[package]] [[package]]
name = "collab" name = "collab"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -867,7 +867,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-database" name = "collab-database"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -897,7 +897,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-document" name = "collab-document"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -916,7 +916,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-entity" name = "collab-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -931,7 +931,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-folder" name = "collab-folder"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@ -969,7 +969,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-plugins" name = "collab-plugins"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
@ -1008,7 +1008,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-entity" name = "collab-rt-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1033,7 +1033,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-protocol" name = "collab-rt-protocol"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -1047,7 +1047,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-user" name = "collab-user"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -1280,7 +1280,7 @@ dependencies = [
"cssparser-macros", "cssparser-macros",
"dtoa-short", "dtoa-short",
"itoa 1.0.10", "itoa 1.0.10",
"phf 0.8.0", "phf 0.11.2",
"smallvec", "smallvec",
] ]
@ -1391,7 +1391,7 @@ checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -2844,7 +2844,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -2861,7 +2861,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -3298,7 +3298,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -4803,7 +4803,7 @@ checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2"
dependencies = [ dependencies = [
"bytes", "bytes",
"heck 0.4.1", "heck 0.4.1",
"itertools 0.11.0", "itertools 0.10.5",
"log", "log",
"multimap", "multimap",
"once_cell", "once_cell",
@ -4824,7 +4824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"itertools 0.11.0", "itertools 0.10.5",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.55", "syn 2.0.55",
@ -5802,7 +5802,7 @@ dependencies = [
[[package]] [[package]]
name = "shared-entity" name = "shared-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",

View File

@ -87,7 +87,7 @@ yrs = { git = "https://github.com/appflowy/y-crdt", rev = "3f25bb510ca5274e7657d
# Run the script: # Run the script:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ca70c426311fc6fb87ecccfa66e3927b36e96795" } client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "1019b8c5b6ffb548253dc2c7819afb84d242ab7b" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #
@ -97,10 +97,10 @@ client-api = { git = "https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ca7
# To switch to the local path, run: # To switch to the local path, run:
# scripts/tool/update_collab_source.sh # scripts/tool/update_collab_source.sh
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }

View File

@ -1,2 +1,2 @@
[toolchain] [toolchain]
channel = "1.75" channel = "1.77.2"

View File

@ -1193,6 +1193,7 @@
}, },
"inlineActions": { "inlineActions": {
"noResults": "No results", "noResults": "No results",
"recentPages": "Recent pages",
"pageReference": "Page reference", "pageReference": "Page reference",
"docReference": "Document reference", "docReference": "Document reference",
"boardReference": "Board reference", "boardReference": "Board reference",

View File

@ -135,9 +135,9 @@ dependencies = [
[[package]] [[package]]
name = "allocator-api2" name = "allocator-api2"
version = "0.2.18" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]] [[package]]
name = "android-tzdata" name = "android-tzdata"
@ -163,7 +163,7 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]] [[package]]
name = "app-error" name = "app-error"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -182,9 +182,9 @@ dependencies = [
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
version = "1.7.1" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
@ -696,7 +696,7 @@ dependencies = [
[[package]] [[package]]
name = "client-api" name = "client-api"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"again", "again",
"anyhow", "anyhow",
@ -742,7 +742,7 @@ dependencies = [
[[package]] [[package]]
name = "client-websocket" name = "client-websocket"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
@ -785,7 +785,7 @@ dependencies = [
[[package]] [[package]]
name = "collab" name = "collab"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -809,7 +809,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-database" name = "collab-database"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -839,7 +839,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-document" name = "collab-document"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -858,7 +858,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-entity" name = "collab-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -873,7 +873,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-folder" name = "collab-folder"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@ -911,7 +911,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-plugins" name = "collab-plugins"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
@ -950,7 +950,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-entity" name = "collab-rt-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -975,7 +975,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-rt-protocol" name = "collab-rt-protocol"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bincode", "bincode",
@ -989,7 +989,7 @@ dependencies = [
[[package]] [[package]]
name = "collab-user" name = "collab-user"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=5e32057ac8e6939368a8e75df91bcbce2ac143e7#5e32057ac8e6939368a8e75df91bcbce2ac143e7" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=66bc02f87ba73b3f1095424a2ec053c1fac72c36#66bc02f87ba73b3f1095424a2ec053c1fac72c36"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"collab", "collab",
@ -1326,7 +1326,7 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]] [[package]]
name = "database-entity" name = "database-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -1432,6 +1432,12 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95203a6a50906215a502507c0f879a0ce7ff205a6111e2db2a5ef8e4bb92e43" checksum = "d95203a6a50906215a502507c0f879a0ce7ff205a6111e2db2a5ef8e4bb92e43"
[[package]]
name = "deunicode"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94"
[[package]] [[package]]
name = "diesel" name = "diesel"
version = "2.1.4" version = "2.1.4"
@ -1496,9 +1502,9 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]] [[package]]
name = "downcast-rs" name = "downcast-rs"
version = "1.2.1" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]] [[package]]
name = "dtoa" name = "dtoa"
@ -1647,12 +1653,12 @@ dependencies = [
[[package]] [[package]]
name = "fake" name = "fake"
version = "2.8.0" version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9af7b0c58ac9d03169e27f080616ce9f64004edca3d2ef4147a811c21b23b319" checksum = "1c25829bde82205da46e1823b2259db6273379f626fc211f126f65654a2669be"
dependencies = [ dependencies = [
"deunicode 1.4.3",
"rand 0.8.5", "rand 0.8.5",
"unidecode",
] ]
[[package]] [[package]]
@ -1695,15 +1701,15 @@ dependencies = [
[[package]] [[package]]
name = "fastdivide" name = "fastdivide"
version = "0.4.1" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59668941c55e5c186b8b58c391629af56774ec768f73c08bbcd56f09348eb00b" checksum = "25c7df09945d65ea8d70b3321547ed414bbc540aad5bac6883d021b970f35b04"
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.0.2" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]] [[package]]
name = "finl_unicode" name = "finl_unicode"
@ -2102,8 +2108,8 @@ dependencies = [
"protobuf", "protobuf",
"serde", "serde",
"serde_json", "serde_json",
"strsim 0.11.1", "strsim 0.11.0",
"strum_macros 0.26.2", "strum_macros 0.26.1",
"tantivy", "tantivy",
"tempfile", "tempfile",
"tokio", "tokio",
@ -2589,7 +2595,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue" name = "gotrue"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-util", "futures-util",
@ -2606,7 +2612,7 @@ dependencies = [
[[package]] [[package]]
name = "gotrue-entity" name = "gotrue-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -2977,7 +2983,7 @@ dependencies = [
[[package]] [[package]]
name = "infra" name = "infra"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"reqwest", "reqwest",
@ -3156,9 +3162,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -3259,9 +3265,9 @@ dependencies = [
[[package]] [[package]]
name = "lz4_flex" name = "lz4_flex"
version = "0.11.3" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15"
[[package]] [[package]]
name = "mac" name = "mac"
@ -3465,9 +3471,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]] [[package]]
name = "murmurhash32" name = "murmurhash32"
version = "0.3.1" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" checksum = "d9380db4c04d219ac5c51d14996bbf2c2e9a15229771b53f8671eb6c83cf44df"
[[package]] [[package]]
name = "nanoid" name = "nanoid"
@ -4741,9 +4747,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.33" version = "0.38.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3cc72858054fcff6d7dea32df2aeaee6a7c24227366d7ea429aada2f26b16ad" checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.0",
"errno", "errno",
@ -5089,7 +5095,7 @@ dependencies = [
[[package]] [[package]]
name = "shared-entity" name = "shared-entity"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=ca70c426311fc6fb87ecccfa66e3927b36e96795#ca70c426311fc6fb87ecccfa66e3927b36e96795" source = "git+https://github.com/AppFlowy-IO/AppFlowy-Cloud?rev=1019b8c5b6ffb548253dc2c7819afb84d242ab7b#1019b8c5b6ffb548253dc2c7819afb84d242ab7b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"app-error", "app-error",
@ -5180,7 +5186,7 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
dependencies = [ dependencies = [
"deunicode", "deunicode 0.4.4",
] ]
[[package]] [[package]]
@ -5275,9 +5281,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]] [[package]]
name = "strum" name = "strum"
@ -5312,9 +5318,9 @@ dependencies = [
[[package]] [[package]]
name = "strum_macros" name = "strum_macros"
version = "0.26.2" version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18"
dependencies = [ dependencies = [
"heck 0.4.1", "heck 0.4.1",
"proc-macro2", "proc-macro2",
@ -5551,9 +5557,9 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.10.1" version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
@ -6210,12 +6216,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "unidecode"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc"
[[package]] [[package]]
name = "universal-hash" name = "universal-hash"
version = "0.5.1" version = "0.5.1"

View File

@ -81,7 +81,7 @@ chrono = { version = "0.4.31", default-features = false, features = ["clock"] }
yrs = { version = "0.17.2" } yrs = { version = "0.17.2" }
[profile.dev] [profile.dev]
opt-level = 0 opt-level = 1
lto = false lto = false
codegen-units = 16 codegen-units = 16
@ -115,7 +115,7 @@ rocksdb = { git = "https://github.com/LucasXu0/rust-rocksdb", rev = "21cf4a23ec1
# Run the script.add_workspace_members: # Run the script.add_workspace_members:
# scripts/tool/update_client_api_rev.sh new_rev_id # scripts/tool/update_client_api_rev.sh new_rev_id
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
client-api = { git = " https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ca70c426311fc6fb87ecccfa66e3927b36e96795" } client-api = { git = " https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "1019b8c5b6ffb548253dc2c7819afb84d242ab7b" }
# Please use the following script to update collab. # Please use the following script to update collab.
# Working directory: frontend # Working directory: frontend
# #
@ -125,10 +125,10 @@ client-api = { git = " https://github.com/AppFlowy-IO/AppFlowy-Cloud", rev = "ca
# To switch to the local path, run: # To switch to the local path, run:
# scripts/tool/update_collab_source.sh # scripts/tool/update_collab_source.sh
# ⚠️⚠️⚠️️ # ⚠️⚠️⚠️️
collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }
collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "5e32057ac8e6939368a8e75df91bcbce2ac143e7" } collab-entity = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "66bc02f87ba73b3f1095424a2ec053c1fac72c36" }

View File

@ -197,7 +197,7 @@ fn generate_ts_protobuf_files(
.write(true) .write(true)
.append(false) .append(false)
.truncate(true) .truncate(true)
.open(&ts_index) .open(ts_index)
{ {
Ok(ref mut file) => { Ok(ref mut file) => {
let mut export = String::new(); let mut export = String::new();

View File

@ -77,7 +77,7 @@ pub fn gen(dest_folder_name: &str, project: Project) {
.write(true) .write(true)
.append(false) .append(false)
.truncate(true) .truncate(true)
.open(&ts_index) .open(ts_index)
{ {
Ok(ref mut file) => { Ok(ref mut file) => {
let mut export = String::new(); let mut export = String::new();

View File

@ -46,6 +46,7 @@ pub fn save_content_to_file_with_diff_prompt(content: &str, output_file: &str) {
} else { } else {
match OpenOptions::new() match OpenOptions::new()
.create(true) .create(true)
.truncate(true)
.write(true) .write(true)
.open(output_file) .open(output_file)
{ {

View File

@ -8,7 +8,7 @@ edition = "2021"
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies]
collab = { version = "0.1.0" } collab = { version = "0.1.0", features = ["trace_transact"] }
collab-plugins = { version = "0.1.0" } collab-plugins = { version = "0.1.0" }
collab-entity = { version = "0.1.0" } collab-entity = { version = "0.1.0" }
serde.workspace = true serde.workspace = true

View File

@ -177,6 +177,7 @@ pub extern "C" fn link_me_please() {}
#[inline(always)] #[inline(always)]
async fn post_to_flutter(response: AFPluginEventResponse, port: i64) { async fn post_to_flutter(response: AFPluginEventResponse, port: i64) {
let isolate = allo_isolate::Isolate::new(port); let isolate = allo_isolate::Isolate::new(port);
#[allow(clippy::blocks_in_conditions)]
match isolate match isolate
.catch_unwind(async { .catch_unwind(async {
let ffi_resp = FFIResponse::from(response); let ffi_resp = FFIResponse::from(response);

View File

@ -141,7 +141,7 @@ impl EventIntegrationTest {
pub fn get_folder_data(&self) -> FolderData { pub fn get_folder_data(&self) -> FolderData {
let mutex_folder = self.appflowy_core.folder_manager.get_mutex_folder().clone(); let mutex_folder = self.appflowy_core.folder_manager.get_mutex_folder().clone();
let folder_lock_guard = mutex_folder.lock(); let folder_lock_guard = mutex_folder.read();
let folder = folder_lock_guard.as_ref().unwrap(); let folder = folder_lock_guard.as_ref().unwrap();
folder.get_folder_data().clone().unwrap() folder.get_folder_data().clone().unwrap()
} }

View File

@ -1,6 +1,8 @@
mod database; mod database;
mod document; mod document;
mod folder; mod folder;
mod search;
// TODO(Mathias): Enable tests for search
// mod search;
mod user; mod user;
pub mod util; pub mod util;

View File

@ -79,7 +79,7 @@ async fn test_folder_index_create_view() {
// Wait for the index to be updated // Wait for the index to be updated
sleep(Duration::from_millis(500)).await; sleep(Duration::from_millis(500)).await;
let results = folder_search_manager.perform_search(view.name.clone()); let results = folder_search_manager.perform_search(view.name.clone(), None);
if let Err(e) = results { if let Err(e) = results {
panic!("Error performing search: {:?}", e); panic!("Error performing search: {:?}", e);
} }
@ -114,12 +114,12 @@ async fn test_folder_index_rename_view() {
// Wait for the index to be updated // Wait for the index to be updated
sleep(Duration::from_millis(500)).await; sleep(Duration::from_millis(500)).await;
let first = folder_search_manager.perform_search(view.name); let first = folder_search_manager.perform_search(view.name, None);
if let Err(e) = first { if let Err(e) = first {
panic!("Error performing search: {:?}", e); panic!("Error performing search: {:?}", e);
} }
let second = folder_search_manager.perform_search(new_view_name.clone()); let second = folder_search_manager.perform_search(new_view_name.clone(), None);
if let Err(e) = second { if let Err(e) = second {
panic!("Error performing search: {:?}", e); panic!("Error performing search: {:?}", e);
} }

View File

@ -162,9 +162,7 @@ impl AppFlowyCore {
Arc::downgrade(&(server_provider.clone() as Arc<dyn ObjectStorageService>)), Arc::downgrade(&(server_provider.clone() as Arc<dyn ObjectStorageService>)),
); );
let folder_indexer = Arc::new(FolderIndexManagerImpl::new(Arc::downgrade( let folder_indexer = Arc::new(FolderIndexManagerImpl::new(None));
&authenticate_user,
)));
let folder_manager = FolderDepsResolver::resolve( let folder_manager = FolderDepsResolver::resolve(
Arc::downgrade(&authenticate_user), Arc::downgrade(&authenticate_user),
&document_manager, &document_manager,

View File

@ -293,7 +293,7 @@ async fn according_to_select_option_is_filter_test() {
let multi_select_field = test.get_first_field(FieldType::MultiSelect); let multi_select_field = test.get_first_field(FieldType::MultiSelect);
let options = test.get_multi_select_type_option(&multi_select_field.id); let options = test.get_multi_select_type_option(&multi_select_field.id);
let filtering_options = vec![options[1].clone(), options[2].clone()]; let filtering_options = [options[1].clone(), options[2].clone()];
let ids = filtering_options let ids = filtering_options
.iter() .iter()
.map(|option| option.id.clone()) .map(|option| option.id.clone())
@ -346,7 +346,7 @@ async fn according_to_select_option_contains_filter_test() {
let multi_select_field = test.get_first_field(FieldType::MultiSelect); let multi_select_field = test.get_first_field(FieldType::MultiSelect);
let options = test.get_multi_select_type_option(&multi_select_field.id); let options = test.get_multi_select_type_option(&multi_select_field.id);
let filtering_options = vec![options[1].clone(), options[2].clone()]; let filtering_options = [options[1].clone(), options[2].clone()];
let ids = filtering_options let ids = filtering_options
.iter() .iter()
.map(|option| option.id.clone()) .map(|option| option.id.clone())

View File

@ -344,6 +344,7 @@ impl DocumentManager {
// create file if not exist // create file if not exist
let mut file = tokio::fs::OpenOptions::new() let mut file = tokio::fs::OpenOptions::new()
.create(true) .create(true)
.truncate(true)
.write(true) .write(true)
.open(&local_file_path) .open(&local_file_path)
.await?; .await?;

View File

@ -72,6 +72,19 @@ pub fn view_pb_without_child_views(view: View) -> ViewPB {
} }
} }
pub fn view_pb_without_child_views_from_arc(view: Arc<View>) -> ViewPB {
ViewPB {
id: view.id.clone(),
parent_view_id: view.parent_view_id.clone(),
name: view.name.clone(),
create_time: view.created_at,
child_views: Default::default(),
layout: view.layout.clone().into(),
icon: view.icon.clone().map(|icon| icon.into()),
is_favorite: view.is_favorite,
}
}
/// Returns a ViewPB with child views. Only the first level of child views are included. /// Returns a ViewPB with child views. Only the first level of child views are included.
pub fn view_pb_with_child_views(view: Arc<View>, child_views: Vec<Arc<View>>) -> ViewPB { pub fn view_pb_with_child_views(view: Arc<View>, child_views: Vec<Arc<View>>) -> ViewPB {
ViewPB { ViewPB {

View File

@ -138,6 +138,16 @@ pub(crate) async fn get_view_handler(
data_result_ok(view_pb) data_result_ok(view_pb)
} }
#[tracing::instrument(level = "debug", skip(folder), err)]
pub(crate) async fn get_all_views_handler(
folder: AFPluginState<Weak<FolderManager>>,
) -> DataResult<RepeatedViewPB, FlowyError> {
let folder = upgrade_folder(folder)?;
let view_pbs = folder.get_all_views_pb().await?;
data_result_ok(RepeatedViewPB::from(view_pbs))
}
#[tracing::instrument(level = "debug", skip(data, folder), err)] #[tracing::instrument(level = "debug", skip(data, folder), err)]
pub(crate) async fn get_view_ancestors_handler( pub(crate) async fn get_view_ancestors_handler(
data: AFPluginData<ViewIdPB>, data: AFPluginData<ViewIdPB>,

View File

@ -18,6 +18,7 @@ pub fn init(folder: Weak<FolderManager>) -> AFPlugin {
.event(FolderEvent::CreateView, create_view_handler) .event(FolderEvent::CreateView, create_view_handler)
.event(FolderEvent::CreateOrphanView, create_orphan_view_handler) .event(FolderEvent::CreateOrphanView, create_orphan_view_handler)
.event(FolderEvent::GetView, get_view_handler) .event(FolderEvent::GetView, get_view_handler)
.event(FolderEvent::GetAllViews, get_all_views_handler)
.event(FolderEvent::UpdateView, update_view_handler) .event(FolderEvent::UpdateView, update_view_handler)
.event(FolderEvent::DeleteView, delete_view_handler) .event(FolderEvent::DeleteView, delete_view_handler)
.event(FolderEvent::DuplicateView, duplicate_view_handler) .event(FolderEvent::DuplicateView, duplicate_view_handler)
@ -97,6 +98,10 @@ pub enum FolderEvent {
#[event(input = "CreateOrphanViewPayloadPB", output = "ViewPB")] #[event(input = "CreateOrphanViewPayloadPB", output = "ViewPB")]
CreateOrphanView = 16, CreateOrphanView = 16,
/// Return the view info
#[event(output = "RepeatedViewPB")]
GetAllViews = 17,
#[event()] #[event()]
CopyLink = 20, CopyLink = 20,

View File

@ -1,8 +1,9 @@
use crate::entities::icon::UpdateViewIconParams; use crate::entities::icon::UpdateViewIconParams;
use crate::entities::{ use crate::entities::{
view_pb_with_child_views, view_pb_without_child_views, CreateViewParams, CreateWorkspaceParams, view_pb_with_child_views, view_pb_without_child_views, view_pb_without_child_views_from_arc,
DeletedViewPB, FolderSnapshotPB, MoveNestedViewParams, RepeatedTrashPB, RepeatedViewIdPB, CreateViewParams, CreateWorkspaceParams, DeletedViewPB, FolderSnapshotPB, MoveNestedViewParams,
RepeatedViewPB, UpdateViewParams, ViewPB, ViewSectionPB, WorkspacePB, WorkspaceSettingPB, RepeatedTrashPB, RepeatedViewIdPB, RepeatedViewPB, UpdateViewParams, ViewPB, ViewSectionPB,
WorkspacePB, WorkspaceSettingPB,
}; };
use crate::manager_observer::{ use crate::manager_observer::{
notify_child_views_changed, notify_did_update_workspace, notify_parent_view_did_change, notify_child_views_changed, notify_did_update_workspace, notify_parent_view_did_change,
@ -30,11 +31,11 @@ use flowy_folder_pub::cloud::{gen_view_id, FolderCloudService};
use flowy_folder_pub::folder_builder::ParentChildViews; use flowy_folder_pub::folder_builder::ParentChildViews;
use flowy_search_pub::entities::FolderIndexManager; use flowy_search_pub::entities::FolderIndexManager;
use lib_infra::conditional_send_sync_trait; use lib_infra::conditional_send_sync_trait;
use parking_lot::{Mutex, RwLock}; use parking_lot::RwLock;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::ops::Deref; use std::ops::Deref;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use tracing::{error, info, instrument}; use tracing::{error, info, instrument, trace};
conditional_send_sync_trait! { conditional_send_sync_trait! {
"[crate::manager::FolderUser] represents the user for folder."; "[crate::manager::FolderUser] represents the user for folder.";
@ -134,7 +135,7 @@ impl FolderManager {
pub async fn get_current_workspace_public_views(&self) -> FlowyResult<Vec<ViewPB>> { pub async fn get_current_workspace_public_views(&self) -> FlowyResult<Vec<ViewPB>> {
let workspace_id = self let workspace_id = self
.mutex_folder .mutex_folder
.lock() .read()
.as_ref() .as_ref()
.map(|folder| folder.get_workspace_id()); .map(|folder| folder.get_workspace_id());
@ -367,7 +368,7 @@ impl FolderManager {
pub async fn get_workspace_pb(&self) -> FlowyResult<WorkspacePB> { pub async fn get_workspace_pb(&self) -> FlowyResult<WorkspacePB> {
let workspace_pb = { let workspace_pb = {
let guard = self.mutex_folder.lock(); let guard = self.mutex_folder.read();
let folder = guard let folder = guard
.as_ref() .as_ref()
.ok_or(FlowyError::internal().with_context("folder is not initialized"))?; .ok_or(FlowyError::internal().with_context("folder is not initialized"))?;
@ -396,7 +397,7 @@ impl FolderManager {
async fn get_current_workspace_id(&self) -> FlowyResult<String> { async fn get_current_workspace_id(&self) -> FlowyResult<String> {
self self
.mutex_folder .mutex_folder
.lock() .read()
.as_ref() .as_ref()
.map(|folder| folder.get_workspace_id()) .map(|folder| folder.get_workspace_id())
.ok_or(FlowyError::internal().with_context("Unexpected empty workspace id")) .ok_or(FlowyError::internal().with_context("Unexpected empty workspace id"))
@ -409,12 +410,13 @@ impl FolderManager {
/// ///
/// * `none_callback`: A callback function that is invoked when `mutex_folder` contains `None`. /// * `none_callback`: A callback function that is invoked when `mutex_folder` contains `None`.
/// * `f2`: A callback function that is invoked when `mutex_folder` contains a `Some` value. The contained folder is passed as an argument to this callback. /// * `f2`: A callback function that is invoked when `mutex_folder` contains a `Some` value. The contained folder is passed as an argument to this callback.
#[instrument(level = "debug", skip_all)]
fn with_folder<F1, F2, Output>(&self, none_callback: F1, f2: F2) -> Output fn with_folder<F1, F2, Output>(&self, none_callback: F1, f2: F2) -> Output
where where
F1: FnOnce() -> Output, F1: FnOnce() -> Output,
F2: FnOnce(&Folder) -> Output, F2: FnOnce(&Folder) -> Output,
{ {
let folder = self.mutex_folder.lock(); let folder = self.mutex_folder.read();
match &*folder { match &*folder {
None => none_callback(), None => none_callback(),
Some(folder) => f2(folder), Some(folder) => f2(folder),
@ -471,7 +473,7 @@ impl FolderManager {
); );
if let Ok(workspace_id) = self.get_current_workspace_id().await { if let Ok(workspace_id) = self.get_current_workspace_id().await {
let folder = &self.mutex_folder.lock(); let folder = &self.mutex_folder.read();
if let Some(folder) = folder.as_ref() { if let Some(folder) = folder.as_ref() {
notify_did_update_workspace(&workspace_id, folder); notify_did_update_workspace(&workspace_id, folder);
} }
@ -523,8 +525,10 @@ impl FolderManager {
/// again using the ID of the child view you wish to access. /// again using the ID of the child view you wish to access.
#[tracing::instrument(level = "debug", skip(self))] #[tracing::instrument(level = "debug", skip(self))]
pub async fn get_view_pb(&self, view_id: &str) -> FlowyResult<ViewPB> { pub async fn get_view_pb(&self, view_id: &str) -> FlowyResult<ViewPB> {
trace!("Get view pb with id: {}", view_id);
let view_id = view_id.to_string(); let view_id = view_id.to_string();
let folder = self.mutex_folder.lock();
let folder = self.mutex_folder.read();
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?; let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
// trash views and other private views should not be accessed // trash views and other private views should not be accessed
@ -555,6 +559,30 @@ impl FolderManager {
} }
} }
/// Retrieves all views.
///
/// It is important to note that this will return a flat map of all views,
/// excluding all child views themselves, as they are all at the same level in this
/// map.
///
#[tracing::instrument(level = "debug", skip(self))]
pub async fn get_all_views_pb(&self) -> FlowyResult<Vec<ViewPB>> {
let folder = self.mutex_folder.read();
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
// trash views and other private views should not be accessed
let view_ids_should_be_filtered = self.get_view_ids_should_be_filtered(folder);
let all_views = folder.views.get_all_views();
let views = all_views
.into_iter()
.filter(|view| !view_ids_should_be_filtered.contains(&view.id))
.map(view_pb_without_child_views_from_arc)
.collect::<Vec<_>>();
Ok(views)
}
/// Retrieves the ancestors of the view corresponding to the specified view ID, including the view itself. /// Retrieves the ancestors of the view corresponding to the specified view ID, including the view itself.
/// ///
/// For example, if the view hierarchy is as follows: /// For example, if the view hierarchy is as follows:
@ -1063,7 +1091,7 @@ impl FolderManager {
.send(); .send();
if let Ok(workspace_id) = self.get_current_workspace_id().await { if let Ok(workspace_id) = self.get_current_workspace_id().await {
let folder = &self.mutex_folder.lock(); let folder = &self.mutex_folder.read();
if let Some(folder) = folder.as_ref() { if let Some(folder) = folder.as_ref() {
notify_did_update_workspace(&workspace_id, folder); notify_did_update_workspace(&workspace_id, folder);
} }
@ -1318,9 +1346,9 @@ pub(crate) fn get_workspace_private_view_pbs(_workspace_id: &str, folder: &Folde
/// The MutexFolder is a wrapper of the [Folder] that is used to share the folder between different /// The MutexFolder is a wrapper of the [Folder] that is used to share the folder between different
/// threads. /// threads.
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct MutexFolder(Arc<Mutex<Option<Folder>>>); pub struct MutexFolder(Arc<RwLock<Option<Folder>>>);
impl Deref for MutexFolder { impl Deref for MutexFolder {
type Target = Arc<Mutex<Option<Folder>>>; type Target = Arc<RwLock<Option<Folder>>>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0
} }

View File

@ -133,7 +133,7 @@ impl FolderManager {
let index_content_rx = folder.subscribe_index_content(); let index_content_rx = folder.subscribe_index_content();
self self
.folder_indexer .folder_indexer
.set_index_content_receiver(index_content_rx); .set_index_content_receiver(index_content_rx, workspace_id.clone());
// Index all views in the folder if needed // Index all views in the folder if needed
if !self.folder_indexer.is_indexed() { if !self.folder_indexer.is_indexed() {
@ -141,12 +141,13 @@ impl FolderManager {
let folder_indexer = self.folder_indexer.clone(); let folder_indexer = self.folder_indexer.clone();
// We spawn a blocking task to index all views in the folder // We spawn a blocking task to index all views in the folder
let wid = workspace_id.clone();
spawn_blocking(move || { spawn_blocking(move || {
folder_indexer.index_all_views(views); folder_indexer.index_all_views(views, wid);
}); });
} }
*self.mutex_folder.lock() = Some(folder); *self.mutex_folder.write() = Some(folder);
let weak_mutex_folder = Arc::downgrade(&self.mutex_folder); let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
subscribe_folder_sync_state_changed(workspace_id.clone(), folder_state_rx, &weak_mutex_folder); subscribe_folder_sync_state_changed(workspace_id.clone(), folder_state_rx, &weak_mutex_folder);

View File

@ -67,7 +67,7 @@ pub(crate) fn subscribe_folder_snapshot_state_changed(
af_spawn(async move { af_spawn(async move {
if let Some(mutex_folder) = weak_mutex_folder.upgrade() { if let Some(mutex_folder) = weak_mutex_folder.upgrade() {
let stream = mutex_folder let stream = mutex_folder
.lock() .read()
.as_ref() .as_ref()
.map(|folder| folder.subscribe_snapshot_state()); .map(|folder| folder.subscribe_snapshot_state());
if let Some(mut state_stream) = stream { if let Some(mut state_stream) = stream {
@ -119,7 +119,7 @@ pub(crate) fn subscribe_folder_trash_changed(
TrashSectionChange::TrashItemAdded { ids } => ids, TrashSectionChange::TrashItemAdded { ids } => ids,
TrashSectionChange::TrashItemRemoved { ids } => ids, TrashSectionChange::TrashItemRemoved { ids } => ids,
}; };
if let Some(folder) = folder.lock().as_ref() { if let Some(folder) = folder.read().as_ref() {
let views = folder.views.get_views(&ids); let views = folder.views.get_views(&ids);
for view in views { for view in views {
unique_ids.insert(view.parent_view_id.clone()); unique_ids.insert(view.parent_view_id.clone());
@ -146,7 +146,7 @@ pub(crate) fn notify_parent_view_did_change<T: AsRef<str>>(
folder: Arc<MutexFolder>, folder: Arc<MutexFolder>,
parent_view_ids: Vec<T>, parent_view_ids: Vec<T>,
) -> Option<()> { ) -> Option<()> {
let folder = folder.lock(); let folder = folder.read();
let folder = folder.as_ref()?; let folder = folder.as_ref()?;
let workspace_id = folder.get_workspace_id(); let workspace_id = folder.get_workspace_id();
let trash_ids = folder let trash_ids = folder

View File

@ -9,10 +9,11 @@ pub struct IndexableData {
pub data: String, pub data: String,
pub icon: Option<ViewIcon>, pub icon: Option<ViewIcon>,
pub layout: ViewLayout, pub layout: ViewLayout,
pub workspace_id: String,
} }
pub trait IndexManager: Send + Sync { pub trait IndexManager: Send + Sync {
fn set_index_content_receiver(&self, rx: IndexContentReceiver); fn set_index_content_receiver(&self, rx: IndexContentReceiver, workspace_id: String);
fn add_index(&self, data: IndexableData) -> Result<(), FlowyError>; fn add_index(&self, data: IndexableData) -> Result<(), FlowyError>;
fn update_index(&self, data: IndexableData) -> Result<(), FlowyError>; fn update_index(&self, data: IndexableData) -> Result<(), FlowyError>;
fn remove_indices(&self, ids: Vec<String>) -> Result<(), FlowyError>; fn remove_indices(&self, ids: Vec<String>) -> Result<(), FlowyError>;
@ -22,5 +23,5 @@ pub trait IndexManager: Send + Sync {
} }
pub trait FolderIndexManager: IndexManager { pub trait FolderIndexManager: IndexManager {
fn index_all_views(&self, views: Vec<View>); fn index_all_views(&self, views: Vec<View>, workspace_id: String);
} }

View File

@ -1,2 +1,2 @@
proto_input = ["src/event_map.rs", "src/entities.rs"] proto_input = ["src/event_map.rs", "src/entities"]
event_files = ["src/event_map.rs"] event_files = ["src/event_map.rs"]

View File

@ -0,0 +1,30 @@
use flowy_derive::ProtoBuf_Enum;
#[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)]
pub enum IndexTypePB {
View = 0,
DocumentBlock = 1,
DatabaseRow = 2,
}
impl Default for IndexTypePB {
fn default() -> Self {
Self::View
}
}
impl std::convert::From<IndexTypePB> for i32 {
fn from(notification: IndexTypePB) -> Self {
notification as i32
}
}
impl std::convert::From<i32> for IndexTypePB {
fn from(notification: i32) -> Self {
match notification {
1 => IndexTypePB::View,
2 => IndexTypePB::DocumentBlock,
_ => IndexTypePB::DatabaseRow,
}
}
}

View File

@ -0,0 +1,11 @@
mod index_type;
mod notification;
mod query;
mod result;
mod search_filter;
pub use index_type::*;
pub use notification::*;
pub use query::*;
pub use result::*;
pub use search_filter::*;

View File

@ -0,0 +1,39 @@
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use super::SearchResultPB;
#[derive(ProtoBuf, Default, Debug, Clone)]
pub struct SearchResultNotificationPB {
#[pb(index = 1)]
pub items: Vec<SearchResultPB>,
#[pb(index = 2)]
pub closed: bool,
#[pb(index = 3, one_of)]
pub channel: Option<String>,
}
#[derive(ProtoBuf_Enum, Debug, Default)]
pub enum SearchNotification {
#[default]
Unknown = 0,
DidUpdateResults = 1,
DidCloseResults = 2,
}
impl std::convert::From<SearchNotification> for i32 {
fn from(notification: SearchNotification) -> Self {
notification as i32
}
}
impl std::convert::From<i32> for SearchNotification {
fn from(notification: i32) -> Self {
match notification {
1 => SearchNotification::DidUpdateResults,
2 => SearchNotification::DidCloseResults,
_ => SearchNotification::Unknown,
}
}
}

View File

@ -0,0 +1,25 @@
use flowy_derive::ProtoBuf;
use super::SearchFilterPB;
#[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone)]
pub struct SearchQueryPB {
#[pb(index = 1)]
pub search: String,
#[pb(index = 2, one_of)]
pub limit: Option<i64>,
#[pb(index = 3, one_of)]
pub filter: Option<SearchFilterPB>,
/// Used to identify the channel of the search
///
/// This can be used to have multiple search notification listeners in place.
/// It is up to the client to decide how to handle this.
///
/// If not set, then no channel is used.
///
#[pb(index = 4, one_of)]
pub channel: Option<String>,
}

View File

@ -1,14 +1,7 @@
use collab_folder::{IconType, ViewIcon}; use collab_folder::{IconType, ViewIcon};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
#[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone)] use super::IndexTypePB;
pub struct SearchQueryPB {
#[pb(index = 1)]
pub search: String,
#[pb(index = 2, one_of)]
pub limit: Option<i64>,
}
#[derive(Debug, Default, ProtoBuf, Clone)] #[derive(Debug, Default, ProtoBuf, Clone)]
pub struct RepeatedSearchResultPB { pub struct RepeatedSearchResultPB {
@ -35,6 +28,9 @@ pub struct SearchResultPB {
#[pb(index = 6)] #[pb(index = 6)]
pub score: f64, pub score: f64,
#[pb(index = 7)]
pub workspace_id: String,
} }
impl SearchResultPB { impl SearchResultPB {
@ -46,6 +42,7 @@ impl SearchResultPB {
data: self.data.clone(), data: self.data.clone(),
icon: self.icon.clone(), icon: self.icon.clone(),
score, score,
workspace_id: self.workspace_id.clone(),
} }
} }
} }
@ -125,65 +122,3 @@ impl From<ViewIcon> for ResultIconPB {
} }
} }
} }
#[derive(ProtoBuf_Enum, Eq, PartialEq, Debug, Clone)]
pub enum IndexTypePB {
View = 0,
DocumentBlock = 1,
DatabaseRow = 2,
}
impl Default for IndexTypePB {
fn default() -> Self {
Self::View
}
}
impl std::convert::From<IndexTypePB> for i32 {
fn from(notification: IndexTypePB) -> Self {
notification as i32
}
}
impl std::convert::From<i32> for IndexTypePB {
fn from(notification: i32) -> Self {
match notification {
1 => IndexTypePB::View,
2 => IndexTypePB::DocumentBlock,
_ => IndexTypePB::DatabaseRow,
}
}
}
#[derive(ProtoBuf, Default, Debug, Clone)]
pub struct SearchResultNotificationPB {
#[pb(index = 1)]
pub items: Vec<SearchResultPB>,
#[pb(index = 2)]
pub closed: bool,
}
#[derive(ProtoBuf_Enum, Debug, Default)]
pub enum SearchNotification {
#[default]
Unknown = 0,
DidUpdateResults = 1,
DidCloseResults = 2,
}
impl std::convert::From<SearchNotification> for i32 {
fn from(notification: SearchNotification) -> Self {
notification as i32
}
}
impl std::convert::From<i32> for SearchNotification {
fn from(notification: i32) -> Self {
match notification {
1 => SearchNotification::DidUpdateResults,
2 => SearchNotification::DidCloseResults,
_ => SearchNotification::Unknown,
}
}
}

View File

@ -0,0 +1,7 @@
use flowy_derive::ProtoBuf;
#[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone)]
pub struct SearchFilterPB {
#[pb(index = 1, one_of)]
pub workspace_id: Option<String>,
}

View File

@ -21,7 +21,7 @@ pub(crate) async fn search_handler(
) -> Result<(), FlowyError> { ) -> Result<(), FlowyError> {
let query = data.into_inner(); let query = data.into_inner();
let manager = upgrade_manager(manager)?; let manager = upgrade_manager(manager)?;
manager.perform_search(query.search); manager.perform_search(query.search, query.filter, query.channel);
Ok(()) Ok(())
} }

View File

@ -8,6 +8,7 @@ pub struct FolderIndexData {
pub title: String, pub title: String,
pub icon: String, pub icon: String,
pub icon_ty: i64, pub icon_ty: i64,
pub workspace_id: String,
} }
impl From<FolderIndexData> for SearchResultPB { impl From<FolderIndexData> for SearchResultPB {
@ -28,6 +29,7 @@ impl From<FolderIndexData> for SearchResultPB {
data: data.title, data: data.title,
score: 0.0, score: 0.0,
icon, icon,
workspace_id: data.workspace_id,
} }
} }
} }

View File

@ -1,5 +1,7 @@
use crate::entities::SearchResultPB; use crate::{
use crate::services::manager::{SearchHandler, SearchType}; entities::{SearchFilterPB, SearchResultPB},
services::manager::{SearchHandler, SearchType},
};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use std::sync::Arc; use std::sync::Arc;
@ -20,8 +22,20 @@ impl SearchHandler for FolderSearchHandler {
SearchType::Folder SearchType::Folder
} }
fn perform_search(&self, query: String) -> FlowyResult<Vec<SearchResultPB>> { fn perform_search(
self.index_manager.search(query) &self,
query: String,
filter: Option<SearchFilterPB>,
) -> FlowyResult<Vec<SearchResultPB>> {
let mut results = self.index_manager.search(query, filter.clone())?;
if let Some(filter) = filter {
if let Some(workspace_id) = filter.workspace_id {
// Filter results by workspace ID
results.retain(|result| result.workspace_id == workspace_id);
}
}
Ok(results)
} }
fn index_count(&self) -> u64 { fn index_count(&self) -> u64 {

View File

@ -8,8 +8,11 @@ use std::{
}; };
use crate::{ use crate::{
entities::ResultIconTypePB, entities::{ResultIconTypePB, SearchFilterPB, SearchResultPB},
folder::schema::{FolderSchema, FOLDER_ICON_FIELD_NAME, FOLDER_TITLE_FIELD_NAME}, folder::schema::{
FolderSchema, FOLDER_ICON_FIELD_NAME, FOLDER_ICON_TY_FIELD_NAME, FOLDER_ID_FIELD_NAME,
FOLDER_TITLE_FIELD_NAME, FOLDER_WORKSPACE_ID_FIELD_NAME,
},
}; };
use collab::core::collab::{IndexContent, IndexContentReceiver}; use collab::core::collab::{IndexContent, IndexContentReceiver};
use collab_folder::{View, ViewIcon, ViewIndexContent, ViewLayout}; use collab_folder::{View, ViewIcon, ViewIndexContent, ViewLayout};
@ -23,12 +26,7 @@ use tantivy::{
IndexWriter, Term, IndexWriter, Term,
}; };
use crate::entities::SearchResultPB; use super::entities::FolderIndexData;
use super::{
entities::FolderIndexData,
schema::{FOLDER_ICON_TY_FIELD_NAME, FOLDER_ID_FIELD_NAME},
};
#[derive(Clone)] #[derive(Clone)]
pub struct FolderIndexManagerImpl { pub struct FolderIndexManagerImpl {
@ -41,7 +39,15 @@ pub struct FolderIndexManagerImpl {
const FOLDER_INDEX_DIR: &str = "folder_index"; const FOLDER_INDEX_DIR: &str = "folder_index";
impl FolderIndexManagerImpl { impl FolderIndexManagerImpl {
pub fn new(auth_user: Weak<AuthenticateUser>) -> Self { pub fn new(auth_user: Option<Weak<AuthenticateUser>>) -> Self {
// TODO(Mathias): Temporarily disable seaerch
let auth_user = match auth_user {
Some(auth_user) => auth_user,
None => {
return FolderIndexManagerImpl::empty();
},
};
// AuthenticateUser is required to get the index path // AuthenticateUser is required to get the index path
let authenticate_user = auth_user.upgrade(); let authenticate_user = auth_user.upgrade();
@ -130,15 +136,19 @@ impl FolderIndexManagerImpl {
let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?; let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?;
let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?; let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?;
let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?; let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?;
let workspace_id_field = folder_schema
.schema
.get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?;
for data in indexes { for data in indexes {
let (icon, icon_ty) = self.extract_icon(data.icon, data.layout); let (icon, icon_ty) = self.extract_icon(data.icon, data.layout);
let _ = index_writer.add_document(doc![ let _ = index_writer.add_document(doc![
id_field => data.id.clone(), id_field => data.id.clone(),
title_field => data.data.clone(), title_field => data.data.clone(),
icon_field => icon.unwrap_or_default(), icon_field => icon.unwrap_or_default(),
icon_ty_field => icon_ty, icon_ty_field => icon_ty,
workspace_id_field => data.workspace_id.clone(),
]); ]);
} }
@ -206,7 +216,11 @@ impl FolderIndexManagerImpl {
(icon, icon_ty) (icon, icon_ty)
} }
pub fn search(&self, query: String) -> Result<Vec<SearchResultPB>, FlowyError> { pub fn search(
&self,
query: String,
_filter: Option<SearchFilterPB>,
) -> Result<Vec<SearchResultPB>, FlowyError> {
let folder_schema = self.get_folder_schema()?; let folder_schema = self.get_folder_schema()?;
let index = match &self.index { let index = match &self.index {
@ -222,11 +236,7 @@ impl FolderIndexManagerImpl {
let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?; let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?;
let length = query.len(); let length = query.len();
let distance: u8 = match length { let distance: u8 = if length >= 2 { 2 } else { 1 };
_ if length > 4 => 2,
_ if length > 2 => 1,
_ => 0,
};
let mut query_parser = QueryParser::for_index(&index.clone(), vec![title_field]); let mut query_parser = QueryParser::for_index(&index.clone(), vec![title_field]);
query_parser.set_field_fuzzy(title_field, true, distance, true); query_parser.set_field_fuzzy(title_field, true, distance, true);
@ -273,8 +283,9 @@ impl IndexManager for FolderIndexManagerImpl {
.unwrap_or(false) .unwrap_or(false)
} }
fn set_index_content_receiver(&self, mut rx: IndexContentReceiver) { fn set_index_content_receiver(&self, mut rx: IndexContentReceiver, workspace_id: String) {
let indexer = self.clone(); let indexer = self.clone();
let wid = workspace_id.clone();
af_spawn(async move { af_spawn(async move {
while let Ok(msg) = rx.recv().await { while let Ok(msg) = rx.recv().await {
match msg { match msg {
@ -285,6 +296,7 @@ impl IndexManager for FolderIndexManagerImpl {
data: view.name, data: view.name,
icon: view.icon, icon: view.icon,
layout: view.layout, layout: view.layout,
workspace_id: wid.clone(),
}); });
}, },
Err(err) => tracing::error!("FolderIndexManager error deserialize: {:?}", err), Err(err) => tracing::error!("FolderIndexManager error deserialize: {:?}", err),
@ -296,6 +308,7 @@ impl IndexManager for FolderIndexManagerImpl {
data: view.name, data: view.name,
icon: view.icon, icon: view.icon,
layout: view.layout, layout: view.layout,
workspace_id: wid.clone(),
}); });
}, },
Err(err) => tracing::error!("FolderIndexManager error deserialize: {:?}", err), Err(err) => tracing::error!("FolderIndexManager error deserialize: {:?}", err),
@ -317,7 +330,11 @@ impl IndexManager for FolderIndexManagerImpl {
let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?; let id_field = folder_schema.schema.get_field(FOLDER_ID_FIELD_NAME)?;
let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?; let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?;
let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?; let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?;
let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?; let icon_ty_field: tantivy::schema::Field =
folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?;
let workspace_id_field = folder_schema
.schema
.get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?;
let delete_term = Term::from_field_text(id_field, &data.id.clone()); let delete_term = Term::from_field_text(id_field, &data.id.clone());
@ -332,6 +349,7 @@ impl IndexManager for FolderIndexManagerImpl {
title_field => data.data, title_field => data.data,
icon_field => icon.unwrap_or_default(), icon_field => icon.unwrap_or_default(),
icon_ty_field => icon_ty, icon_ty_field => icon_ty,
workspace_id_field => data.workspace_id.clone(),
]); ]);
index_writer.commit()?; index_writer.commit()?;
@ -364,6 +382,9 @@ impl IndexManager for FolderIndexManagerImpl {
let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?; let title_field = folder_schema.schema.get_field(FOLDER_TITLE_FIELD_NAME)?;
let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?; let icon_field = folder_schema.schema.get_field(FOLDER_ICON_FIELD_NAME)?;
let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?; let icon_ty_field = folder_schema.schema.get_field(FOLDER_ICON_TY_FIELD_NAME)?;
let workspace_id_field = folder_schema
.schema
.get_field(FOLDER_WORKSPACE_ID_FIELD_NAME)?;
let (icon, icon_ty) = self.extract_icon(data.icon, data.layout); let (icon, icon_ty) = self.extract_icon(data.icon, data.layout);
@ -373,6 +394,7 @@ impl IndexManager for FolderIndexManagerImpl {
title_field => data.data, title_field => data.data,
icon_field => icon.unwrap_or_default(), icon_field => icon.unwrap_or_default(),
icon_ty_field => icon_ty, icon_ty_field => icon_ty,
workspace_id_field => data.workspace_id,
]); ]);
index_writer.commit()?; index_writer.commit()?;
@ -386,7 +408,7 @@ impl IndexManager for FolderIndexManagerImpl {
} }
impl FolderIndexManager for FolderIndexManagerImpl { impl FolderIndexManager for FolderIndexManagerImpl {
fn index_all_views(&self, views: Vec<View>) { fn index_all_views(&self, views: Vec<View>, workspace_id: String) {
let indexable_data = views let indexable_data = views
.into_iter() .into_iter()
.map(|view| IndexableData { .map(|view| IndexableData {
@ -394,6 +416,7 @@ impl FolderIndexManager for FolderIndexManagerImpl {
data: view.name, data: view.name,
icon: view.icon, icon: view.icon,
layout: view.layout, layout: view.layout,
workspace_id: workspace_id.clone(),
}) })
.collect(); .collect();

View File

@ -4,6 +4,7 @@ pub const FOLDER_ID_FIELD_NAME: &str = "id";
pub const FOLDER_TITLE_FIELD_NAME: &str = "title"; pub const FOLDER_TITLE_FIELD_NAME: &str = "title";
pub const FOLDER_ICON_FIELD_NAME: &str = "icon"; pub const FOLDER_ICON_FIELD_NAME: &str = "icon";
pub const FOLDER_ICON_TY_FIELD_NAME: &str = "icon_ty"; pub const FOLDER_ICON_TY_FIELD_NAME: &str = "icon_ty";
pub const FOLDER_WORKSPACE_ID_FIELD_NAME: &str = "workspace_id";
#[derive(Clone)] #[derive(Clone)]
pub struct FolderSchema { pub struct FolderSchema {
@ -33,6 +34,10 @@ impl FolderSchema {
tantivy::schema::TEXT | tantivy::schema::STORED, tantivy::schema::TEXT | tantivy::schema::STORED,
); );
schema_builder.add_i64_field(FOLDER_ICON_TY_FIELD_NAME, tantivy::schema::STORED); schema_builder.add_i64_field(FOLDER_ICON_TY_FIELD_NAME, tantivy::schema::STORED);
schema_builder.add_text_field(
FOLDER_WORKSPACE_ID_FIELD_NAME,
tantivy::schema::TEXT | tantivy::schema::STORED,
);
let schema = schema_builder.build(); let schema = schema_builder.build();

View File

@ -5,7 +5,7 @@ use flowy_error::FlowyResult;
use lib_dispatch::prelude::af_spawn; use lib_dispatch::prelude::af_spawn;
use tokio::{sync::broadcast, task::spawn_blocking}; use tokio::{sync::broadcast, task::spawn_blocking};
use crate::entities::{SearchResultNotificationPB, SearchResultPB}; use crate::entities::{SearchFilterPB, SearchResultNotificationPB, SearchResultPB};
use super::notifier::{SearchNotifier, SearchResultChanged, SearchResultReceiverRunner}; use super::notifier::{SearchNotifier, SearchResultChanged, SearchResultReceiverRunner};
@ -18,7 +18,11 @@ pub trait SearchHandler: Send + Sync + 'static {
/// returns the type of search this handler is responsible for /// returns the type of search this handler is responsible for
fn search_type(&self) -> SearchType; fn search_type(&self) -> SearchType;
/// performs a search and returns the results /// performs a search and returns the results
fn perform_search(&self, query: String) -> FlowyResult<Vec<SearchResultPB>>; fn perform_search(
&self,
query: String,
filter: Option<SearchFilterPB>,
) -> FlowyResult<Vec<SearchResultPB>>;
/// returns the number of indexed objects /// returns the number of indexed objects
fn index_count(&self) -> u64; fn index_count(&self) -> u64;
} }
@ -50,17 +54,24 @@ impl SearchManager {
self.handlers.get(&search_type) self.handlers.get(&search_type)
} }
pub fn perform_search(&self, query: String) { pub fn perform_search(
&self,
query: String,
filter: Option<SearchFilterPB>,
channel: Option<String>,
) {
let mut sends: usize = 0; let mut sends: usize = 0;
let max: usize = self.handlers.len(); let max: usize = self.handlers.len();
let handlers = self.handlers.clone(); let handlers = self.handlers.clone();
for (_, handler) in handlers { for (_, handler) in handlers {
let q = query.clone(); let q = query.clone();
let f = filter.clone();
let ch = channel.clone();
let notifier = self.notifier.clone(); let notifier = self.notifier.clone();
spawn_blocking(move || { spawn_blocking(move || {
let res = handler.perform_search(q); let res = handler.perform_search(q, f);
sends += 1; sends += 1;
let close = sends == max; let close = sends == max;
@ -68,6 +79,7 @@ impl SearchManager {
let notification = SearchResultNotificationPB { let notification = SearchResultNotificationPB {
items, items,
closed: close, closed: close,
channel: ch,
}; };
let _ = notifier.send(SearchResultChanged::SearchResultUpdate(notification)); let _ = notifier.send(SearchResultChanged::SearchResultUpdate(notification));

View File

@ -37,7 +37,7 @@ impl SearchResultReceiverRunner {
SearchNotification::DidUpdateResults SearchNotification::DidUpdateResults
}; };
send_notification(SEARCH_ID, ty) send_notification(SEARCH_ID, ty, notification.channel.clone())
.payload(notification) .payload(notification)
.send(); .send();
}, },
@ -48,6 +48,16 @@ impl SearchResultReceiverRunner {
} }
#[tracing::instrument(level = "trace")] #[tracing::instrument(level = "trace")]
pub fn send_notification(id: &str, ty: SearchNotification) -> NotificationBuilder { pub fn send_notification(
NotificationBuilder::new(id, ty, SEARCH_OBSERVABLE_SOURCE) id: &str,
ty: SearchNotification,
channel: Option<String>,
) -> NotificationBuilder {
let observable_source = &format!(
"{}{}",
SEARCH_OBSERVABLE_SOURCE,
channel.unwrap_or_default()
);
NotificationBuilder::new(id, ty, observable_source)
} }

View File

@ -32,9 +32,6 @@ pub(crate) struct UserProfileResponse {
pub updated_at: DateTime<Utc>, pub updated_at: DateTime<Utc>,
} }
#[derive(Debug, Deserialize)]
pub(crate) struct UserProfileResponseList(pub Vec<UserProfileResponse>);
#[derive(Deserialize, Clone)] #[derive(Deserialize, Clone)]
pub(crate) struct UidResponse { pub(crate) struct UidResponse {
#[allow(dead_code)] #[allow(dead_code)]

View File

@ -1,3 +1,5 @@
use std::io;
use std::io::Write;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use chrono::Local; use chrono::Local;
@ -88,8 +90,8 @@ impl Builder {
.pretty() .pretty()
.with_env_filter(env_filter) .with_env_filter(env_filter)
.finish() .finish()
.with(FlowyFormattingLayer::new(StdoutWriter))
.with(JsonStorageLayer) .with(JsonStorageLayer)
.with(FlowyFormattingLayer::new(DebugStdoutWriter))
.with(file_layer); .with(file_layer);
set_global_default(subscriber).map_err(|e| format!("{:?}", e))?; set_global_default(subscriber).map_err(|e| format!("{:?}", e))?;
}; };
@ -106,12 +108,19 @@ impl tracing_subscriber::fmt::time::FormatTime for CustomTime {
} }
} }
pub struct StdoutWriter; pub struct DebugStdoutWriter;
impl<'a> MakeWriter<'a> for StdoutWriter { impl<'a> MakeWriter<'a> for DebugStdoutWriter {
type Writer = std::io::Stdout; type Writer = Box<dyn Write>;
fn make_writer(&'a self) -> Self::Writer { fn make_writer(&'a self) -> Self::Writer {
std::io::stdout() #[cfg(not(debug_assertions))]
{
Box::new(io::sink())
}
#[cfg(debug_assertions)]
{
Box::new(io::stdout())
}
} }
} }

View File

@ -1,2 +1,2 @@
[toolchain] [toolchain]
channel = "1.75" channel = "1.77.2"