mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-16 14:40:43 +03:00
feat: search mvp (#5064)
* feat: implement folder indexer * feat: sqlite search views using fts5 * feat: add view indexing to user manager * feat: implement folder indexer * feat: add sqlite search documents * feat: add document indexing to user manager * feat: add document indexing to folder indexer * chore: update collab rev * feat: search frontend integration * refactor: search index * test: add event test * chore: fix ci * feat: initial command palette overlay impl (#4619) * chore: test search engine * chore: initial structure * chore: replace old search request * chore: enable log for lib-dispatch * chore: move search manager to core * feat: move traits and responsibility to search crate * feat: move search to search crate * feat: replace sqlite with tantivy * feat: deserialize tantivy documents * chore: fixes after rebase * chore: clean code * feat: fetch and sort results * fix: code review + cleaning * feat: support custom icons * feat: support view layout icons * feat: rename bloc and fix indexing * fix: prettify dialog * feat: score results * chore: update collab rev * feat: add recent view history to command palette * test: add integration_tests * fix: clippy changes * fix: focus traversal in cmd palette * fix: remove file after merging main * chore: code review and panic-safe * feat: index all views if index does not exist * chore: improve logic with conditional * chore: add is_empty check * chore: abstract logic from folder manager init * chore: update collab rev * chore: code review * chore: fixes after merge + update lock file * chore: revert cargo lock * fix: set icon type when removing icon * fix: code review + dependency inversion * fix: remove icon fix for not persisting icon type * test: simple tests manipulating views * test: create 100 views * fix: tauri build * chore: create 1000 views * chore: create util methods * chore: test * chore: test * chore: remove logs * chore: fix build.rs * chore: export models * chore: enable clear cache on Rust-CI * fix: navigate to newly created views * fix: force disable setting workspace listener on rebuilds * fix: remove late final * fix: missing returns * fix: localization and minor fixes * test: add index assert to large test * fix: missing section param after merging main * chore: try fix unzip file error * chore: lower the test * feat: show hint when result is in trash * feat: one index_writer per index * fix: minor changes after merge * fix: make create_log_filter public after merge * chore: fix test * chore: fix test * chore: flutter analyze * chore: flutter analyze * chore: fix tauri build --------- Co-authored-by: nathan <nathan@appflowy.io> Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io> Co-authored-by: Nathan.fooo <86001920+appflowy@users.noreply.github.com>
This commit is contained in:
parent
39d8d428a6
commit
b4d22bab14
30
.github/workflows/rust_ci.yaml
vendored
30
.github/workflows/rust_ci.yaml
vendored
@ -25,21 +25,21 @@ jobs:
|
||||
test-on-ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# - name: Maximize build space
|
||||
# uses: easimon/maximize-build-space@master
|
||||
# with:
|
||||
# root-reserve-mb: 2048
|
||||
# swap-size-mb: 1024
|
||||
# remove-dotnet: 'true'
|
||||
#
|
||||
# # the following step is required to avoid running out of space
|
||||
# - name: Maximize build space
|
||||
# run: |
|
||||
# sudo rm -rf /usr/share/dotnet
|
||||
# sudo rm -rf /opt/ghc
|
||||
# sudo rm -rf "/usr/local/share/boost"
|
||||
# sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
# sudo docker image prune --all --force
|
||||
- name: Maximize build space
|
||||
uses: easimon/maximize-build-space@master
|
||||
with:
|
||||
root-reserve-mb: 2048
|
||||
swap-size-mb: 1024
|
||||
remove-dotnet: 'true'
|
||||
|
||||
# the following step is required to avoid running out of space
|
||||
- name: Maximize build space
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf "/usr/local/share/boost"
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
sudo docker image prune --all --force
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
|
@ -0,0 +1,22 @@
|
||||
import 'package:appflowy/workspace/presentation/command_palette/command_palette.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../../shared/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('Command Palette', () {
|
||||
testWidgets('Toggle command palette', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapAnonymousSignInButton();
|
||||
|
||||
await tester.toggleCommandPalette();
|
||||
expect(find.byType(CommandPaletteModal), findsOneWidget);
|
||||
|
||||
await tester.toggleCommandPalette();
|
||||
expect(find.byType(CommandPaletteModal), findsNothing);
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'command_palette_test.dart' as command_palette_test;
|
||||
import 'folder_search_test.dart' as folder_search_test;
|
||||
import 'recent_history_test.dart' as recent_history_test;
|
||||
|
||||
void startTesting() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// Command Palette integration tests
|
||||
command_palette_test.main();
|
||||
folder_search_test.main();
|
||||
recent_history_test.main();
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import 'package:appflowy/workspace/presentation/command_palette/command_palette.dart';
|
||||
import 'package:appflowy/workspace/presentation/command_palette/widgets/search_field.dart';
|
||||
import 'package:appflowy/workspace/presentation/command_palette/widgets/search_result_tile.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../../shared/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('Folder Search', () {
|
||||
testWidgets('Search for views', (tester) async {
|
||||
const firstDocument = "ViewOne";
|
||||
const secondDocument = "ViewOna";
|
||||
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapAnonymousSignInButton();
|
||||
|
||||
await tester.createNewPageWithNameUnderParent(name: firstDocument);
|
||||
await tester.createNewPageWithNameUnderParent(name: secondDocument);
|
||||
|
||||
await tester.toggleCommandPalette();
|
||||
expect(find.byType(CommandPaletteModal), findsOneWidget);
|
||||
|
||||
final searchFieldFinder = find.descendant(
|
||||
of: find.byType(SearchField),
|
||||
matching: find.byType(FlowyTextField),
|
||||
);
|
||||
|
||||
await tester.enterText(searchFieldFinder, secondDocument);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 200));
|
||||
|
||||
// Expect two search results "ViewOna" and "ViewOne" (Distance 1 to ViewOna)
|
||||
expect(find.byType(SearchResultTile), findsNWidgets(2));
|
||||
|
||||
// The score should be higher for "ViewOna" thus it should be shown first
|
||||
final secondDocumentWidget = tester
|
||||
.widget(find.byType(SearchResultTile).first) as SearchResultTile;
|
||||
expect(secondDocumentWidget.result.data, secondDocument);
|
||||
|
||||
// Change search to "ViewOne"
|
||||
await tester.enterText(searchFieldFinder, firstDocument);
|
||||
await tester.pumpAndSettle(const Duration(seconds: 1));
|
||||
|
||||
// The score should be higher for "ViewOne" thus it should be shown first
|
||||
final firstDocumentWidget = tester
|
||||
.widget(find.byType(SearchResultTile).first) as SearchResultTile;
|
||||
expect(firstDocumentWidget.result.data, firstDocument);
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
import 'package:appflowy/workspace/presentation/command_palette/command_palette.dart';
|
||||
import 'package:appflowy/workspace/presentation/command_palette/widgets/recent_view_tile.dart';
|
||||
import 'package:appflowy/workspace/presentation/command_palette/widgets/recent_views_list.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import '../../shared/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('Recent History', () {
|
||||
testWidgets('Search for views', (tester) async {
|
||||
const firstDocument = "First";
|
||||
const secondDocument = "Second";
|
||||
|
||||
await tester.initializeAppFlowy();
|
||||
await tester.tapAnonymousSignInButton();
|
||||
|
||||
await tester.createNewPageWithNameUnderParent(name: firstDocument);
|
||||
await tester.createNewPageWithNameUnderParent(name: secondDocument);
|
||||
|
||||
await tester.toggleCommandPalette();
|
||||
expect(find.byType(CommandPaletteModal), findsOneWidget);
|
||||
|
||||
// Expect history list
|
||||
expect(find.byType(RecentViewsList), findsOneWidget);
|
||||
|
||||
// Expect three recent history items
|
||||
expect(find.byType(RecentViewTile), findsNWidgets(3));
|
||||
|
||||
// Expect the first item to be the last viewed document
|
||||
final firstDocumentWidget =
|
||||
tester.widget(find.byType(RecentViewTile).first) as RecentViewTile;
|
||||
expect(firstDocumentWidget.view.name, secondDocument);
|
||||
});
|
||||
});
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:appflowy/core/config/kv.dart';
|
||||
import 'package:appflowy/core/config/kv_keys.dart';
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
@ -26,9 +30,6 @@ import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'emoji.dart';
|
||||
@ -520,6 +521,16 @@ extension CommonOperations on WidgetTester {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleCommandPalette() async {
|
||||
// Press CMD+P or CTRL+P to open the command palette
|
||||
await simulateKeyEvent(
|
||||
LogicalKeyboardKey.keyP,
|
||||
isControlPressed: !Platform.isMacOS,
|
||||
isMetaPressed: Platform.isMacOS,
|
||||
);
|
||||
await pumpAndSettle();
|
||||
}
|
||||
|
||||
Future<void> openCollaborativeWorkspaceMenu() async {
|
||||
if (!FeatureFlag.collaborativeWorkspace.isOn) {
|
||||
throw UnsupportedError('Collaborative workspace is not enabled');
|
||||
|
@ -0,0 +1,55 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.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-search/entities.pbenum.dart';
|
||||
import 'package:appflowy_backend/rust_stream.dart';
|
||||
import 'package:appflowy_result/appflowy_result.dart';
|
||||
|
||||
import 'notification_helper.dart';
|
||||
|
||||
// This value must be identical to the value in the backend (SEARCH_OBSERVABLE_SOURCE)
|
||||
const _source = 'Search';
|
||||
|
||||
typedef SearchNotificationCallback = void Function(
|
||||
SearchNotification,
|
||||
FlowyResult<Uint8List, FlowyError>,
|
||||
);
|
||||
|
||||
class SearchNotificationParser
|
||||
extends NotificationParser<SearchNotification, FlowyError> {
|
||||
SearchNotificationParser({
|
||||
super.id,
|
||||
required super.callback,
|
||||
}) : super(
|
||||
tyParser: (ty, source) =>
|
||||
source == _source ? SearchNotification.valueOf(ty) : null,
|
||||
errorParser: (bytes) => FlowyError.fromBuffer(bytes),
|
||||
);
|
||||
}
|
||||
|
||||
typedef SearchNotificationHandler = Function(
|
||||
SearchNotification ty,
|
||||
FlowyResult<Uint8List, FlowyError> result,
|
||||
);
|
||||
|
||||
class SearchNotificationListener {
|
||||
SearchNotificationListener({
|
||||
required String objectId,
|
||||
required SearchNotificationHandler handler,
|
||||
}) : _parser = SearchNotificationParser(id: objectId, callback: handler) {
|
||||
_subscription =
|
||||
RustStreamReceiver.listen((observable) => _parser?.parse(observable));
|
||||
}
|
||||
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
SearchNotificationParser? _parser;
|
||||
|
||||
Future<void> stop() async {
|
||||
_parser = null;
|
||||
await _subscription?.cancel();
|
||||
_subscription = null;
|
||||
}
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'widgets/widgets.dart';
|
||||
|
||||
class NotificationsSettingGroup extends StatefulWidget {
|
||||
const NotificationsSettingGroup({
|
||||
super.key,
|
||||
});
|
||||
const NotificationsSettingGroup({super.key});
|
||||
|
||||
@override
|
||||
State<NotificationsSettingGroup> createState() =>
|
||||
@ -15,7 +14,6 @@ class NotificationsSettingGroup extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _NotificationsSettingGroupState extends State<NotificationsSettingGroup> {
|
||||
// TODO:remove this after notification page is implemented
|
||||
bool isPushNotificationOn = false;
|
||||
|
||||
@override
|
||||
|
@ -1,11 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/icon.pbenum.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
extension ToProto on FlowyIconType {
|
||||
ViewIconTypePB toProto() {
|
||||
switch (this) {
|
||||
case FlowyIconType.emoji:
|
||||
return ViewIconTypePB.Emoji;
|
||||
case FlowyIconType.icon:
|
||||
return ViewIconTypePB.Icon;
|
||||
case FlowyIconType.custom:
|
||||
return ViewIconTypePB.Url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum FlowyIconType {
|
||||
emoji,
|
||||
@ -14,6 +29,12 @@ enum FlowyIconType {
|
||||
}
|
||||
|
||||
class EmojiPickerResult {
|
||||
factory EmojiPickerResult.none() =>
|
||||
const EmojiPickerResult(FlowyIconType.icon, '');
|
||||
|
||||
factory EmojiPickerResult.emoji(String emoji) =>
|
||||
EmojiPickerResult(FlowyIconType.emoji, emoji);
|
||||
|
||||
const EmojiPickerResult(
|
||||
this.type,
|
||||
this.emoji,
|
||||
@ -23,7 +44,7 @@ class EmojiPickerResult {
|
||||
final String emoji;
|
||||
}
|
||||
|
||||
class FlowyIconPicker extends StatefulWidget {
|
||||
class FlowyIconPicker extends StatelessWidget {
|
||||
const FlowyIconPicker({
|
||||
super.key,
|
||||
required this.onSelected,
|
||||
@ -31,17 +52,6 @@ class FlowyIconPicker extends StatefulWidget {
|
||||
|
||||
final void Function(EmojiPickerResult result) onSelected;
|
||||
|
||||
@override
|
||||
State<FlowyIconPicker> createState() => _FlowyIconPickerState();
|
||||
}
|
||||
|
||||
class _FlowyIconPickerState extends State<FlowyIconPicker>
|
||||
with SingleTickerProviderStateMixin {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// ONLY supports emoji picker for now
|
||||
@ -55,33 +65,18 @@ class _FlowyIconPickerState extends State<FlowyIconPicker>
|
||||
_buildTabs(context),
|
||||
const Spacer(),
|
||||
_RemoveIconButton(
|
||||
onTap: () {
|
||||
widget.onSelected(
|
||||
const EmojiPickerResult(
|
||||
FlowyIconType.icon,
|
||||
'',
|
||||
),
|
||||
);
|
||||
},
|
||||
onTap: () => onSelected(EmojiPickerResult.none()),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Divider(
|
||||
height: 2,
|
||||
),
|
||||
const Divider(height: 2),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
children: [
|
||||
FlowyEmojiPicker(
|
||||
emojiPerLine: _getEmojiPerLine(),
|
||||
onEmojiSelected: (_, emoji) {
|
||||
widget.onSelected(
|
||||
EmojiPickerResult(
|
||||
FlowyIconType.emoji,
|
||||
emoji,
|
||||
),
|
||||
);
|
||||
},
|
||||
emojiPerLine: _getEmojiPerLine(context),
|
||||
onEmojiSelected: (_, emoji) =>
|
||||
onSelected(EmojiPickerResult.emoji(emoji)),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -109,9 +104,7 @@ class _FlowyIconPickerState extends State<FlowyIconPicker>
|
||||
horizontal: 12.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: FlowyText(
|
||||
LocaleKeys.emoji_emojiTab.tr(),
|
||||
),
|
||||
child: FlowyText(LocaleKeys.emoji_emojiTab.tr()),
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -119,7 +112,7 @@ class _FlowyIconPickerState extends State<FlowyIconPicker>
|
||||
);
|
||||
}
|
||||
|
||||
int _getEmojiPerLine() {
|
||||
int _getEmojiPerLine(BuildContext context) {
|
||||
if (PlatformExtension.isDesktopOrWeb) {
|
||||
return 9;
|
||||
}
|
||||
@ -129,11 +122,10 @@ class _FlowyIconPickerState extends State<FlowyIconPicker>
|
||||
}
|
||||
|
||||
class _RemoveIconButton extends StatelessWidget {
|
||||
const _RemoveIconButton({
|
||||
required this.onTap,
|
||||
});
|
||||
const _RemoveIconButton({required this.onTap});
|
||||
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
|
@ -1,8 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/app_bar.dart';
|
||||
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class IconPickerPage extends StatelessWidget {
|
||||
const IconPickerPage({
|
||||
@ -21,9 +22,7 @@ class IconPickerPage extends StatelessWidget {
|
||||
titleText: title ?? LocaleKeys.titleBar_pageIcon.tr(),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: FlowyIconPicker(
|
||||
onSelected: onSelected,
|
||||
),
|
||||
child: FlowyIconPicker(onSelected: onSelected),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ import 'package:appflowy/plugins/database/grid/presentation/widgets/calculations
|
||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/toolbar/grid_setting_bar.dart';
|
||||
import 'package:appflowy/plugins/database/tab_bar/desktop/setting_menu.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/cell/editable_cell_builder.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action_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_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
@ -123,7 +123,7 @@ class _GridPageState extends State<GridPage> {
|
||||
view: widget.view,
|
||||
databaseController: widget.databaseController,
|
||||
)..add(const GridEvent.initial()),
|
||||
child: BlocListener<NotificationActionBloc, NotificationActionState>(
|
||||
child: BlocListener<ActionNavigationBloc, ActionNavigationState>(
|
||||
listener: (context, state) {
|
||||
final action = state.action;
|
||||
if (action?.type == ActionType.openRow &&
|
||||
|
@ -10,7 +10,7 @@ import 'package:appflowy/plugins/database/grid/application/grid_bloc.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/widgets/shortcuts.dart';
|
||||
import 'package:appflowy/plugins/database/tab_bar/tab_bar_view.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/action_navigation/action_navigation_bloc.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
||||
@ -87,8 +87,8 @@ class _MobileGridPageState extends State<MobileGridPage> {
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<NotificationActionBloc>.value(
|
||||
value: getIt<NotificationActionBloc>(),
|
||||
BlocProvider<ActionNavigationBloc>.value(
|
||||
value: getIt<ActionNavigationBloc>(),
|
||||
),
|
||||
BlocProvider<GridBloc>(
|
||||
create: (context) => GridBloc(
|
||||
|
@ -1,3 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/banner.dart';
|
||||
@ -6,15 +8,14 @@ import 'package:appflowy/plugins/document/presentation/editor_page.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action_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/view/prelude.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/widget/error_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class DocumentPage extends StatefulWidget {
|
||||
@ -52,7 +53,7 @@ class _DocumentPageState extends State<DocumentPage> {
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider.value(value: getIt<NotificationActionBloc>()),
|
||||
BlocProvider.value(value: getIt<ActionNavigationBloc>()),
|
||||
BlocProvider(
|
||||
create: (_) => DocumentBloc(view: widget.view)
|
||||
..add(const DocumentEvent.initial()),
|
||||
@ -80,9 +81,9 @@ class _DocumentPageState extends State<DocumentPage> {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return BlocListener<NotificationActionBloc, NotificationActionState>(
|
||||
listener: _onNotificationAction,
|
||||
return BlocListener<ActionNavigationBloc, ActionNavigationState>(
|
||||
listenWhen: (_, curr) => curr.action != null,
|
||||
listener: _onNotificationAction,
|
||||
child: _buildEditorPage(context, state),
|
||||
);
|
||||
},
|
||||
@ -156,7 +157,7 @@ class _DocumentPageState extends State<DocumentPage> {
|
||||
|
||||
void _onNotificationAction(
|
||||
BuildContext context,
|
||||
NotificationActionState state,
|
||||
ActionNavigationState state,
|
||||
) {
|
||||
if (state.action != null && state.action!.type == ActionType.jumpToBlock) {
|
||||
final path = state.action?.arguments?[ActionArgumentKeys.nodePath];
|
||||
|
@ -1,5 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
@ -19,7 +21,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/widget/rounded_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:string_validator/string_validator.dart';
|
||||
|
@ -18,9 +18,9 @@ import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
|
||||
import 'package:appflowy/user/application/user_listener.dart';
|
||||
import 'package:appflowy/user/application/user_service.dart';
|
||||
import 'package:appflowy/user/presentation/router.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/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action_bloc.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/mobile_appearance.dart';
|
||||
@ -193,7 +193,7 @@ void _resolveHomeDeps(GetIt getIt) {
|
||||
(view, _) => DocumentShareBloc(view: view),
|
||||
);
|
||||
|
||||
getIt.registerSingleton<NotificationActionBloc>(NotificationActionBloc());
|
||||
getIt.registerSingleton<ActionNavigationBloc>(ActionNavigationBloc());
|
||||
|
||||
getIt.registerLazySingleton<TabsBloc>(() => TabsBloc());
|
||||
|
||||
|
@ -1,25 +1,27 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:appflowy/mobile/application/mobile_router.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
|
||||
import 'package:appflowy/user/application/user_settings_service.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_service.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/notification/notification_service.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/sidebar/rename_view/rename_view_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||
import 'package:appflowy/workspace/presentation/command_palette/command_palette.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
@ -150,12 +152,15 @@ class _ApplicationWidgetState extends State<ApplicationWidget> {
|
||||
create: (_) => DocumentAppearanceCubit()..fetch(),
|
||||
),
|
||||
BlocProvider.value(value: getIt<RenameViewBloc>()),
|
||||
BlocProvider.value(value: getIt<NotificationActionBloc>()),
|
||||
BlocProvider.value(
|
||||
value: getIt<ActionNavigationBloc>()
|
||||
..add(const ActionNavigationEvent.initialize()),
|
||||
),
|
||||
BlocProvider.value(
|
||||
value: getIt<ReminderBloc>()..add(const ReminderEvent.started()),
|
||||
),
|
||||
],
|
||||
child: BlocListener<NotificationActionBloc, NotificationActionState>(
|
||||
child: BlocListener<ActionNavigationBloc, ActionNavigationState>(
|
||||
listenWhen: (_, curr) => curr.action != null,
|
||||
listener: (context, state) {
|
||||
final action = state.action;
|
||||
@ -189,7 +194,13 @@ class _ApplicationWidgetState extends State<ApplicationWidget> {
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: TextScaler.linear(state.textScaleFactor),
|
||||
),
|
||||
child: overlayManagerBuilder(context, child),
|
||||
child: overlayManagerBuilder(
|
||||
context,
|
||||
CommandPalette(
|
||||
toggleNotifier: ValueNotifier<bool>(false),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: state.lightTheme,
|
||||
|
@ -6,9 +6,9 @@ import 'package:appflowy/user/application/reminder/reminder_extension.dart';
|
||||
import 'package:appflowy/user/application/reminder/reminder_service.dart';
|
||||
import 'package:appflowy/user/application/user_settings_service.dart';
|
||||
import 'package:appflowy/util/int64_extension.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_service.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/notification/notification_service.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
@ -22,14 +22,14 @@ part 'reminder_bloc.freezed.dart';
|
||||
|
||||
class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
|
||||
ReminderBloc() : super(ReminderState()) {
|
||||
_actionBloc = getIt<NotificationActionBloc>();
|
||||
_actionBloc = getIt<ActionNavigationBloc>();
|
||||
_reminderService = const ReminderService();
|
||||
timer = _periodicCheck();
|
||||
|
||||
_dispatch();
|
||||
}
|
||||
|
||||
late final NotificationActionBloc _actionBloc;
|
||||
late final ActionNavigationBloc _actionBloc;
|
||||
late final ReminderService _reminderService;
|
||||
late final Timer timer;
|
||||
|
||||
@ -147,7 +147,7 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
|
||||
rowId = reminder.meta[ReminderMetaKeys.rowId];
|
||||
}
|
||||
|
||||
final action = NotificationAction(
|
||||
final action = NavigationAction(
|
||||
objectId: reminder.objectId,
|
||||
arguments: {
|
||||
ActionArgumentKeys.view: view,
|
||||
@ -158,7 +158,7 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
|
||||
|
||||
if (!isClosed) {
|
||||
_actionBloc.add(
|
||||
NotificationActionEvent.performAction(
|
||||
ActionNavigationEvent.performAction(
|
||||
action: action,
|
||||
nextActions: [
|
||||
action.copyWith(
|
||||
@ -198,8 +198,8 @@ class ReminderBloc extends Bloc<ReminderEvent, ReminderState> {
|
||||
title: LocaleKeys.reminderNotification_title.tr(),
|
||||
body: LocaleKeys.reminderNotification_message.tr(),
|
||||
onClick: () => _actionBloc.add(
|
||||
NotificationActionEvent.performAction(
|
||||
action: NotificationAction(objectId: reminder.objectId),
|
||||
ActionNavigationEvent.performAction(
|
||||
action: NavigationAction(objectId: reminder.objectId),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -0,0 +1,134 @@
|
||||
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/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:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'action_navigation_bloc.freezed.dart';
|
||||
|
||||
class ActionNavigationBloc
|
||||
extends Bloc<ActionNavigationEvent, ActionNavigationState> {
|
||||
ActionNavigationBloc() : super(const ActionNavigationState.initial()) {
|
||||
on<ActionNavigationEvent>((event, emit) async {
|
||||
await event.when(
|
||||
initialize: () async {
|
||||
final views = await ViewBackendService().fetchViews();
|
||||
emit(state.copyWith(views: views));
|
||||
await initializeListeners();
|
||||
},
|
||||
viewsChanged: (views) {
|
||||
emit(state.copyWith(views: views));
|
||||
},
|
||||
performAction: (action, nextActions) {
|
||||
emit(state.copyWith(action: action, nextActions: nextActions));
|
||||
|
||||
if (nextActions.isNotEmpty) {
|
||||
final newActions = [...nextActions];
|
||||
final next = newActions.removeAt(0);
|
||||
|
||||
add(
|
||||
ActionNavigationEvent.performAction(
|
||||
action: next,
|
||||
nextActions: newActions,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
emit(state.setNoAction());
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
class ActionNavigationEvent with _$ActionNavigationEvent {
|
||||
const factory ActionNavigationEvent.initialize() = _Initialize;
|
||||
|
||||
const factory ActionNavigationEvent.performAction({
|
||||
required NavigationAction action,
|
||||
@Default([]) List<NavigationAction> nextActions,
|
||||
}) = _PerformAction;
|
||||
|
||||
const factory ActionNavigationEvent.viewsChanged(List<ViewPB> views) =
|
||||
_ViewsChanged;
|
||||
}
|
||||
|
||||
class ActionNavigationState {
|
||||
const ActionNavigationState.initial()
|
||||
: action = null,
|
||||
nextActions = const [],
|
||||
views = const [];
|
||||
|
||||
const ActionNavigationState({
|
||||
required this.action,
|
||||
this.nextActions = const [],
|
||||
this.views = const [],
|
||||
});
|
||||
|
||||
final NavigationAction? action;
|
||||
final List<NavigationAction> nextActions;
|
||||
final List<ViewPB> views;
|
||||
|
||||
ActionNavigationState copyWith({
|
||||
NavigationAction? action,
|
||||
List<NavigationAction>? nextActions,
|
||||
List<ViewPB>? views,
|
||||
}) =>
|
||||
ActionNavigationState(
|
||||
action: action ?? this.action,
|
||||
nextActions: nextActions ?? this.nextActions,
|
||||
views: views ?? this.views,
|
||||
);
|
||||
|
||||
ActionNavigationState setNoAction() =>
|
||||
ActionNavigationState(action: null, nextActions: [], views: views);
|
||||
}
|
@ -10,13 +10,13 @@ class ActionArgumentKeys {
|
||||
static String rowId = "row_id";
|
||||
}
|
||||
|
||||
/// A [NotificationAction] is used to communicate with the
|
||||
/// [NotificationActionBloc] to perform actions based on an event
|
||||
/// A [NavigationAction] is used to communicate with the
|
||||
/// [ActionNavigationBloc] to perform actions based on an event
|
||||
/// triggered by pressing a notification, such as opening a specific
|
||||
/// view and jumping to a specific block.
|
||||
///
|
||||
class NotificationAction {
|
||||
const NotificationAction({
|
||||
class NavigationAction {
|
||||
const NavigationAction({
|
||||
this.type = ActionType.openView,
|
||||
this.arguments,
|
||||
required this.objectId,
|
||||
@ -27,12 +27,12 @@ class NotificationAction {
|
||||
final String objectId;
|
||||
final Map<String, dynamic>? arguments;
|
||||
|
||||
NotificationAction copyWith({
|
||||
NavigationAction copyWith({
|
||||
ActionType? type,
|
||||
String? objectId,
|
||||
Map<String, dynamic>? arguments,
|
||||
}) =>
|
||||
NotificationAction(
|
||||
NavigationAction(
|
||||
type: type ?? this.type,
|
||||
objectId: objectId ?? this.objectId,
|
||||
arguments: arguments ?? this.arguments,
|
@ -0,0 +1,180 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:appflowy/plugins/trash/application/trash_listener.dart';
|
||||
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_service.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/trash.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'command_palette_bloc.freezed.dart';
|
||||
|
||||
class CommandPaletteBloc
|
||||
extends Bloc<CommandPaletteEvent, CommandPaletteState> {
|
||||
CommandPaletteBloc() : super(CommandPaletteState.initial()) {
|
||||
_searchListener.start(
|
||||
onResultsChanged: _onResultsChanged,
|
||||
onResultsClosed: _onResultsClosed,
|
||||
);
|
||||
|
||||
_initTrash();
|
||||
_dispatch();
|
||||
}
|
||||
|
||||
Timer? _debounceOnChanged;
|
||||
final TrashService _trashService = TrashService();
|
||||
final SearchListener _searchListener = SearchListener();
|
||||
final TrashListener _trashListener = TrashListener();
|
||||
String? _oldQuery;
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_trashListener.close();
|
||||
_searchListener.stop();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _dispatch() {
|
||||
on<CommandPaletteEvent>((event, emit) async {
|
||||
event.when(
|
||||
searchChanged: _debounceOnSearchChanged,
|
||||
trashChanged: (trash) async {
|
||||
if (trash != null) {
|
||||
emit(state.copyWith(trash: trash));
|
||||
return;
|
||||
}
|
||||
|
||||
final trashOrFailure = await _trashService.readTrash();
|
||||
final trashRes = trashOrFailure.fold(
|
||||
(trash) => trash,
|
||||
(error) => null,
|
||||
);
|
||||
|
||||
if (trashRes != null) {
|
||||
emit(state.copyWith(trash: trashRes.items));
|
||||
}
|
||||
},
|
||||
performSearch: (search) async {
|
||||
if (search.isNotEmpty) {
|
||||
_oldQuery = state.query;
|
||||
emit(state.copyWith(query: search, isLoading: true));
|
||||
await SearchBackendService.performSearch(search);
|
||||
} else {
|
||||
emit(state.copyWith(query: null, isLoading: false, results: []));
|
||||
}
|
||||
},
|
||||
resultsChanged: (results, didClose) {
|
||||
if (state.query != _oldQuery) {
|
||||
emit(state.copyWith(results: []));
|
||||
}
|
||||
|
||||
final searchResults = _filterDuplicates(results.items);
|
||||
searchResults.sort((a, b) => b.score.compareTo(a.score));
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
results: searchResults,
|
||||
isLoading: !didClose,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _initTrash() async {
|
||||
_trashListener.start(
|
||||
trashUpdated: (trashOrFailed) {
|
||||
final trash = trashOrFailed.fold(
|
||||
(trash) => trash,
|
||||
(error) => null,
|
||||
);
|
||||
|
||||
add(CommandPaletteEvent.trashChanged(trash: trash));
|
||||
},
|
||||
);
|
||||
|
||||
final trashOrFailure = await _trashService.readTrash();
|
||||
final trashRes = trashOrFailure.fold(
|
||||
(trash) => trash,
|
||||
(error) => null,
|
||||
);
|
||||
|
||||
add(CommandPaletteEvent.trashChanged(trash: trashRes?.items));
|
||||
}
|
||||
|
||||
void _debounceOnSearchChanged(String value) {
|
||||
_debounceOnChanged?.cancel();
|
||||
_debounceOnChanged = Timer(
|
||||
const Duration(milliseconds: 300),
|
||||
() => _performSearch(value),
|
||||
);
|
||||
}
|
||||
|
||||
List<SearchResultPB> _filterDuplicates(List<SearchResultPB> results) {
|
||||
final currentItems = [...state.results];
|
||||
final res = [...results];
|
||||
|
||||
for (final item in results) {
|
||||
final duplicateIndex = currentItems.indexWhere((a) => a.id == item.id);
|
||||
if (duplicateIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final duplicate = currentItems[duplicateIndex];
|
||||
if (item.score < duplicate.score) {
|
||||
res.remove(item);
|
||||
} else {
|
||||
currentItems.remove(duplicate);
|
||||
}
|
||||
}
|
||||
|
||||
return res..addAll(currentItems);
|
||||
}
|
||||
|
||||
void _performSearch(String value) =>
|
||||
add(CommandPaletteEvent.performSearch(search: value));
|
||||
|
||||
void _onResultsChanged(RepeatedSearchResultPB results) =>
|
||||
add(CommandPaletteEvent.resultsChanged(results: results));
|
||||
|
||||
void _onResultsClosed(RepeatedSearchResultPB results) =>
|
||||
add(CommandPaletteEvent.resultsChanged(results: results, didClose: true));
|
||||
}
|
||||
|
||||
@freezed
|
||||
class CommandPaletteEvent with _$CommandPaletteEvent {
|
||||
const factory CommandPaletteEvent.searchChanged({required String search}) =
|
||||
_SearchChanged;
|
||||
|
||||
const factory CommandPaletteEvent.performSearch({required String search}) =
|
||||
_PerformSearch;
|
||||
|
||||
const factory CommandPaletteEvent.resultsChanged({
|
||||
required RepeatedSearchResultPB results,
|
||||
@Default(false) bool didClose,
|
||||
}) = _ResultsChanged;
|
||||
|
||||
const factory CommandPaletteEvent.trashChanged({
|
||||
@Default(null) List<TrashPB>? trash,
|
||||
}) = _TrashChanged;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class CommandPaletteState with _$CommandPaletteState {
|
||||
const CommandPaletteState._();
|
||||
|
||||
const factory CommandPaletteState({
|
||||
@Default(null) String? query,
|
||||
required List<SearchResultPB> results,
|
||||
required bool isLoading,
|
||||
@Default([]) List<TrashPB> trash,
|
||||
}) = _CommandPaletteState;
|
||||
|
||||
factory CommandPaletteState.initial() =>
|
||||
const CommandPaletteState(results: [], isLoading: false);
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/core/notification/search_notification.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart';
|
||||
import 'package:appflowy_result/appflowy_result.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
|
||||
// Do not modify!
|
||||
const _searchObjectId = "SEARCH_IDENTIFIER";
|
||||
|
||||
class SearchListener {
|
||||
SearchListener();
|
||||
|
||||
PublishNotifier<RepeatedSearchResultPB>? _updateNotifier = PublishNotifier();
|
||||
PublishNotifier<RepeatedSearchResultPB>? _updateDidCloseNotifier =
|
||||
PublishNotifier();
|
||||
SearchNotificationListener? _listener;
|
||||
|
||||
void start({
|
||||
required void Function(RepeatedSearchResultPB) onResultsChanged,
|
||||
required void Function(RepeatedSearchResultPB) onResultsClosed,
|
||||
}) {
|
||||
_updateNotifier?.addPublishListener(onResultsChanged);
|
||||
_updateDidCloseNotifier?.addPublishListener(onResultsClosed);
|
||||
_listener = SearchNotificationListener(
|
||||
objectId: _searchObjectId,
|
||||
handler: _handler,
|
||||
);
|
||||
}
|
||||
|
||||
void _handler(
|
||||
SearchNotification ty,
|
||||
FlowyResult<Uint8List, FlowyError> result,
|
||||
) {
|
||||
switch (ty) {
|
||||
case SearchNotification.DidUpdateResults:
|
||||
result.fold(
|
||||
(payload) => _updateNotifier?.value =
|
||||
RepeatedSearchResultPB.fromBuffer(payload),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
break;
|
||||
case SearchNotification.DidCloseResults:
|
||||
result.fold(
|
||||
(payload) => _updateDidCloseNotifier?.value =
|
||||
RepeatedSearchResultPB.fromBuffer(payload),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
await _listener?.stop();
|
||||
_updateNotifier?.dispose();
|
||||
_updateNotifier = null;
|
||||
_updateDidCloseNotifier?.dispose();
|
||||
_updateDidCloseNotifier = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart';
|
||||
|
||||
extension GetIcon on SearchResultPB {
|
||||
Widget? getIcon() {
|
||||
if (icon.ty == ResultIconTypePB.Emoji) {
|
||||
return icon.value.isNotEmpty
|
||||
? Text(
|
||||
icon.value,
|
||||
style: const TextStyle(fontSize: 18.0),
|
||||
)
|
||||
: null;
|
||||
} else if (icon.ty == ResultIconTypePB.Icon) {
|
||||
return FlowySvg(icon.getViewSvg(), size: const Size.square(20));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
extension _ToViewIcon on ResultIconPB {
|
||||
FlowySvgData getViewSvg() => switch (value) {
|
||||
"0" => FlowySvgs.document_s,
|
||||
"1" => FlowySvgs.grid_s,
|
||||
"2" => FlowySvgs.board_s,
|
||||
"3" => FlowySvgs.date_s,
|
||||
_ => FlowySvgs.document_s,
|
||||
};
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart';
|
||||
import 'package:appflowy_result/appflowy_result.dart';
|
||||
|
||||
class SearchBackendService {
|
||||
static Future<FlowyResult<void, FlowyError>> performSearch(
|
||||
String keyword,
|
||||
) async {
|
||||
final request = SearchQueryPB(search: keyword);
|
||||
|
||||
return SearchEventSearch(request).send();
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:local_notifier/local_notifier.dart';
|
||||
|
||||
const _appName = "AppFlowy";
|
||||
@ -12,9 +13,7 @@ const _appName = "AppFlowy";
|
||||
///
|
||||
class NotificationService {
|
||||
static Future<void> initialize() async {
|
||||
await localNotifier.setup(
|
||||
appName: _appName,
|
||||
);
|
||||
await localNotifier.setup(appName: _appName);
|
||||
}
|
||||
}
|
||||
|
@ -1,61 +0,0 @@
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'notification_action_bloc.freezed.dart';
|
||||
|
||||
class NotificationActionBloc
|
||||
extends Bloc<NotificationActionEvent, NotificationActionState> {
|
||||
NotificationActionBloc() : super(const NotificationActionState.initial()) {
|
||||
on<NotificationActionEvent>((event, emit) async {
|
||||
event.when(
|
||||
performAction: (action, nextActions) {
|
||||
emit(state.copyWith(action: action, nextActions: nextActions));
|
||||
|
||||
if (nextActions.isNotEmpty) {
|
||||
final newActions = [...nextActions];
|
||||
final next = newActions.removeAt(0);
|
||||
|
||||
add(
|
||||
NotificationActionEvent.performAction(
|
||||
action: next,
|
||||
nextActions: newActions,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class NotificationActionEvent with _$NotificationActionEvent {
|
||||
const factory NotificationActionEvent.performAction({
|
||||
required NotificationAction action,
|
||||
@Default([]) List<NotificationAction> nextActions,
|
||||
}) = _PerformAction;
|
||||
}
|
||||
|
||||
class NotificationActionState {
|
||||
const NotificationActionState.initial()
|
||||
: action = null,
|
||||
nextActions = const [];
|
||||
|
||||
const NotificationActionState({
|
||||
required this.action,
|
||||
this.nextActions = const [],
|
||||
});
|
||||
|
||||
final NotificationAction? action;
|
||||
final List<NotificationAction> nextActions;
|
||||
|
||||
NotificationActionState copyWith({
|
||||
NotificationAction? action,
|
||||
List<NotificationAction>? nextActions,
|
||||
}) =>
|
||||
NotificationActionState(
|
||||
action: action ?? this.action,
|
||||
nextActions: nextActions ?? this.nextActions,
|
||||
);
|
||||
}
|
@ -29,9 +29,7 @@ class RecentViewsBloc extends Bloc<RecentViewsEvent, RecentViewsState> {
|
||||
await event.map(
|
||||
initial: (e) async {
|
||||
_listener.start(
|
||||
recentViewsUpdated: (result) => _onRecentViewsUpdated(
|
||||
result,
|
||||
),
|
||||
recentViewsUpdated: (result) => _onRecentViewsUpdated(result),
|
||||
);
|
||||
add(const RecentViewsEvent.fetchRecentViews());
|
||||
},
|
||||
|
@ -167,9 +167,10 @@ class ViewBackendService {
|
||||
static Future<FlowyResult<void, FlowyError>> updateViewIcon({
|
||||
required String viewId,
|
||||
required String viewIcon,
|
||||
ViewIconTypePB iconType = ViewIconTypePB.Emoji,
|
||||
}) {
|
||||
final icon = ViewIconPB()
|
||||
..ty = ViewIconTypePB.Emoji
|
||||
..ty = iconType
|
||||
..value = viewIcon;
|
||||
final payload = UpdateViewIconPayloadPB.create()
|
||||
..viewId = viewId
|
||||
|
@ -0,0 +1,243 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/command_palette/command_palette_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/command_palette/widgets/recent_views_list.dart';
|
||||
import 'package:appflowy/workspace/presentation/command_palette/widgets/search_field.dart';
|
||||
import 'package:appflowy/workspace/presentation/command_palette/widgets/search_results_list.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class CommandPalette extends InheritedWidget {
|
||||
CommandPalette({
|
||||
super.key,
|
||||
required Widget? child,
|
||||
required ValueNotifier<bool> toggleNotifier,
|
||||
}) : _toggleNotifier = toggleNotifier,
|
||||
super(
|
||||
child: _CommandPaletteController(
|
||||
toggleNotifier: toggleNotifier,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
|
||||
final ValueNotifier<bool> _toggleNotifier;
|
||||
|
||||
void toggle() => _toggleNotifier.value = !_toggleNotifier.value;
|
||||
|
||||
static CommandPalette of(BuildContext context) {
|
||||
final CommandPalette? result =
|
||||
context.dependOnInheritedWidgetOfExactType<CommandPalette>();
|
||||
|
||||
assert(result != null, "CommandPalette could not be found");
|
||||
|
||||
return result!;
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(covariant InheritedWidget oldWidget) => false;
|
||||
}
|
||||
|
||||
class _ToggleCommandPaletteIntent extends Intent {
|
||||
const _ToggleCommandPaletteIntent();
|
||||
}
|
||||
|
||||
class _CommandPaletteController extends StatefulWidget {
|
||||
const _CommandPaletteController({
|
||||
required this.toggleNotifier,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final Widget? child;
|
||||
final ValueNotifier<bool> toggleNotifier;
|
||||
|
||||
@override
|
||||
State<_CommandPaletteController> createState() =>
|
||||
_CommandPaletteControllerState();
|
||||
}
|
||||
|
||||
class _CommandPaletteControllerState extends State<_CommandPaletteController> {
|
||||
late final CommandPaletteBloc _commandPaletteBloc;
|
||||
late ValueNotifier<bool> _toggleNotifier = widget.toggleNotifier;
|
||||
bool _isOpen = false;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant _CommandPaletteController oldWidget) {
|
||||
if (oldWidget.toggleNotifier != widget.toggleNotifier) {
|
||||
_toggleNotifier.removeListener(_onToggle);
|
||||
_toggleNotifier.dispose();
|
||||
_toggleNotifier = widget.toggleNotifier;
|
||||
|
||||
// If widget is changed, eg. on theme mode hotkey used
|
||||
// while modal is shown, set the value before listening
|
||||
_toggleNotifier.value = _isOpen;
|
||||
|
||||
_toggleNotifier.addListener(_onToggle);
|
||||
}
|
||||
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_toggleNotifier.addListener(_onToggle);
|
||||
_commandPaletteBloc = CommandPaletteBloc();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_toggleNotifier.removeListener(_onToggle);
|
||||
_toggleNotifier.dispose();
|
||||
_commandPaletteBloc.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onToggle() {
|
||||
if (widget.toggleNotifier.value && !_isOpen) {
|
||||
_isOpen = true;
|
||||
FlowyOverlay.show(
|
||||
context: context,
|
||||
builder: (_) => BlocProvider.value(
|
||||
value: _commandPaletteBloc,
|
||||
child: CommandPaletteModal(shortcutBuilder: _buildShortcut),
|
||||
),
|
||||
).then((_) {
|
||||
_isOpen = false;
|
||||
widget.toggleNotifier.value = false;
|
||||
});
|
||||
} else if (!widget.toggleNotifier.value && _isOpen) {
|
||||
FlowyOverlay.pop(context);
|
||||
_isOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) =>
|
||||
_buildShortcut(widget.child ?? const SizedBox.shrink());
|
||||
|
||||
Widget _buildShortcut(Widget child) => FocusableActionDetector(
|
||||
actions: {
|
||||
_ToggleCommandPaletteIntent:
|
||||
CallbackAction<_ToggleCommandPaletteIntent>(
|
||||
onInvoke: (intent) =>
|
||||
_toggleNotifier.value = !_toggleNotifier.value,
|
||||
),
|
||||
},
|
||||
shortcuts: {
|
||||
LogicalKeySet(
|
||||
PlatformExtension.isMacOS
|
||||
? LogicalKeyboardKey.meta
|
||||
: LogicalKeyboardKey.control,
|
||||
LogicalKeyboardKey.keyP,
|
||||
): const _ToggleCommandPaletteIntent(),
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
class CommandPaletteModal extends StatelessWidget {
|
||||
const CommandPaletteModal({super.key, required this.shortcutBuilder});
|
||||
|
||||
final Widget Function(Widget) shortcutBuilder;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<CommandPaletteBloc, CommandPaletteState>(
|
||||
builder: (context, state) {
|
||||
return FlowyDialog(
|
||||
alignment: Alignment.topCenter,
|
||||
insetPadding: const EdgeInsets.only(top: 100),
|
||||
constraints: const BoxConstraints(maxHeight: 420, maxWidth: 510),
|
||||
expandHeight: false,
|
||||
child: shortcutBuilder(
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SearchField(query: state.query, isLoading: state.isLoading),
|
||||
if ((state.query?.isEmpty ?? true) ||
|
||||
state.isLoading && state.results.isEmpty) ...[
|
||||
const Divider(height: 0),
|
||||
Flexible(
|
||||
child: RecentViewsList(
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CommandPaletteFooter extends StatelessWidget {
|
||||
const _CommandPaletteFooter({
|
||||
required this.shouldShow,
|
||||
});
|
||||
|
||||
final bool shouldShow;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!shouldShow) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 5,
|
||||
vertical: 1,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: AFThemeExtension.of(context).lightGreyHover,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: const FlowyText.semibold(
|
||||
'TAB',
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
const HSpace(4),
|
||||
FlowyText(
|
||||
LocaleKeys.commandPalette_navigateHint.tr(),
|
||||
fontSize: 11,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import 'package:flutter/material.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/navigation_action.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
|
||||
class RecentViewTile extends StatelessWidget {
|
||||
const RecentViewTile({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.view,
|
||||
required this.onSelected,
|
||||
});
|
||||
|
||||
final Widget icon;
|
||||
final ViewPB view;
|
||||
final VoidCallback onSelected;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
dense: true,
|
||||
title: Row(
|
||||
children: [
|
||||
icon,
|
||||
const HSpace(4),
|
||||
FlowyText(view.name),
|
||||
],
|
||||
),
|
||||
focusColor: Theme.of(context).colorScheme.primary.withOpacity(0.5),
|
||||
hoverColor: Theme.of(context).colorScheme.primary.withOpacity(0.5),
|
||||
onTap: () {
|
||||
onSelected();
|
||||
|
||||
getIt<ActionNavigationBloc>().add(
|
||||
ActionNavigationEvent.performAction(
|
||||
action: NavigationAction(objectId: view.id),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/recent/recent_views_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||
import 'package:appflowy/workspace/presentation/command_palette/widgets/recent_view_tile.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class RecentViewsList extends StatelessWidget {
|
||||
const RecentViewsList({super.key, required this.onSelected});
|
||||
|
||||
final VoidCallback onSelected;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) =>
|
||||
RecentViewsBloc()..add(const RecentViewsEvent.initial()),
|
||||
child: BlocBuilder<RecentViewsBloc, RecentViewsState>(
|
||||
builder: (context, state) {
|
||||
// We remove duplicates by converting the list to a set first
|
||||
final List<ViewPB> recentViews =
|
||||
state.views.reversed.toSet().toList();
|
||||
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
itemCount: recentViews.length + 1,
|
||||
itemBuilder: (_, index) {
|
||||
if (index == 0) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
child: FlowyText(
|
||||
LocaleKeys.commandPalette_recentHistory.tr(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final view = recentViews[index - 1];
|
||||
final icon = view.icon.value.isNotEmpty
|
||||
? Text(
|
||||
view.icon.value,
|
||||
style: const TextStyle(fontSize: 18.0),
|
||||
)
|
||||
: FlowySvg(view.iconData, size: const Size.square(20));
|
||||
|
||||
return RecentViewTile(
|
||||
icon: icon,
|
||||
view: view,
|
||||
onSelected: onSelected,
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, __) => const Divider(height: 0),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/workspace/application/command_palette/command_palette_bloc.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/size.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_field.dart';
|
||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class SearchField extends StatelessWidget {
|
||||
const SearchField({super.key, this.query, this.isLoading = false});
|
||||
|
||||
final String? query;
|
||||
final bool isLoading;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
const HSpace(12),
|
||||
FlowySvg(
|
||||
FlowySvgs.search_m,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
Expanded(
|
||||
child: FlowyTextField(
|
||||
controller: TextEditingController(text: query),
|
||||
textStyle:
|
||||
Theme.of(context).textTheme.bodySmall?.copyWith(fontSize: 14),
|
||||
decoration: InputDecoration(
|
||||
constraints: const BoxConstraints(maxHeight: 48),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.transparent),
|
||||
borderRadius: Corners.s8Border,
|
||||
),
|
||||
isDense: false,
|
||||
hintText: LocaleKeys.commandPalette_placeholder.tr(),
|
||||
hintStyle: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
errorStyle: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(color: Theme.of(context).colorScheme.error),
|
||||
// TODO(Mathias): Remove beta when support document/database search
|
||||
suffix: FlowyTooltip(
|
||||
message: LocaleKeys.commandPalette_betaTooltip.tr(),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 5,
|
||||
vertical: 1,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: AFThemeExtension.of(context).lightGreyHover,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: FlowyText.semibold(
|
||||
LocaleKeys.commandPalette_betaLabel.tr(),
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
counterText: "",
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.transparent),
|
||||
borderRadius: Corners.s8Border,
|
||||
),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
borderRadius: Corners.s8Border,
|
||||
),
|
||||
),
|
||||
onChanged: (value) => context
|
||||
.read<CommandPaletteBloc>()
|
||||
.add(CommandPaletteEvent.searchChanged(search: value)),
|
||||
),
|
||||
),
|
||||
if (isLoading) ...[
|
||||
const HSpace(12),
|
||||
FlowyTooltip(
|
||||
message: LocaleKeys.commandPalette_loadingTooltip.tr(),
|
||||
child: const SizedBox(
|
||||
width: 16,
|
||||
height: 16,
|
||||
child: CircularProgressIndicator(strokeWidth: 2.5),
|
||||
),
|
||||
),
|
||||
const HSpace(12),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.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/navigation_action.dart';
|
||||
import 'package:appflowy/workspace/application/command_palette/search_result_ext.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-search/entities.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
|
||||
class SearchResultTile extends StatelessWidget {
|
||||
const SearchResultTile({
|
||||
super.key,
|
||||
required this.result,
|
||||
required this.onSelected,
|
||||
this.isTrashed = false,
|
||||
});
|
||||
|
||||
final SearchResultPB result;
|
||||
final VoidCallback onSelected;
|
||||
final bool isTrashed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final icon = result.getIcon();
|
||||
|
||||
return ListTile(
|
||||
dense: true,
|
||||
title: Row(
|
||||
children: [
|
||||
if (icon != null) ...[icon, const HSpace(6)],
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (isTrashed) ...[
|
||||
FlowyText(
|
||||
LocaleKeys.commandPalette_fromTrashHint.tr(),
|
||||
color: AFThemeExtension.of(context).textColor.withAlpha(175),
|
||||
fontSize: 10,
|
||||
),
|
||||
],
|
||||
FlowyText(result.data),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
focusColor: Theme.of(context).colorScheme.primary.withOpacity(0.5),
|
||||
hoverColor: Theme.of(context).colorScheme.primary.withOpacity(0.5),
|
||||
onTap: () {
|
||||
onSelected();
|
||||
|
||||
getIt<ActionNavigationBloc>().add(
|
||||
ActionNavigationEvent.performAction(
|
||||
action: NavigationAction(objectId: result.viewId),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.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-search/entities.pb.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
|
||||
class SearchResultsList extends StatelessWidget {
|
||||
const SearchResultsList({
|
||||
super.key,
|
||||
required this.trash,
|
||||
required this.results,
|
||||
});
|
||||
|
||||
final List<TrashPB> trash;
|
||||
final List<SearchResultPB> results;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
separatorBuilder: (_, __) => const Divider(height: 0),
|
||||
itemCount: results.length + 1,
|
||||
itemBuilder: (_, index) {
|
||||
if (index == 0) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8) +
|
||||
const EdgeInsets.only(left: 16),
|
||||
child: FlowyText(
|
||||
LocaleKeys.commandPalette_bestMatches.tr(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final result = results[index - 1];
|
||||
return SearchResultTile(
|
||||
result: result,
|
||||
onSelected: () => FlowyOverlay.pop(context),
|
||||
isTrashed: trash.any((t) => t.id == result.viewId),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/startup/startup.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/sidebar/rename_view/rename_view_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_setting.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hotkey_manager/hotkey_manager.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.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/navigation_action.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/prelude.dart';
|
||||
import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action.dart';
|
||||
import 'package:appflowy/workspace/application/notifications/notification_action_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/view/view_ext.dart';
|
||||
@ -20,7 +21,6 @@ import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
|
||||
show UserProfilePB;
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
/// Home Sidebar is the left side bar of the home page.
|
||||
@ -74,9 +74,7 @@ class HomeSideBar extends StatelessWidget {
|
||||
}
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (_) => getIt<NotificationActionBloc>(),
|
||||
),
|
||||
BlocProvider(create: (_) => getIt<ActionNavigationBloc>()),
|
||||
BlocProvider(
|
||||
create: (_) => SidebarSectionsBloc()
|
||||
..add(
|
||||
@ -99,7 +97,7 @@ class HomeSideBar extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
BlocListener<NotificationActionBloc, NotificationActionState>(
|
||||
BlocListener<ActionNavigationBloc, ActionNavigationState>(
|
||||
listenWhen: (_, curr) => curr.action != null,
|
||||
listener: _onNotificationAction,
|
||||
),
|
||||
@ -134,35 +132,28 @@ class HomeSideBar extends StatelessWidget {
|
||||
|
||||
void _onNotificationAction(
|
||||
BuildContext context,
|
||||
NotificationActionState state,
|
||||
ActionNavigationState state,
|
||||
) {
|
||||
final action = state.action;
|
||||
if (action != null) {
|
||||
if (action.type == ActionType.openView) {
|
||||
final view = context
|
||||
.read<SidebarSectionsBloc>()
|
||||
.state
|
||||
.section
|
||||
.publicViews
|
||||
.findView(action.objectId);
|
||||
if (action?.type == ActionType.openView) {
|
||||
final view = state.views.findView(action!.objectId);
|
||||
|
||||
if (view != null) {
|
||||
final Map<String, dynamic> arguments = {};
|
||||
if (view != null) {
|
||||
final Map<String, dynamic> arguments = {};
|
||||
|
||||
final nodePath = action.arguments?[ActionArgumentKeys.nodePath];
|
||||
if (nodePath != null) {
|
||||
arguments[PluginArgumentKeys.selection] = Selection.collapsed(
|
||||
Position(path: [nodePath]),
|
||||
);
|
||||
}
|
||||
|
||||
final rowId = action.arguments?[ActionArgumentKeys.rowId];
|
||||
if (rowId != null) {
|
||||
arguments[PluginArgumentKeys.rowId] = rowId;
|
||||
}
|
||||
|
||||
context.read<TabsBloc>().openPlugin(view, arguments: arguments);
|
||||
final nodePath = action.arguments?[ActionArgumentKeys.nodePath];
|
||||
if (nodePath != null) {
|
||||
arguments[PluginArgumentKeys.selection] = Selection.collapsed(
|
||||
Position(path: [nodePath]),
|
||||
);
|
||||
}
|
||||
|
||||
final rowId = action.arguments?[ActionArgumentKeys.rowId];
|
||||
if (rowId != null) {
|
||||
arguments[PluginArgumentKeys.rowId] = rowId;
|
||||
}
|
||||
|
||||
context.read<TabsBloc>().openPlugin(view, arguments: arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
|
||||
@ -17,13 +19,13 @@ import 'package:appflowy/workspace/presentation/home/menu/view/view_add_button.d
|
||||
import 'package:appflowy/workspace/presentation/home/menu/view/view_more_action_button.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/rename_view_popover.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
typedef ViewItemOnSelected = void Function(ViewPB);
|
||||
@ -485,6 +487,7 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
|
||||
ViewBackendService.updateViewIcon(
|
||||
viewId: widget.view.id,
|
||||
viewIcon: result.emoji,
|
||||
iconType: result.type.toProto(),
|
||||
);
|
||||
controller.close();
|
||||
},
|
||||
|
@ -3,6 +3,8 @@ import 'dart:convert' show utf8;
|
||||
import 'dart:ffi';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:appflowy_backend/ffi.dart' as ffi;
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
// ignore: unnecessary_import
|
||||
@ -15,7 +17,6 @@ import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:appflowy_result/appflowy_result.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:isolates/isolates.dart';
|
||||
import 'package:isolates/ports.dart';
|
||||
import 'package:protobuf/protobuf.dart';
|
||||
@ -24,14 +25,18 @@ import '../protobuf/flowy-config/entities.pb.dart';
|
||||
import '../protobuf/flowy-config/event_map.pb.dart';
|
||||
import '../protobuf/flowy-date/entities.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';
|
||||
|
||||
part 'dart_event/flowy-config/dart_event.dart';
|
||||
part 'dart_event/flowy-database2/dart_event.dart';
|
||||
part 'dart_event/flowy-date/dart_event.dart';
|
||||
part 'dart_event/flowy-document/dart_event.dart';
|
||||
part 'dart_event/flowy-folder/dart_event.dart';
|
||||
part 'dart_event/flowy-user/dart_event.dart';
|
||||
part 'dart_event/flowy-database2/dart_event.dart';
|
||||
part 'dart_event/flowy-document/dart_event.dart';
|
||||
part 'dart_event/flowy-config/dart_event.dart';
|
||||
part 'dart_event/flowy-date/dart_event.dart';
|
||||
part 'dart_event/flowy-search/dart_event.dart';
|
||||
|
||||
enum FFIException {
|
||||
RequestIsEmpty,
|
||||
|
@ -5,6 +5,8 @@ import 'package:flutter/material.dart';
|
||||
const _overlayContainerPadding = EdgeInsets.symmetric(vertical: 12);
|
||||
const overlayContainerMaxWidth = 760.0;
|
||||
const overlayContainerMinWidth = 320.0;
|
||||
const _defaultInsetPadding =
|
||||
EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0);
|
||||
|
||||
class FlowyDialog extends StatelessWidget {
|
||||
const FlowyDialog({
|
||||
@ -15,6 +17,9 @@ class FlowyDialog extends StatelessWidget {
|
||||
this.constraints,
|
||||
this.padding = _overlayContainerPadding,
|
||||
this.backgroundColor,
|
||||
this.expandHeight = true,
|
||||
this.alignment,
|
||||
this.insetPadding,
|
||||
this.width,
|
||||
});
|
||||
|
||||
@ -24,32 +29,43 @@ class FlowyDialog extends StatelessWidget {
|
||||
final BoxConstraints? constraints;
|
||||
final EdgeInsets padding;
|
||||
final Color? backgroundColor;
|
||||
final bool expandHeight;
|
||||
|
||||
// Position of the Dialog
|
||||
final Alignment? alignment;
|
||||
|
||||
// Inset of the Dialog
|
||||
final EdgeInsets? insetPadding;
|
||||
|
||||
final double? width;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final windowSize = MediaQuery.of(context).size;
|
||||
final size = windowSize * 0.6;
|
||||
final size = windowSize * 0.7;
|
||||
|
||||
return SimpleDialog(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
backgroundColor: backgroundColor ?? Theme.of(context).cardColor,
|
||||
title: title,
|
||||
shape: shape ??
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
children: [
|
||||
Material(
|
||||
type: MaterialType.transparency,
|
||||
child: Container(
|
||||
height: size.height,
|
||||
width: width ??
|
||||
max(
|
||||
min(size.width, overlayContainerMaxWidth),
|
||||
overlayContainerMinWidth,
|
||||
),
|
||||
constraints: constraints,
|
||||
child: child,
|
||||
),
|
||||
)
|
||||
]);
|
||||
alignment: alignment,
|
||||
insetPadding: insetPadding ?? _defaultInsetPadding,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
backgroundColor: backgroundColor ?? Theme.of(context).cardColor,
|
||||
title: title,
|
||||
shape: shape ??
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
children: [
|
||||
Material(
|
||||
type: MaterialType.transparency,
|
||||
child: Container(
|
||||
height: expandHeight ? size.height : null,
|
||||
width: width ??
|
||||
max(min(size.width, overlayContainerMaxWidth),
|
||||
overlayContainerMinWidth),
|
||||
constraints: constraints,
|
||||
child: child,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
450
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
450
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -132,6 +132,12 @@ dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
@ -185,6 +191,7 @@ dependencies = [
|
||||
"flowy-document",
|
||||
"flowy-error",
|
||||
"flowy-notification",
|
||||
"flowy-search",
|
||||
"flowy-user",
|
||||
"lib-dispatch",
|
||||
"serde",
|
||||
@ -197,6 +204,12 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
@ -362,6 +375,15 @@ version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "bitpacking"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8c7d2ac73c167c06af4a5f37e6e59d84148d57ccbe4480b76f0273eefea82d7"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "1.0.1"
|
||||
@ -578,6 +600,12 @@ dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "census"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0"
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
version = "1.1.0"
|
||||
@ -1221,6 +1249,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
@ -1332,7 +1366,7 @@ dependencies = [
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"strsim 0.10.0",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
@ -1547,6 +1581,12 @@ version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "1.0.6"
|
||||
@ -1628,23 +1668,12 @@ checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1690,6 +1719,12 @@ dependencies = [
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastdivide"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25c7df09945d65ea8d70b3321547ed414bbc540aad5bac6883d021b970f35b04"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.1"
|
||||
@ -1760,7 +1795,7 @@ dependencies = [
|
||||
"console",
|
||||
"fancy-regex 0.10.0",
|
||||
"flowy-ast",
|
||||
"itertools",
|
||||
"itertools 0.10.5",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"phf 0.8.0",
|
||||
@ -1812,6 +1847,7 @@ dependencies = [
|
||||
"flowy-error",
|
||||
"flowy-folder",
|
||||
"flowy-folder-pub",
|
||||
"flowy-search",
|
||||
"flowy-server",
|
||||
"flowy-server-pub",
|
||||
"flowy-sqlite",
|
||||
@ -2007,6 +2043,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"tantivy",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"url",
|
||||
@ -2021,6 +2058,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"collab",
|
||||
"collab-document",
|
||||
"collab-entity",
|
||||
"collab-folder",
|
||||
"collab-integrate",
|
||||
@ -2030,6 +2068,7 @@ dependencies = [
|
||||
"flowy-error",
|
||||
"flowy-folder-pub",
|
||||
"flowy-notification",
|
||||
"flowy-search-pub",
|
||||
"lazy_static",
|
||||
"lib-dispatch",
|
||||
"lib-infra",
|
||||
@ -2072,6 +2111,47 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-search"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"bytes",
|
||||
"collab",
|
||||
"collab-folder",
|
||||
"diesel",
|
||||
"diesel_derives",
|
||||
"diesel_migrations",
|
||||
"flowy-codegen",
|
||||
"flowy-derive",
|
||||
"flowy-error",
|
||||
"flowy-notification",
|
||||
"flowy-search-pub",
|
||||
"flowy-sqlite",
|
||||
"flowy-user",
|
||||
"futures",
|
||||
"lib-dispatch",
|
||||
"protobuf",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strsim 0.11.0",
|
||||
"strum_macros 0.26.1",
|
||||
"tantivy",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"validator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-search-pub"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"collab",
|
||||
"collab-folder",
|
||||
"flowy-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-server"
|
||||
version = "0.1.0"
|
||||
@ -2263,6 +2343,16 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs4"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
@ -2795,6 +2885,10 @@ name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
dependencies = [
|
||||
"ahash 0.8.6",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@ -2863,6 +2957,12 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "htmlescape"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.9"
|
||||
@ -3142,6 +3242,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3172,6 +3275,15 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
@ -3308,6 +3420,12 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "levenshtein_automata"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25"
|
||||
|
||||
[[package]]
|
||||
name = "lib-dispatch"
|
||||
version = "0.1.0"
|
||||
@ -3374,9 +3492,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@ -3442,9 +3560,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.11"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@ -3470,6 +3588,7 @@ checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"generator",
|
||||
"pin-utils",
|
||||
"scoped-tls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -3477,6 +3596,21 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lz4_flex"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15"
|
||||
|
||||
[[package]]
|
||||
name = "mac"
|
||||
version = "0.1.1"
|
||||
@ -3588,12 +3722,31 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||
|
||||
[[package]]
|
||||
name = "measure_time"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56220900f1a0923789ecd6bf25fbae8af3b2f1ff3e9e297fc9b6b8674dd4d852"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
@ -3682,6 +3835,12 @@ version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
||||
|
||||
[[package]]
|
||||
name = "murmurhash32"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9380db4c04d219ac5c51d14996bbf2c2e9a15229771b53f8671eb6c83cf44df"
|
||||
|
||||
[[package]]
|
||||
name = "nanoid"
|
||||
version = "0.4.0"
|
||||
@ -3926,6 +4085,15 @@ version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "oneshot"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f6640c6bda7731b1fdbab747981a0f896dd1fedaf9f4a53fa237a04a84431f4"
|
||||
dependencies = [
|
||||
"loom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
@ -4018,6 +4186,15 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "ownedbytes"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e8a72b918ae8198abb3a18c190288123e1d442b6b9a7d709305fd194688b4b7"
|
||||
dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.15.10"
|
||||
@ -4543,7 +4720,7 @@ checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"heck 0.4.1",
|
||||
"itertools",
|
||||
"itertools 0.11.0",
|
||||
"log",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
@ -4564,7 +4741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"itertools 0.11.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.47",
|
||||
@ -5055,6 +5232,16 @@ dependencies = [
|
||||
"librocksdb-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-stemmers"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_decimal"
|
||||
version = "1.30.0"
|
||||
@ -5106,15 +5293,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.25"
|
||||
version = "0.38.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
|
||||
checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5591,6 +5778,15 @@ version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
|
||||
|
||||
[[package]]
|
||||
name = "sketches-ddsketch"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.8"
|
||||
@ -5725,6 +5921,12 @@ version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.25.0"
|
||||
@ -5756,6 +5958,19 @@ dependencies = [
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
@ -5852,6 +6067,146 @@ dependencies = [
|
||||
"version-compare 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6083cd777fa94271b8ce0fe4533772cb8110c3044bab048d20f70108329a1f2"
|
||||
dependencies = [
|
||||
"aho-corasick 1.0.2",
|
||||
"arc-swap",
|
||||
"async-trait",
|
||||
"base64 0.21.5",
|
||||
"bitpacking",
|
||||
"byteorder",
|
||||
"census",
|
||||
"crc32fast",
|
||||
"crossbeam-channel",
|
||||
"downcast-rs",
|
||||
"fastdivide",
|
||||
"fs4",
|
||||
"htmlescape",
|
||||
"itertools 0.11.0",
|
||||
"levenshtein_automata",
|
||||
"log",
|
||||
"lru",
|
||||
"lz4_flex",
|
||||
"measure_time",
|
||||
"memmap2",
|
||||
"murmurhash32",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"oneshot",
|
||||
"rayon",
|
||||
"regex",
|
||||
"rust-stemmers",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sketches-ddsketch",
|
||||
"smallvec",
|
||||
"tantivy-bitpacker",
|
||||
"tantivy-columnar",
|
||||
"tantivy-common",
|
||||
"tantivy-fst",
|
||||
"tantivy-query-grammar",
|
||||
"tantivy-stacker",
|
||||
"tantivy-tokenizer-api",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"time",
|
||||
"uuid",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-bitpacker"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cecb164321482301f514dd582264fa67f70da2d7eb01872ccd71e35e0d96655a"
|
||||
dependencies = [
|
||||
"bitpacking",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-columnar"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d85f8019af9a78b3118c11298b36ffd21c2314bd76bbcd9d12e00124cbb7e70"
|
||||
dependencies = [
|
||||
"fastdivide",
|
||||
"fnv",
|
||||
"itertools 0.11.0",
|
||||
"serde",
|
||||
"tantivy-bitpacker",
|
||||
"tantivy-common",
|
||||
"tantivy-sstable",
|
||||
"tantivy-stacker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-common"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af4a3a975e604a2aba6b1106a04505e1e7a025e6def477fab6e410b4126471e1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"byteorder",
|
||||
"ownedbytes",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-fst"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc3c506b1a8443a3a65352df6382a1fb6a7afe1a02e871cee0d25e2c3d5f3944"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"regex-syntax 0.6.29",
|
||||
"utf8-ranges",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-query-grammar"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d39c5a03100ac10c96e0c8b07538e2ab8b17da56434ab348309b31f23fada77"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-sstable"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0c1bb43e5e8b8e05eb8009610344dbf285f06066c844032fbb3e546b3c71df"
|
||||
dependencies = [
|
||||
"tantivy-common",
|
||||
"tantivy-fst",
|
||||
"zstd 0.12.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-stacker"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2c078595413f13f218cf6f97b23dcfd48936838f1d3d13a1016e05acd64ed6c"
|
||||
dependencies = [
|
||||
"murmurhash32",
|
||||
"tantivy-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-tokenizer-api"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "347b6fb212b26d3505d224f438e3c4b827ab8bd847fe9953ad5ac6b8f9443b66"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tao"
|
||||
version = "0.16.2"
|
||||
@ -6139,15 +6494,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.8.1"
|
||||
version = "3.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
|
||||
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall 0.4.1",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6304,6 +6659,7 @@ dependencies = [
|
||||
"signal-hook-registry",
|
||||
"socket2 0.5.5",
|
||||
"tokio-macros",
|
||||
"tracing",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -6772,6 +7128,12 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.6.1"
|
||||
@ -7249,6 +7611,15 @@ dependencies = [
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.0"
|
||||
@ -7637,7 +8008,7 @@ dependencies = [
|
||||
"pbkdf2 0.11.0",
|
||||
"sha1",
|
||||
"time",
|
||||
"zstd",
|
||||
"zstd 0.11.2+zstd.1.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7646,7 +8017,16 @@ version = "0.11.2+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
"zstd-safe 5.0.2+zstd.1.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c"
|
||||
dependencies = [
|
||||
"zstd-safe 6.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7659,6 +8039,16 @@ dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "6.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.8+zstd.1.5.5"
|
||||
|
@ -60,6 +60,7 @@ flowy-error = { path = "../../rust-lib/flowy-error", features = [
|
||||
"impl_from_serde",
|
||||
"tauri_ts",
|
||||
] }
|
||||
flowy-search = { path = "../../rust-lib/flowy-search", features = ["tauri_ts"] }
|
||||
flowy-document = { path = "../../rust-lib/flowy-document", features = [
|
||||
"tauri_ts",
|
||||
] }
|
||||
|
@ -5,3 +5,4 @@ export * from "./models/flowy-document";
|
||||
export * from "./models/flowy-error";
|
||||
export * from "./models/flowy-config";
|
||||
export * from "./models/flowy-date";
|
||||
export * from "./models/flowy-search";
|
||||
|
11
frontend/appflowy_web/wasm-libs/Cargo.lock
generated
11
frontend/appflowy_web/wasm-libs/Cargo.lock
generated
@ -1371,6 +1371,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"collab",
|
||||
"collab-document",
|
||||
"collab-entity",
|
||||
"collab-folder",
|
||||
"collab-integrate",
|
||||
@ -1380,6 +1381,7 @@ dependencies = [
|
||||
"flowy-error",
|
||||
"flowy-folder-pub",
|
||||
"flowy-notification",
|
||||
"flowy-search-pub",
|
||||
"lazy_static",
|
||||
"lib-dispatch",
|
||||
"lib-infra",
|
||||
@ -1422,6 +1424,15 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-search-pub"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"collab",
|
||||
"collab-folder",
|
||||
"flowy-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-server"
|
||||
version = "0.1.0"
|
||||
|
@ -1463,5 +1463,15 @@
|
||||
"synced": "Synced",
|
||||
"noNetworkConnected": "No network connected"
|
||||
}
|
||||
},
|
||||
"commandPalette": {
|
||||
"placeholder": "Type to search for views...",
|
||||
"bestMatches": "Best matches",
|
||||
"recentHistory": "Recent history",
|
||||
"navigateHint": "to navigate",
|
||||
"loadingTooltip": "We are looking for results...",
|
||||
"betaLabel": "BETA",
|
||||
"betaTooltip": "We currently only support searching for pages",
|
||||
"fromTrashHint": "From trash"
|
||||
}
|
||||
}
|
||||
|
537
frontend/rust-lib/Cargo.lock
generated
537
frontend/rust-lib/Cargo.lock
generated
@ -133,6 +133,12 @@ dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
@ -174,6 +180,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
@ -422,6 +434,15 @@ version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
|
||||
[[package]]
|
||||
name = "bitpacking"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8c7d2ac73c167c06af4a5f37e6e59d84148d57ccbe4480b76f0273eefea82d7"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "1.0.1"
|
||||
@ -593,6 +614,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "census"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
@ -1138,6 +1165,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
@ -1222,7 +1255,7 @@ dependencies = [
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"strsim 0.10.0",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
@ -1335,6 +1368,9 @@ name = "deranged"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
@ -1395,6 +1431,12 @@ version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d95203a6a50906215a502507c0f879a0ce7ff205a6111e2db2a5ef8e4bb92e43"
|
||||
|
||||
[[package]]
|
||||
name = "deunicode"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94"
|
||||
|
||||
[[package]]
|
||||
name = "diesel"
|
||||
version = "2.1.4"
|
||||
@ -1457,6 +1499,12 @@ version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "1.0.9"
|
||||
@ -1523,23 +1571,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.3"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1566,6 +1603,7 @@ dependencies = [
|
||||
"flowy-folder",
|
||||
"flowy-folder-pub",
|
||||
"flowy-notification",
|
||||
"flowy-search",
|
||||
"flowy-server",
|
||||
"flowy-server-pub",
|
||||
"flowy-storage",
|
||||
@ -1586,6 +1624,7 @@ dependencies = [
|
||||
"tokio-postgres",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"walkdir",
|
||||
"zip",
|
||||
]
|
||||
|
||||
@ -1613,12 +1652,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fake"
|
||||
version = "2.8.0"
|
||||
version = "2.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9af7b0c58ac9d03169e27f080616ce9f64004edca3d2ef4147a811c21b23b319"
|
||||
checksum = "1c25829bde82205da46e1823b2259db6273379f626fc211f126f65654a2669be"
|
||||
dependencies = [
|
||||
"deunicode 1.4.3",
|
||||
"rand 0.8.5",
|
||||
"unidecode",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1660,10 +1699,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.0"
|
||||
name = "fastdivide"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
|
||||
checksum = "25c7df09945d65ea8d70b3321547ed414bbc540aad5bac6883d021b970f35b04"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
|
||||
[[package]]
|
||||
name = "finl_unicode"
|
||||
@ -1718,7 +1763,7 @@ dependencies = [
|
||||
"console",
|
||||
"fancy-regex 0.10.0",
|
||||
"flowy-ast",
|
||||
"itertools",
|
||||
"itertools 0.10.5",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"phf 0.8.0",
|
||||
@ -1771,6 +1816,7 @@ dependencies = [
|
||||
"flowy-error",
|
||||
"flowy-folder",
|
||||
"flowy-folder-pub",
|
||||
"flowy-search",
|
||||
"flowy-server",
|
||||
"flowy-server-pub",
|
||||
"flowy-sqlite",
|
||||
@ -1969,6 +2015,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"tantivy",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"url",
|
||||
@ -1983,6 +2030,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"collab",
|
||||
"collab-document",
|
||||
"collab-entity",
|
||||
"collab-folder",
|
||||
"collab-integrate",
|
||||
@ -1992,6 +2040,7 @@ dependencies = [
|
||||
"flowy-error",
|
||||
"flowy-folder-pub",
|
||||
"flowy-notification",
|
||||
"flowy-search-pub",
|
||||
"lazy_static",
|
||||
"lib-dispatch",
|
||||
"lib-infra",
|
||||
@ -2035,6 +2084,47 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-search"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"bytes",
|
||||
"collab",
|
||||
"collab-folder",
|
||||
"diesel",
|
||||
"diesel_derives",
|
||||
"diesel_migrations",
|
||||
"flowy-codegen",
|
||||
"flowy-derive",
|
||||
"flowy-error",
|
||||
"flowy-notification",
|
||||
"flowy-search-pub",
|
||||
"flowy-sqlite",
|
||||
"flowy-user",
|
||||
"futures",
|
||||
"lib-dispatch",
|
||||
"protobuf",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strsim 0.11.0",
|
||||
"strum_macros 0.26.1",
|
||||
"tantivy",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"validator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-search-pub"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"collab",
|
||||
"collab-folder",
|
||||
"flowy-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flowy-server"
|
||||
version = "0.1.0"
|
||||
@ -2238,6 +2328,16 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs4"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
@ -2364,6 +2464,19 @@ dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generator"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"log",
|
||||
"rustversion",
|
||||
"windows 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
@ -2551,6 +2664,10 @@ name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
dependencies = [
|
||||
"ahash 0.8.6",
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hdrhistogram"
|
||||
@ -2607,7 +2724,7 @@ version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2624,6 +2741,12 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "htmlescape"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.9"
|
||||
@ -2883,6 +3006,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2900,6 +3026,15 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
@ -2950,6 +3085,12 @@ version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "levenshtein_automata"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25"
|
||||
|
||||
[[package]]
|
||||
name = "lib-dispatch"
|
||||
version = "0.1.0"
|
||||
@ -3019,9 +3160,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@ -3077,9 +3218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.11"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@ -3097,6 +3238,35 @@ version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "loom"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"generator",
|
||||
"pin-utils",
|
||||
"scoped-tls",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lz4_flex"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15"
|
||||
|
||||
[[package]]
|
||||
name = "mac"
|
||||
version = "0.1.1"
|
||||
@ -3194,12 +3364,31 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||
|
||||
[[package]]
|
||||
name = "measure_time"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56220900f1a0923789ecd6bf25fbae8af3b2f1ff3e9e297fc9b6b8674dd4d852"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
@ -3269,7 +3458,7 @@ checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3278,6 +3467,12 @@ version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
||||
|
||||
[[package]]
|
||||
name = "murmurhash32"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9380db4c04d219ac5c51d14996bbf2c2e9a15229771b53f8671eb6c83cf44df"
|
||||
|
||||
[[package]]
|
||||
name = "nanoid"
|
||||
version = "0.4.0"
|
||||
@ -3395,6 +3590,15 @@ version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "oneshot"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f6640c6bda7731b1fdbab747981a0f896dd1fedaf9f4a53fa237a04a84431f4"
|
||||
dependencies = [
|
||||
"loom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
@ -3471,6 +3675,15 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "ownedbytes"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e8a72b918ae8198abb3a18c190288123e1d442b6b9a7d709305fd194688b4b7"
|
||||
dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
@ -3933,7 +4146,7 @@ checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"heck 0.4.1",
|
||||
"itertools",
|
||||
"itertools 0.11.0",
|
||||
"log",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
@ -3954,7 +4167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"itertools 0.11.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.47",
|
||||
@ -4302,15 +4515,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "regex"
|
||||
version = "1.9.5"
|
||||
@ -4491,6 +4695,16 @@ dependencies = [
|
||||
"librocksdb-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-stemmers"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_decimal"
|
||||
version = "1.32.0"
|
||||
@ -4531,15 +4745,15 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.25"
|
||||
version = "0.38.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
|
||||
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4622,7 +4836,7 @@ version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4634,6 +4848,12 @@ dependencies = [
|
||||
"parking_lot 0.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@ -4940,6 +5160,15 @@ version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||
|
||||
[[package]]
|
||||
name = "sketches-ddsketch"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
@ -4955,7 +5184,7 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
|
||||
dependencies = [
|
||||
"deunicode",
|
||||
"deunicode 0.4.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4990,7 +5219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5048,6 +5277,12 @@ version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.25.0"
|
||||
@ -5079,6 +5314,19 @@ dependencies = [
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.5.0"
|
||||
@ -5149,6 +5397,146 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6083cd777fa94271b8ce0fe4533772cb8110c3044bab048d20f70108329a1f2"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"arc-swap",
|
||||
"async-trait",
|
||||
"base64 0.21.5",
|
||||
"bitpacking",
|
||||
"byteorder",
|
||||
"census",
|
||||
"crc32fast",
|
||||
"crossbeam-channel",
|
||||
"downcast-rs",
|
||||
"fastdivide",
|
||||
"fs4",
|
||||
"htmlescape",
|
||||
"itertools 0.11.0",
|
||||
"levenshtein_automata",
|
||||
"log",
|
||||
"lru",
|
||||
"lz4_flex",
|
||||
"measure_time",
|
||||
"memmap2",
|
||||
"murmurhash32",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"oneshot",
|
||||
"rayon",
|
||||
"regex",
|
||||
"rust-stemmers",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sketches-ddsketch",
|
||||
"smallvec",
|
||||
"tantivy-bitpacker",
|
||||
"tantivy-columnar",
|
||||
"tantivy-common",
|
||||
"tantivy-fst",
|
||||
"tantivy-query-grammar",
|
||||
"tantivy-stacker",
|
||||
"tantivy-tokenizer-api",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"time",
|
||||
"uuid",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-bitpacker"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cecb164321482301f514dd582264fa67f70da2d7eb01872ccd71e35e0d96655a"
|
||||
dependencies = [
|
||||
"bitpacking",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-columnar"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d85f8019af9a78b3118c11298b36ffd21c2314bd76bbcd9d12e00124cbb7e70"
|
||||
dependencies = [
|
||||
"fastdivide",
|
||||
"fnv",
|
||||
"itertools 0.11.0",
|
||||
"serde",
|
||||
"tantivy-bitpacker",
|
||||
"tantivy-common",
|
||||
"tantivy-sstable",
|
||||
"tantivy-stacker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-common"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af4a3a975e604a2aba6b1106a04505e1e7a025e6def477fab6e410b4126471e1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"byteorder",
|
||||
"ownedbytes",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-fst"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc3c506b1a8443a3a65352df6382a1fb6a7afe1a02e871cee0d25e2c3d5f3944"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"regex-syntax 0.6.29",
|
||||
"utf8-ranges",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-query-grammar"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d39c5a03100ac10c96e0c8b07538e2ab8b17da56434ab348309b31f23fada77"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-sstable"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0c1bb43e5e8b8e05eb8009610344dbf285f06066c844032fbb3e546b3c71df"
|
||||
dependencies = [
|
||||
"tantivy-common",
|
||||
"tantivy-fst",
|
||||
"zstd 0.12.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-stacker"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2c078595413f13f218cf6f97b23dcfd48936838f1d3d13a1016e05acd64ed6c"
|
||||
dependencies = [
|
||||
"murmurhash32",
|
||||
"tantivy-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy-tokenizer-api"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "347b6fb212b26d3505d224f438e3c4b827ab8bd847fe9953ad5ac6b8f9443b66"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
@ -5167,15 +5555,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.8.1"
|
||||
version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
|
||||
checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall 0.4.1",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5322,7 +5709,7 @@ dependencies = [
|
||||
"socket2 0.5.5",
|
||||
"tokio-macros",
|
||||
"tracing",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5827,12 +6214,6 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "unidecode"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
@ -5872,6 +6253,12 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.6.1"
|
||||
@ -5946,9 +6333,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
@ -6175,6 +6562,15 @@ dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
@ -6305,7 +6701,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6368,7 +6764,7 @@ dependencies = [
|
||||
"pbkdf2 0.11.0",
|
||||
"sha1",
|
||||
"time",
|
||||
"zstd",
|
||||
"zstd 0.11.2+zstd.1.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6377,7 +6773,16 @@ version = "0.11.2+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
"zstd-safe 5.0.2+zstd.1.5.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c"
|
||||
dependencies = [
|
||||
"zstd-safe 6.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6390,6 +6795,16 @@ dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "6.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.8+zstd.1.5.5"
|
||||
|
@ -24,10 +24,12 @@ members = [
|
||||
"collab-integrate",
|
||||
"flowy-ai",
|
||||
"flowy-date",
|
||||
"flowy-search",
|
||||
"lib-infra",
|
||||
"build-tool/flowy-ast",
|
||||
"build-tool/flowy-codegen",
|
||||
"build-tool/flowy-derive",
|
||||
"flowy-search-pub",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
@ -56,6 +58,8 @@ flowy-server-pub = { workspace = true, path = "flowy-server-pub" }
|
||||
flowy-config = { workspace = true, path = "flowy-config" }
|
||||
flowy-encrypt = { workspace = true, path = "flowy-encrypt" }
|
||||
flowy-storage = { workspace = true, path = "flowy-storage" }
|
||||
flowy-search = { workspace = true, path = "flowy-search" }
|
||||
flowy-search-pub = { workspace = true, path = "flowy-search-pub" }
|
||||
collab-integrate = { workspace = true, path = "collab-integrate" }
|
||||
flowy-ai = { workspace = true, path = "flowy-ai" }
|
||||
flowy-date = { workspace = true, path = "flowy-date" }
|
||||
|
@ -17,9 +17,9 @@ anyhow.workspace = true
|
||||
tracing.workspace = true
|
||||
parking_lot.workspace = true
|
||||
async-trait.workspace = true
|
||||
tokio = { workspace = true, features = ["sync"]}
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
lib-infra = { workspace = true }
|
||||
futures = "0.3"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = []
|
||||
|
@ -23,6 +23,7 @@ flowy-server-pub = { workspace = true }
|
||||
flowy-notification = { workspace = true }
|
||||
anyhow.workspace = true
|
||||
flowy-storage = { workspace = true }
|
||||
flowy-search = { workspace = true }
|
||||
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
@ -51,6 +52,7 @@ assert-json-diff = "2.0.2"
|
||||
tokio-postgres = { version = "0.7.8" }
|
||||
chrono = "0.4.31"
|
||||
zip = "0.6.6"
|
||||
walkdir = "2.5.0"
|
||||
|
||||
[features]
|
||||
default = ["supabase_cloud_test"]
|
||||
|
@ -29,7 +29,7 @@ pub struct OpenDocumentData {
|
||||
|
||||
impl DocumentEventTest {
|
||||
pub async fn new() -> Self {
|
||||
let sdk = EventIntegrationTest::new_with_guest_user().await;
|
||||
let sdk = EventIntegrationTest::new_anon().await;
|
||||
Self { event_test: sdk }
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
use collab_folder::{FolderData, View};
|
||||
use flowy_folder::entities::icon::UpdateViewIconPayloadPB;
|
||||
use flowy_folder::entities::*;
|
||||
use flowy_folder::event_map::FolderEvent;
|
||||
use flowy_folder::event_map::FolderEvent::*;
|
||||
use flowy_folder::{entities::*, ViewLayout};
|
||||
use flowy_search::services::manager::{SearchHandler, SearchType};
|
||||
use flowy_user::entities::{
|
||||
AcceptWorkspaceInvitationPB, AddWorkspaceMemberPB, QueryWorkspacePB, RemoveWorkspaceMemberPB,
|
||||
RepeatedWorkspaceInvitationPB, RepeatedWorkspaceMemberPB, WorkspaceMemberInvitationPB,
|
||||
@ -9,6 +11,7 @@ use flowy_user::entities::{
|
||||
};
|
||||
use flowy_user::errors::FlowyError;
|
||||
use flowy_user::event_map::UserEvent;
|
||||
use std::sync::Arc;
|
||||
use flowy_user_pub::entities::Role;
|
||||
|
||||
use crate::event_builder::EventBuilder;
|
||||
@ -99,6 +102,49 @@ impl EventIntegrationTest {
|
||||
.parse::<WorkspacePB>()
|
||||
}
|
||||
|
||||
pub fn get_folder_search_handler(&self) -> &Arc<dyn SearchHandler> {
|
||||
self
|
||||
.appflowy_core
|
||||
.search_manager
|
||||
.get_handler(SearchType::Folder)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// create views in the folder.
|
||||
pub async fn create_views(&self, views: Vec<View>) {
|
||||
let create_view_params = views
|
||||
.into_iter()
|
||||
.map(|view| CreateViewParams {
|
||||
parent_view_id: view.parent_view_id,
|
||||
name: view.name,
|
||||
desc: "".to_string(),
|
||||
layout: view.layout.into(),
|
||||
view_id: view.id,
|
||||
initial_data: vec![],
|
||||
meta: Default::default(),
|
||||
set_as_current: false,
|
||||
index: None,
|
||||
section: None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for params in create_view_params {
|
||||
self
|
||||
.appflowy_core
|
||||
.folder_manager
|
||||
.create_view_with_params(params)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_folder_data(&self) -> FolderData {
|
||||
let mutex_folder = self.appflowy_core.folder_manager.get_mutex_folder().clone();
|
||||
let folder_lock_guard = mutex_folder.lock();
|
||||
let folder = folder_lock_guard.as_ref().unwrap();
|
||||
folder.get_folder_data().clone().unwrap()
|
||||
}
|
||||
|
||||
pub async fn get_all_workspace_views(&self) -> Vec<ViewPB> {
|
||||
EventBuilder::new(self.clone())
|
||||
.event(FolderEvent::ReadCurrentWorkspaceViews)
|
||||
@ -201,7 +247,7 @@ pub struct ViewTest {
|
||||
}
|
||||
impl ViewTest {
|
||||
#[allow(dead_code)]
|
||||
pub async fn new(sdk: &EventIntegrationTest, layout: ViewLayoutPB, data: Vec<u8>) -> Self {
|
||||
pub async fn new(sdk: &EventIntegrationTest, layout: ViewLayout, data: Vec<u8>) -> Self {
|
||||
let workspace = sdk.folder_manager.get_current_workspace().await.unwrap();
|
||||
|
||||
let payload = CreateViewPayloadPB {
|
||||
@ -209,7 +255,7 @@ impl ViewTest {
|
||||
name: "View A".to_string(),
|
||||
desc: "".to_string(),
|
||||
thumbnail: Some("http://1.png".to_string()),
|
||||
layout,
|
||||
layout: layout.into(),
|
||||
initial_data: data,
|
||||
meta: Default::default(),
|
||||
set_as_current: true,
|
||||
@ -223,6 +269,7 @@ impl ViewTest {
|
||||
.async_send()
|
||||
.await
|
||||
.parse::<ViewPB>();
|
||||
|
||||
Self {
|
||||
sdk: sdk.clone(),
|
||||
workspace,
|
||||
@ -231,15 +278,15 @@ impl ViewTest {
|
||||
}
|
||||
|
||||
pub async fn new_grid_view(sdk: &EventIntegrationTest, data: Vec<u8>) -> Self {
|
||||
Self::new(sdk, ViewLayoutPB::Grid, data).await
|
||||
Self::new(sdk, ViewLayout::Grid, data).await
|
||||
}
|
||||
|
||||
pub async fn new_board_view(sdk: &EventIntegrationTest, data: Vec<u8>) -> Self {
|
||||
Self::new(sdk, ViewLayoutPB::Board, data).await
|
||||
Self::new(sdk, ViewLayout::Board, data).await
|
||||
}
|
||||
|
||||
pub async fn new_calendar_view(sdk: &EventIntegrationTest, data: Vec<u8>) -> Self {
|
||||
Self::new(sdk, ViewLayoutPB::Calendar, data).await
|
||||
Self::new(sdk, ViewLayout::Calendar, data).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ use tokio::select;
|
||||
use tokio::time::sleep;
|
||||
|
||||
use flowy_core::config::AppFlowyCoreConfig;
|
||||
use flowy_core::integrate::log::create_log_filter;
|
||||
use flowy_core::AppFlowyCore;
|
||||
use flowy_notification::register_notification_sender;
|
||||
use flowy_server::AppFlowyServer;
|
||||
@ -86,6 +87,14 @@ impl EventIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn instance_name(&self) -> String {
|
||||
self.appflowy_core.config.name.clone()
|
||||
}
|
||||
|
||||
pub fn user_data_path(&self) -> String {
|
||||
self.appflowy_core.config.application_path.clone()
|
||||
}
|
||||
|
||||
pub fn get_server(&self) -> Arc<dyn AppFlowyServer> {
|
||||
self.appflowy_core.server_provider.get_server().unwrap()
|
||||
}
|
||||
|
@ -51,13 +51,14 @@ impl EventIntegrationTest {
|
||||
config.encrypt_secret
|
||||
}
|
||||
|
||||
pub async fn new_with_guest_user() -> Self {
|
||||
/// Create a anonymous user for given test.
|
||||
pub async fn new_anon() -> Self {
|
||||
let test = Self::new().await;
|
||||
test.sign_up_as_guest().await;
|
||||
test.sign_up_as_anon().await;
|
||||
test
|
||||
}
|
||||
|
||||
pub async fn sign_up_as_guest(&self) -> SignUpContext {
|
||||
pub async fn sign_up_as_anon(&self) -> SignUpContext {
|
||||
let password = login_password();
|
||||
let email = unique_email();
|
||||
let payload = SignUpPayloadPB {
|
||||
@ -116,7 +117,7 @@ impl EventIntegrationTest {
|
||||
}
|
||||
|
||||
pub async fn init_anon_user(&self) -> UserProfilePB {
|
||||
self.sign_up_as_guest().await.user_profile
|
||||
self.sign_up_as_anon().await.user_profile
|
||||
}
|
||||
|
||||
pub async fn get_user_profile(&self) -> Result<UserProfilePB, FlowyError> {
|
||||
|
Binary file not shown.
@ -3,7 +3,7 @@ use event_integration::EventIntegrationTest;
|
||||
// The number of groups should be 0 if there is no group by field in grid
|
||||
#[tokio::test]
|
||||
async fn get_groups_event_with_grid_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my board view".to_owned(), vec![])
|
||||
@ -15,7 +15,7 @@ async fn get_groups_event_with_grid_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_groups_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let board_view = test
|
||||
.create_board(¤t_workspace.id, "my board view".to_owned(), vec![])
|
||||
@ -27,7 +27,7 @@ async fn get_groups_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_group_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let board_view = test
|
||||
.create_board(¤t_workspace.id, "my board view".to_owned(), vec![])
|
||||
@ -61,7 +61,7 @@ async fn move_group_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_group_event_with_invalid_id_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let board_view = test
|
||||
.create_board(¤t_workspace.id, "my board view".to_owned(), vec![])
|
||||
@ -83,7 +83,7 @@ async fn move_group_event_with_invalid_id_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn rename_group_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let board_view = test
|
||||
.create_board(¤t_workspace.id, "my board view".to_owned(), vec![])
|
||||
@ -104,7 +104,7 @@ async fn rename_group_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn hide_group_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let board_view = test
|
||||
.create_board(¤t_workspace.id, "my board view".to_owned(), vec![])
|
||||
@ -132,7 +132,7 @@ async fn hide_group_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_group_name_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let board_view = test
|
||||
.create_board(¤t_workspace.id, "my board view".to_owned(), vec![])
|
||||
@ -157,7 +157,7 @@ async fn update_group_name_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_group_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let board_view = test
|
||||
.create_board(¤t_workspace.id, "my board view".to_owned(), vec![])
|
||||
|
@ -13,7 +13,7 @@ use lib_infra::util::timestamp;
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_database_id_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -35,7 +35,7 @@ async fn get_database_id_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_database_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -49,7 +49,7 @@ async fn get_database_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_field_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -64,7 +64,7 @@ async fn get_field_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_field_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -78,7 +78,7 @@ async fn create_field_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_field_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -99,7 +99,7 @@ async fn delete_field_event_test() {
|
||||
// The primary field is not allowed to be deleted.
|
||||
#[tokio::test]
|
||||
async fn delete_primary_field_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -114,7 +114,7 @@ async fn delete_primary_field_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_field_type_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -132,7 +132,7 @@ async fn update_field_type_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_primary_field_type_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -151,7 +151,7 @@ async fn update_primary_field_type_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn duplicate_field_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -169,7 +169,7 @@ async fn duplicate_field_event_test() {
|
||||
// The primary field is not allowed to be duplicated. So this test should return an error.
|
||||
#[tokio::test]
|
||||
async fn duplicate_primary_field_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -183,7 +183,7 @@ async fn duplicate_primary_field_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_primary_field_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -196,7 +196,7 @@ async fn get_primary_field_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_row_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -211,7 +211,7 @@ async fn create_row_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_row_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -234,7 +234,7 @@ async fn delete_row_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_row_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -250,7 +250,7 @@ async fn get_row_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_row_meta_event_with_url_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -279,7 +279,7 @@ async fn update_row_meta_event_with_url_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_row_meta_event_with_cover_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -308,7 +308,7 @@ async fn update_row_meta_event_with_cover_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_row_event_with_invalid_row_id_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -321,7 +321,7 @@ async fn delete_row_event_with_invalid_row_id_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn duplicate_row_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -338,7 +338,7 @@ async fn duplicate_row_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn duplicate_row_event_with_invalid_row_id_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -355,7 +355,7 @@ async fn duplicate_row_event_with_invalid_row_id_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_row_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -375,7 +375,7 @@ async fn move_row_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_row_event_test2() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -395,7 +395,7 @@ async fn move_row_event_test2() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_row_event_with_invalid_row_id_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -422,7 +422,7 @@ async fn move_row_event_with_invalid_row_id_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_text_cell_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -452,7 +452,7 @@ async fn update_text_cell_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_checkbox_cell_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -483,7 +483,7 @@ async fn update_checkbox_cell_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_single_select_cell_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -510,7 +510,7 @@ async fn update_single_select_cell_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_date_cell_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -547,7 +547,7 @@ async fn update_date_cell_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_date_cell_event_with_empty_time_str_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -583,7 +583,7 @@ async fn update_date_cell_event_with_empty_time_str_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_checklist_field_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -604,7 +604,7 @@ async fn create_checklist_field_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_checklist_cell_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -661,7 +661,7 @@ async fn update_checklist_cell_test() {
|
||||
// Update the database layout type from grid to board
|
||||
#[tokio::test]
|
||||
async fn update_database_layout_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -683,7 +683,7 @@ async fn update_database_layout_event_test() {
|
||||
// Update the database layout type from grid to board. Set the checkbox field as the grouping field
|
||||
#[tokio::test]
|
||||
async fn update_database_layout_event_test2() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -715,7 +715,7 @@ async fn update_database_layout_event_test2() {
|
||||
// Create a checkbox field in the default board and then set it as the grouping field.
|
||||
#[tokio::test]
|
||||
async fn set_group_by_checkbox_field_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let board_view = test
|
||||
.create_board(¤t_workspace.id, "my board view".to_owned(), vec![])
|
||||
@ -732,7 +732,7 @@ async fn set_group_by_checkbox_field_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_all_calendar_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let calendar_view = test
|
||||
.create_calendar(¤t_workspace.id, "my calendar view".to_owned(), vec![])
|
||||
@ -745,7 +745,7 @@ async fn get_all_calendar_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_calendar_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let calendar_view = test
|
||||
.create_calendar(¤t_workspace.id, "my calendar view".to_owned(), vec![])
|
||||
@ -781,7 +781,7 @@ async fn create_calendar_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_relation_cell_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let grid_view = test
|
||||
.create_grid(¤t_workspace.id, "my grid view".to_owned(), vec![])
|
||||
@ -840,7 +840,7 @@ async fn update_relation_cell_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_detailed_relation_cell_data() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
|
||||
let origin_grid_view = test
|
||||
|
@ -8,7 +8,7 @@ use event_integration::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use flowy_document::entities::{DocumentSyncState, DocumentSyncStatePB};
|
||||
|
||||
use crate::util::{receive_with_timeout, unzip_history_user_db};
|
||||
use crate::util::{receive_with_timeout, unzip};
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_edit_document_test() {
|
||||
@ -43,8 +43,7 @@ async fn af_cloud_edit_document_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn af_cloud_sync_anon_user_document_test() {
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", "040_sync_local_document").unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", "040_sync_local_document").unwrap();
|
||||
user_localhost_af_cloud().await;
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path.clone(), DEFAULT_NAME.to_string())
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::util::unzip_history_user_db;
|
||||
use crate::util::unzip;
|
||||
use event_integration::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use flowy_folder::entities::{ImportPB, ImportTypePB, ViewLayoutPB};
|
||||
@ -7,11 +7,11 @@ use flowy_folder::entities::{ImportPB, ImportTypePB, ViewLayoutPB};
|
||||
async fn import_492_row_csv_file_test() {
|
||||
// csv_500r_15c.csv is a file with 492 rows and 17 columns
|
||||
let file_name = "csv_492r_17c.csv".to_string();
|
||||
let (cleaner, csv_file_path) = unzip_history_user_db("./tests/asset", &file_name).unwrap();
|
||||
let (cleaner, csv_file_path) = unzip("./tests/asset", &file_name).unwrap();
|
||||
|
||||
let csv_string = std::fs::read_to_string(csv_file_path).unwrap();
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
test.sign_up_as_guest().await;
|
||||
test.sign_up_as_anon().await;
|
||||
|
||||
let workspace_id = test.get_current_workspace().await.id;
|
||||
let import_data = gen_import_data(file_name, csv_string, workspace_id);
|
||||
@ -26,11 +26,11 @@ async fn import_492_row_csv_file_test() {
|
||||
async fn import_10240_row_csv_file_test() {
|
||||
// csv_22577r_15c.csv is a file with 10240 rows and 15 columns
|
||||
let file_name = "csv_10240r_15c.csv".to_string();
|
||||
let (cleaner, csv_file_path) = unzip_history_user_db("./tests/asset", &file_name).unwrap();
|
||||
let (cleaner, csv_file_path) = unzip("./tests/asset", &file_name).unwrap();
|
||||
|
||||
let csv_string = std::fs::read_to_string(csv_file_path).unwrap();
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
test.sign_up_as_guest().await;
|
||||
test.sign_up_as_anon().await;
|
||||
|
||||
let workspace_id = test.get_current_workspace().await.id;
|
||||
let import_data = gen_import_data(file_name, csv_string, workspace_id);
|
||||
|
@ -16,8 +16,6 @@ pub enum FolderScript {
|
||||
AssertWorkspace(WorkspacePB),
|
||||
#[allow(dead_code)]
|
||||
ReadWorkspace(String),
|
||||
|
||||
// App
|
||||
CreateParentView {
|
||||
name: String,
|
||||
desc: String,
|
||||
@ -81,16 +79,16 @@ impl FolderTest {
|
||||
let parent_view = create_view(
|
||||
&sdk,
|
||||
&workspace.id,
|
||||
"Folder App",
|
||||
"Folder test app",
|
||||
"first level view",
|
||||
"",
|
||||
ViewLayout::Document,
|
||||
)
|
||||
.await;
|
||||
let view = create_view(
|
||||
&sdk,
|
||||
&parent_view.id,
|
||||
"Folder View",
|
||||
"Folder test view",
|
||||
"second level view",
|
||||
"",
|
||||
ViewLayout::Document,
|
||||
)
|
||||
.await;
|
||||
|
@ -16,7 +16,7 @@ use crate::util::receive_with_timeout;
|
||||
/// 5. Await the notification for workspace view updates with a timeout of 30 seconds.
|
||||
/// 6. Ensure that the received views contain the newly created "test_view".
|
||||
async fn create_child_view_in_workspace_subscription_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let workspace = test.get_current_workspace().await;
|
||||
let rx = test
|
||||
.notification_sender
|
||||
@ -40,7 +40,7 @@ async fn create_child_view_in_workspace_subscription_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_child_view_in_view_subscription_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let mut workspace = test.get_current_workspace().await;
|
||||
let workspace_child_view = workspace.views.pop().unwrap();
|
||||
let rx = test.notification_sender.subscribe::<ChildViewUpdatePB>(
|
||||
@ -72,7 +72,7 @@ async fn create_child_view_in_view_subscription_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_view_subscription_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let workspace = test.get_current_workspace().await;
|
||||
let rx = test
|
||||
.notification_sender
|
||||
@ -103,7 +103,7 @@ async fn delete_view_subscription_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_view_subscription_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let mut workspace = test.get_current_workspace().await;
|
||||
let rx = test
|
||||
.notification_sender
|
||||
|
@ -6,7 +6,7 @@ use flowy_user::errors::ErrorCode;
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_workspace_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let request = CreateWorkspacePayloadPB {
|
||||
name: "my second workspace".to_owned(),
|
||||
desc: "".to_owned(),
|
||||
@ -53,7 +53,7 @@ async fn create_workspace_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_view_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let view = test
|
||||
.create_view(¤t_workspace.id, "My first view".to_string())
|
||||
@ -65,7 +65,7 @@ async fn create_view_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_view_event_with_name_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let view = test
|
||||
.create_view(¤t_workspace.id, "My first view".to_string())
|
||||
@ -86,7 +86,7 @@ async fn update_view_event_with_name_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_view_icon_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let view = test
|
||||
.create_view(¤t_workspace.id, "My first view".to_string())
|
||||
@ -110,7 +110,7 @@ async fn update_view_icon_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_view_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let view = test
|
||||
.create_view(¤t_workspace.id, "My first view".to_string())
|
||||
@ -133,7 +133,7 @@ async fn delete_view_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn put_back_trash_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let view = test
|
||||
.create_view(¤t_workspace.id, "My first view".to_string())
|
||||
@ -176,7 +176,7 @@ async fn put_back_trash_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_view_permanently_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let view = test
|
||||
.create_view(¤t_workspace.id, "My first view".to_string())
|
||||
@ -225,7 +225,7 @@ async fn delete_view_permanently_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_all_trash_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
|
||||
for i in 0..3 {
|
||||
@ -269,7 +269,7 @@ async fn delete_all_trash_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn multiple_hierarchy_view_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
for i in 1..4 {
|
||||
let parent = test
|
||||
@ -345,7 +345,7 @@ async fn multiple_hierarchy_view_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_view_event_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
for i in 1..4 {
|
||||
let parent = test
|
||||
@ -383,7 +383,7 @@ async fn move_view_event_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_view_event_after_delete_view_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
for i in 1..6 {
|
||||
let _ = test
|
||||
@ -425,7 +425,7 @@ async fn move_view_event_after_delete_view_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_view_event_after_delete_view_test2() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let parent = test
|
||||
.create_view(¤t_workspace.id, "My view".to_string())
|
||||
@ -495,7 +495,7 @@ fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> {
|
||||
|
||||
#[tokio::test]
|
||||
async fn move_view_across_parent_test() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let current_workspace = test.get_current_workspace().await;
|
||||
let parent_1 = test
|
||||
.create_view(¤t_workspace.id, "My view 1".to_string())
|
||||
|
@ -3,3 +3,5 @@ mod document;
|
||||
mod folder;
|
||||
mod user;
|
||||
pub mod util;
|
||||
|
||||
mod search;
|
||||
|
@ -0,0 +1,215 @@
|
||||
use crate::util::{unzip_test_asset, zip};
|
||||
use collab_folder::View;
|
||||
use event_integration::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use flowy_folder::entities::UpdateViewPayloadPB;
|
||||
use flowy_folder_pub::folder_builder::{FlattedViews, NestedViewBuilder};
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_folder_index_all_startup() {
|
||||
let folder_name = "folder_1000_view";
|
||||
// comment out the following line to create a test asset if you modify the test data
|
||||
// don't forget to delete unnecessary test assets
|
||||
// create_folder_test_data(folder_name).await;
|
||||
|
||||
let (cleaner, user_db_path) = unzip_test_asset(folder_name).unwrap();
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path.clone(), DEFAULT_NAME.to_string())
|
||||
.await;
|
||||
|
||||
let first_level_views = test.get_all_workspace_views().await;
|
||||
assert_eq!(first_level_views.len(), 3);
|
||||
assert_eq!(first_level_views[1].name, "1");
|
||||
assert_eq!(first_level_views[2].name, "2");
|
||||
|
||||
let view_1 = test.get_view(&first_level_views[1].id).await;
|
||||
assert_eq!(view_1.child_views.len(), 500);
|
||||
|
||||
let folder_data = test.get_folder_data();
|
||||
// Get started + 1002 Views
|
||||
assert_eq!(folder_data.views.len(), 1003);
|
||||
|
||||
// Wait for the index to be created/updated
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
|
||||
let folder_search_manager = test.get_folder_search_handler();
|
||||
let num_docs = folder_search_manager.index_count();
|
||||
assert_eq!(num_docs, 1004);
|
||||
|
||||
drop(cleaner);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_folder_index_create_20_views() {
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let folder_search_manager = test.get_folder_search_handler();
|
||||
|
||||
// Wait for the index to be created/updated
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
let workspace_id = test.get_current_workspace().await.id;
|
||||
|
||||
for i in 0..20 {
|
||||
let view = test.create_view(&workspace_id, format!("View {}", i)).await;
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
assert_eq!(view.name, format!("View {}", i));
|
||||
}
|
||||
|
||||
// Wait for the index update to finish
|
||||
sleep(Duration::from_secs(2)).await;
|
||||
|
||||
let num_docs = folder_search_manager.index_count();
|
||||
// Workspace + Get started + 20 Views
|
||||
assert_eq!(num_docs, 22);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_folder_index_create_view() {
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
|
||||
let folder_search_manager = test.get_folder_search_handler();
|
||||
|
||||
// Wait for the index to be created/updated
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
|
||||
let workspace_id = test.get_current_workspace().await.id;
|
||||
let view = test.create_view(&workspace_id, "Flowers".to_owned()).await;
|
||||
|
||||
// Wait for the index to be updated
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let results = folder_search_manager.perform_search(view.name.clone());
|
||||
if let Err(e) = results {
|
||||
panic!("Error performing search: {:?}", e);
|
||||
}
|
||||
|
||||
let results = results.unwrap();
|
||||
assert_eq!(results.len(), 1);
|
||||
assert_eq!(results[0].data, view.name);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_folder_index_rename_view() {
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let folder_search_manager = test.get_folder_search_handler();
|
||||
|
||||
// Wait for the index to be created/updated
|
||||
sleep(Duration::from_secs(1)).await;
|
||||
|
||||
let workspace_id = test.get_current_workspace().await.id;
|
||||
let view = test.create_view(&workspace_id, "Flowers".to_owned()).await;
|
||||
|
||||
// Wait for the index to be updated
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let new_view_name = "Bouquets".to_string();
|
||||
let update_payload = UpdateViewPayloadPB {
|
||||
view_id: view.id,
|
||||
name: Some(new_view_name.clone()),
|
||||
..Default::default()
|
||||
};
|
||||
test.update_view(update_payload).await;
|
||||
|
||||
// Wait for the index to be updated
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let first = folder_search_manager.perform_search(view.name);
|
||||
if let Err(e) = first {
|
||||
panic!("Error performing search: {:?}", e);
|
||||
}
|
||||
|
||||
let second = folder_search_manager.perform_search(new_view_name.clone());
|
||||
if let Err(e) = second {
|
||||
panic!("Error performing search: {:?}", e);
|
||||
}
|
||||
|
||||
let first = first.unwrap();
|
||||
assert_eq!(first.len(), 0);
|
||||
|
||||
let second = second.unwrap();
|
||||
assert_eq!(second.len(), 1);
|
||||
assert_eq!(second[0].data, new_view_name);
|
||||
}
|
||||
|
||||
/// Using this method to create a folder test asset. Only use when you want to create a new asset.
|
||||
/// The file will be created at tests/asset/{file_name}.zip and it will be committed to the repo.
|
||||
///
|
||||
#[allow(dead_code)]
|
||||
async fn create_folder_test_data(file_name: &str) {
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
test.sign_up_as_anon().await;
|
||||
|
||||
let uid = test.get_user_profile().await.unwrap().id;
|
||||
let workspace_id = test.get_current_workspace().await.id;
|
||||
let views = create_1002_views(uid, workspace_id.clone()).await;
|
||||
test.create_views(views).await;
|
||||
|
||||
let first_level_views = test.get_all_workspace_views().await;
|
||||
assert_eq!(first_level_views.len(), 3);
|
||||
assert_eq!(first_level_views[1].name, "1");
|
||||
assert_eq!(first_level_views[2].name, "2");
|
||||
|
||||
let view_1 = test.get_view(&first_level_views[1].id).await;
|
||||
assert_eq!(view_1.child_views.len(), 500);
|
||||
|
||||
let folder_data = test.get_folder_data();
|
||||
// Get started + 1002 Views
|
||||
assert_eq!(folder_data.views.len(), 1003);
|
||||
|
||||
let data_path = test.config.application_path.clone();
|
||||
zip(
|
||||
data_path.into(),
|
||||
format!("tests/asset/{}.zip", file_name).into(),
|
||||
)
|
||||
.unwrap();
|
||||
sleep(Duration::from_secs(2)).await;
|
||||
}
|
||||
|
||||
/// Create view without create the view's content(document/database).
|
||||
/// workspace
|
||||
/// - get_started
|
||||
/// - view_1
|
||||
/// - view_1_1
|
||||
/// - view_1_2
|
||||
/// - view_2
|
||||
/// - view_2_1
|
||||
/// - view_2_2
|
||||
async fn create_1002_views(uid: i64, workspace_id: String) -> Vec<View> {
|
||||
let mut builder = NestedViewBuilder::new(workspace_id.clone(), uid);
|
||||
builder
|
||||
.with_view_builder(|view_builder| async {
|
||||
let mut builder = view_builder.with_name("1");
|
||||
for i in 0..500 {
|
||||
builder = builder
|
||||
.with_child_view_builder(|child_view_builder| async {
|
||||
child_view_builder.with_name(format!("1_{}", i)).build()
|
||||
})
|
||||
.await;
|
||||
}
|
||||
builder.build()
|
||||
})
|
||||
.await;
|
||||
builder
|
||||
.with_view_builder(|view_builder| async {
|
||||
let mut builder = view_builder.with_name("2");
|
||||
for i in 0..500 {
|
||||
builder = builder
|
||||
.with_child_view_builder(|child_view_builder| async {
|
||||
child_view_builder.with_name(format!("2_{}", i)).build()
|
||||
})
|
||||
.await;
|
||||
}
|
||||
builder.build()
|
||||
})
|
||||
.await;
|
||||
// The output views should be:
|
||||
// view_1
|
||||
// view_1_1
|
||||
// view_1_x
|
||||
// view_2
|
||||
// view_2_1
|
||||
// view_2_x
|
||||
let views = builder.build();
|
||||
FlattedViews::flatten_views(views)
|
||||
}
|
@ -0,0 +1 @@
|
||||
mod folder_search_test;
|
1
frontend/rust-lib/event-integration/tests/search/mod.rs
Normal file
1
frontend/rust-lib/event-integration/tests/search/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
mod local_test;
|
@ -3,11 +3,11 @@ use event_integration::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use flowy_user::entities::AuthenticatorPB;
|
||||
|
||||
use crate::util::unzip_history_user_db;
|
||||
use crate::util::unzip;
|
||||
|
||||
#[tokio::test]
|
||||
async fn reading_039_anon_user_data_test() {
|
||||
let (cleaner, user_db_path) = unzip_history_user_db("./tests/asset", "039_local").unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", "039_local").unwrap();
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await;
|
||||
let first_level_views = test.get_all_workspace_views().await;
|
||||
@ -42,7 +42,7 @@ async fn reading_039_anon_user_data_test() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrate_anon_user_data_to_af_cloud_test() {
|
||||
let (cleaner, user_db_path) = unzip_history_user_db("./tests/asset", "040_local").unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", "040_local").unwrap();
|
||||
// In the 040_local, the structure is:
|
||||
// workspace:
|
||||
// view: Document1
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::util::unzip_history_user_db;
|
||||
use crate::util::unzip;
|
||||
use assert_json_diff::assert_json_include;
|
||||
use collab_database::rows::database_row_document_id_from_row_id;
|
||||
use event_integration::user_event::user_localhost_af_cloud;
|
||||
@ -12,8 +12,7 @@ use std::env::temp_dir;
|
||||
async fn import_appflowy_data_need_migration_test() {
|
||||
// In 037, the workspace array will be migrated to view.
|
||||
let import_container_name = "037_local".to_string();
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", &import_container_name).unwrap();
|
||||
// Getting started
|
||||
// Document1
|
||||
// Document2(fav)
|
||||
@ -52,8 +51,7 @@ async fn import_appflowy_data_need_migration_test() {
|
||||
#[tokio::test]
|
||||
async fn import_appflowy_data_folder_into_new_view_test() {
|
||||
let import_container_name = "040_local".to_string();
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", &import_container_name).unwrap();
|
||||
// In the 040_local, the structure is:
|
||||
// workspace:
|
||||
// view: Document1
|
||||
@ -121,8 +119,7 @@ async fn import_appflowy_data_folder_into_new_view_test() {
|
||||
#[tokio::test]
|
||||
async fn import_appflowy_data_folder_into_current_workspace_test() {
|
||||
let import_container_name = "040_local".to_string();
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", &import_container_name).unwrap();
|
||||
// In the 040_local, the structure is:
|
||||
// workspace:
|
||||
// view: Document1
|
||||
@ -169,8 +166,7 @@ async fn import_appflowy_data_folder_into_current_workspace_test() {
|
||||
#[tokio::test]
|
||||
async fn import_appflowy_data_folder_into_new_view_test2() {
|
||||
let import_container_name = "040_local_2".to_string();
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", &import_container_name).unwrap();
|
||||
user_localhost_af_cloud().await;
|
||||
let test = EventIntegrationTest::new_with_name(DEFAULT_NAME).await;
|
||||
let _ = test.af_cloud_sign_up().await;
|
||||
@ -209,8 +205,7 @@ async fn import_empty_appflowy_data_folder_test() {
|
||||
#[tokio::test]
|
||||
async fn import_appflowy_data_folder_multiple_times_test() {
|
||||
let import_container_name = "040_local_2".to_string();
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", &import_container_name).unwrap();
|
||||
// In the 040_local_2, the structure is:
|
||||
// Getting Started
|
||||
// Doc1
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::util::unzip_history_user_db;
|
||||
use crate::util::unzip;
|
||||
use event_integration::user_event::user_localhost_af_cloud;
|
||||
use event_integration::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
@ -7,10 +7,9 @@ use std::time::Duration;
|
||||
#[tokio::test]
|
||||
async fn import_appflowy_data_folder_into_new_view_test() {
|
||||
let import_container_name = "040_local".to_string();
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", &import_container_name).unwrap();
|
||||
let (imported_af_folder_cleaner, imported_af_data_path) =
|
||||
unzip_history_user_db("./tests/asset", &import_container_name).unwrap();
|
||||
unzip("./tests/asset", &import_container_name).unwrap();
|
||||
|
||||
user_localhost_af_cloud().await;
|
||||
let test =
|
||||
|
@ -8,7 +8,7 @@ use flowy_user::event_map::UserEvent::*;
|
||||
#[tokio::test]
|
||||
async fn user_update_with_reminder() {
|
||||
let sdk = EventIntegrationTest::new().await;
|
||||
let _ = sdk.sign_up_as_guest().await;
|
||||
let _ = sdk.sign_up_as_anon().await;
|
||||
let mut meta = HashMap::new();
|
||||
meta.insert("object_id".to_string(), "".to_string());
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
use event_integration::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
|
||||
use crate::util::unzip_history_user_db;
|
||||
use crate::util::unzip;
|
||||
|
||||
#[tokio::test]
|
||||
async fn collab_db_restore_test() {
|
||||
let (cleaner, user_db_path) = unzip_history_user_db(
|
||||
let (cleaner, user_db_path) = unzip(
|
||||
"./tests/user/migration_test/history_user_db",
|
||||
"038_collab_db_corrupt_restore",
|
||||
)
|
||||
|
@ -2,11 +2,11 @@ use event_integration::EventIntegrationTest;
|
||||
use flowy_core::DEFAULT_NAME;
|
||||
use flowy_folder::entities::ViewLayoutPB;
|
||||
|
||||
use crate::util::unzip_history_user_db;
|
||||
use crate::util::unzip;
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrate_historical_empty_document_test() {
|
||||
let (cleaner, user_db_path) = unzip_history_user_db(
|
||||
let (cleaner, user_db_path) = unzip(
|
||||
"./tests/user/migration_test/history_user_db",
|
||||
"historical_empty_document",
|
||||
)
|
||||
|
@ -3,11 +3,11 @@ use flowy_core::DEFAULT_NAME;
|
||||
use flowy_folder::entities::ViewLayoutPB;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::util::unzip_history_user_db;
|
||||
use crate::util::unzip;
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrate_020_historical_empty_document_test() {
|
||||
let (cleaner, user_db_path) = unzip_history_user_db(
|
||||
let (cleaner, user_db_path) = unzip(
|
||||
"./tests/user/migration_test/history_user_db",
|
||||
"020_historical_user_data",
|
||||
)
|
||||
@ -43,7 +43,7 @@ async fn migrate_020_historical_empty_document_test() {
|
||||
#[tokio::test]
|
||||
async fn migrate_036_fav_v1_workspace_array_test() {
|
||||
// Used to test migration: FavoriteV1AndWorkspaceArrayMigration
|
||||
let (cleaner, user_db_path) = unzip_history_user_db(
|
||||
let (cleaner, user_db_path) = unzip(
|
||||
"./tests/user/migration_test/history_user_db",
|
||||
"036_fav_v1_workspace_array",
|
||||
)
|
||||
@ -65,7 +65,7 @@ async fn migrate_036_fav_v1_workspace_array_test() {
|
||||
#[tokio::test]
|
||||
async fn migrate_038_trash_test() {
|
||||
// Used to test migration: WorkspaceTrashMapToSectionMigration
|
||||
let (cleaner, user_db_path) = unzip_history_user_db("./tests/asset", "038_local").unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", "038_local").unwrap();
|
||||
// Getting started
|
||||
// Document1
|
||||
// Document2(deleted)
|
||||
@ -102,8 +102,7 @@ async fn migrate_038_trash_test() {
|
||||
#[tokio::test]
|
||||
async fn migrate_038_trash_test2() {
|
||||
// Used to test migration: WorkspaceTrashMapToSectionMigration
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", "038_document_with_grid").unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", "038_document_with_grid").unwrap();
|
||||
// Getting started
|
||||
// document
|
||||
// grid
|
||||
@ -131,7 +130,7 @@ async fn migrate_038_trash_test2() {
|
||||
#[tokio::test]
|
||||
async fn collab_db_backup_test() {
|
||||
// Used to test migration: WorkspaceTrashMapToSectionMigration
|
||||
let (cleaner, user_db_path) = unzip_history_user_db("./tests/asset", "038_local").unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", "038_local").unwrap();
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await;
|
||||
|
||||
@ -149,8 +148,7 @@ async fn collab_db_backup_test() {
|
||||
#[tokio::test]
|
||||
async fn delete_outdated_collab_db_backup_test() {
|
||||
// Used to test migration: WorkspaceTrashMapToSectionMigration
|
||||
let (cleaner, user_db_path) =
|
||||
unzip_history_user_db("./tests/asset", "040_collab_backups").unwrap();
|
||||
let (cleaner, user_db_path) = unzip("./tests/asset", "040_collab_backups").unwrap();
|
||||
let test =
|
||||
EventIntegrationTest::new_with_user_data_path(user_db_path, DEFAULT_NAME.to_string()).await;
|
||||
|
||||
|
@ -120,7 +120,7 @@ async fn third_party_sign_up_with_duplicated_email() {
|
||||
#[tokio::test]
|
||||
async fn sign_up_as_guest_and_then_update_to_new_cloud_user_test() {
|
||||
if get_supabase_config().is_some() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let old_views = test
|
||||
.folder_manager
|
||||
.get_current_workspace_public_views()
|
||||
@ -151,7 +151,7 @@ async fn sign_up_as_guest_and_then_update_to_new_cloud_user_test() {
|
||||
#[tokio::test]
|
||||
async fn sign_up_as_guest_and_then_update_to_existing_cloud_user_test() {
|
||||
if get_supabase_config().is_some() {
|
||||
let test = EventIntegrationTest::new_with_guest_user().await;
|
||||
let test = EventIntegrationTest::new_anon().await;
|
||||
let uuid = uuid::Uuid::new_v4().to_string();
|
||||
|
||||
let email = format!("{}@appflowy.io", nanoid!(6));
|
||||
@ -172,7 +172,7 @@ async fn sign_up_as_guest_and_then_update_to_existing_cloud_user_test() {
|
||||
// sign out and then sign in as a guest
|
||||
test.sign_out().await;
|
||||
|
||||
let _sign_up_context = test.sign_up_as_guest().await;
|
||||
let _sign_up_context = test.sign_up_as_anon().await;
|
||||
let new_workspace = test.folder_manager.get_current_workspace().await.unwrap();
|
||||
test
|
||||
.create_view(&new_workspace.id, "new workspace child view".to_string())
|
||||
@ -253,7 +253,7 @@ async fn update_user_profile_with_existing_email_test() {
|
||||
async fn migrate_anon_document_on_cloud_signup() {
|
||||
if get_supabase_config().is_some() {
|
||||
let test = EventIntegrationTest::new().await;
|
||||
let user_profile = test.sign_up_as_guest().await.user_profile;
|
||||
let user_profile = test.sign_up_as_anon().await.user_profile;
|
||||
|
||||
let view = test
|
||||
.create_view(&user_profile.workspace_id, "My first view".to_string())
|
||||
@ -292,7 +292,7 @@ async fn migrate_anon_document_on_cloud_signup() {
|
||||
#[tokio::test]
|
||||
async fn migrate_anon_data_on_cloud_signup() {
|
||||
if get_supabase_config().is_some() {
|
||||
let (cleaner, user_db_path) = unzip_history_user_db(
|
||||
let (cleaner, user_db_path) = unzip(
|
||||
"./tests/user/supabase_test/history_user_db",
|
||||
"workspace_sync",
|
||||
)
|
||||
|
@ -1,9 +1,10 @@
|
||||
use std::fs::{create_dir_all, File};
|
||||
use std::fs::{create_dir_all, File, OpenOptions};
|
||||
use std::io::copy;
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{fs, io};
|
||||
|
||||
use anyhow::Error;
|
||||
use collab_folder::FolderData;
|
||||
@ -13,7 +14,9 @@ use tokio::sync::mpsc::Receiver;
|
||||
|
||||
use tokio::time::timeout;
|
||||
use uuid::Uuid;
|
||||
use zip::ZipArchive;
|
||||
use walkdir::WalkDir;
|
||||
use zip::write::FileOptions;
|
||||
use zip::{CompressionMethod, ZipArchive, ZipWriter};
|
||||
|
||||
use event_integration::event_builder::EventBuilder;
|
||||
use event_integration::Cleaner;
|
||||
@ -163,7 +166,78 @@ pub fn appflowy_server(
|
||||
(SupabaseServerServiceImpl::new(server), encryption_impl)
|
||||
}
|
||||
|
||||
pub fn unzip_history_user_db(root: &str, folder_name: &str) -> std::io::Result<(Cleaner, PathBuf)> {
|
||||
/// zip the asset to the destination
|
||||
/// Zips the specified directory into a zip file.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `src_dir`: Path to the directory to zip.
|
||||
/// - `output_file`: Path to the output zip file.
|
||||
///
|
||||
/// # Errors
|
||||
/// Returns `io::Result<()>` indicating the operation's success or failure.
|
||||
pub fn zip(src_dir: PathBuf, output_file_path: PathBuf) -> io::Result<()> {
|
||||
// Ensure the output directory exists
|
||||
if let Some(parent) = output_file_path.parent() {
|
||||
if !parent.exists() {
|
||||
fs::create_dir_all(parent)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Open or create the output file, truncating it if it exists
|
||||
let file = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(&output_file_path)?;
|
||||
|
||||
let options = FileOptions::default().compression_method(CompressionMethod::Deflated);
|
||||
|
||||
let mut zip = ZipWriter::new(file);
|
||||
|
||||
// Calculate the name of the new folder within the ZIP file based on the last component of the output path
|
||||
let new_folder_name = output_file_path
|
||||
.file_stem()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Invalid output file name"))?;
|
||||
|
||||
let src_dir_str = src_dir.to_str().expect("Invalid source directory path");
|
||||
|
||||
for entry in WalkDir::new(&src_dir).into_iter().filter_map(|e| e.ok()) {
|
||||
let path = entry.path();
|
||||
let relative_path = path
|
||||
.strip_prefix(src_dir_str)
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::Other, "Error calculating relative path"))?;
|
||||
|
||||
// Construct the path within the ZIP, prefixing with the new folder's name
|
||||
let zip_path = Path::new(new_folder_name).join(relative_path);
|
||||
|
||||
if path.is_file() {
|
||||
zip.start_file(
|
||||
zip_path
|
||||
.to_str()
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Invalid file name"))?,
|
||||
options,
|
||||
)?;
|
||||
|
||||
let mut f = File::open(path)?;
|
||||
io::copy(&mut f, &mut zip)?;
|
||||
} else if entry.file_type().is_dir() && !relative_path.as_os_str().is_empty() {
|
||||
zip.add_directory(
|
||||
zip_path
|
||||
.to_str()
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Invalid directory name"))?,
|
||||
options,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
zip.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn unzip_test_asset(folder_name: &str) -> io::Result<(Cleaner, PathBuf)> {
|
||||
unzip("./tests/asset", folder_name)
|
||||
}
|
||||
|
||||
pub fn unzip(root: &str, folder_name: &str) -> io::Result<(Cleaner, PathBuf)> {
|
||||
// Open the zip file
|
||||
let zip_file_path = format!("{}/{}.zip", root, folder_name);
|
||||
let reader = File::open(zip_file_path)?;
|
||||
|
@ -23,6 +23,7 @@ flowy-server-pub = { workspace = true }
|
||||
flowy-config = { workspace = true }
|
||||
flowy-date = { workspace = true }
|
||||
collab-integrate = { workspace = true }
|
||||
flowy-search = { workspace = true }
|
||||
collab-entity = { version = "0.1.0" }
|
||||
collab-plugins = { version = "0.1.0" }
|
||||
collab = { version = "0.1.0" }
|
||||
@ -35,7 +36,7 @@ tracing.workspace = true
|
||||
futures-core = { version = "0.3", default-features = false }
|
||||
bytes.workspace = true
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tokio-stream = { workspace = true, features = ["sync"]}
|
||||
tokio-stream = { workspace = true, features = ["sync"] }
|
||||
console-subscriber = { version = "0.2", optional = true }
|
||||
parking_lot.workspace = true
|
||||
anyhow.workspace = true
|
||||
@ -57,12 +58,16 @@ http_sync = []
|
||||
native_sync = []
|
||||
use_bunyan = ["lib-log/use_bunyan"]
|
||||
dart = [
|
||||
"flowy-user/dart",
|
||||
"flowy-date/dart",
|
||||
"flowy-search/dart",
|
||||
"flowy-folder/dart",
|
||||
"flowy-database2/dart",
|
||||
]
|
||||
ts = [
|
||||
"flowy-user/tauri_ts",
|
||||
"flowy-folder/tauri_ts",
|
||||
"flowy-search/tauri_ts",
|
||||
"flowy-database2/ts",
|
||||
"flowy-config/tauri_ts",
|
||||
]
|
||||
@ -71,6 +76,6 @@ openssl_vendored = ["flowy-sqlite/openssl_vendored"]
|
||||
|
||||
# Enable/Disable AppFlowy Verbose Log Configuration
|
||||
verbose_log = [
|
||||
# "flowy-document/verbose_log",
|
||||
# "flowy-document/verbose_log",
|
||||
"client-api/sync_verbose_log"
|
||||
]
|
||||
]
|
||||
|
@ -16,7 +16,7 @@ use crate::integrate::log::create_log_filter;
|
||||
pub struct AppFlowyCoreConfig {
|
||||
/// Different `AppFlowyCoreConfig` instance should have different name
|
||||
pub(crate) app_version: String,
|
||||
pub(crate) name: String,
|
||||
pub name: String,
|
||||
pub(crate) device_id: String,
|
||||
pub platform: String,
|
||||
/// Used to store the user data
|
||||
|
@ -1,10 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use bytes::Bytes;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use collab_integrate::CollabKVDB;
|
||||
use flowy_database2::entities::DatabaseLayoutPB;
|
||||
@ -21,10 +15,15 @@ use flowy_folder::share::ImportType;
|
||||
use flowy_folder::view_operation::{FolderOperationHandler, FolderOperationHandlers, View};
|
||||
use flowy_folder::ViewLayout;
|
||||
use flowy_folder_pub::folder_builder::NestedViewBuilder;
|
||||
use flowy_search::folder::indexer::FolderIndexManagerImpl;
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
use lib_dispatch::prelude::ToBytes;
|
||||
use lib_infra::async_trait::async_trait;
|
||||
use lib_infra::future::FutureResult;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::integrate::server::ServerProvider;
|
||||
|
||||
@ -36,6 +35,7 @@ impl FolderDepsResolver {
|
||||
database_manager: &Arc<DatabaseManager>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
server_provider: Arc<ServerProvider>,
|
||||
folder_indexer: Arc<FolderIndexManagerImpl>,
|
||||
) -> Arc<FolderManager> {
|
||||
let user: Arc<dyn FolderUser> = Arc::new(FolderUserImpl {
|
||||
authenticate_user: authenticate_user.clone(),
|
||||
@ -48,6 +48,7 @@ impl FolderDepsResolver {
|
||||
collab_builder,
|
||||
handlers,
|
||||
server_provider.clone(),
|
||||
folder_indexer,
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
|
@ -2,12 +2,13 @@ pub use collab_deps::*;
|
||||
pub use database_deps::*;
|
||||
pub use document_deps::*;
|
||||
pub use folder_deps::*;
|
||||
pub use search_deps::*;
|
||||
pub use user_deps::*;
|
||||
|
||||
mod collab_deps;
|
||||
mod document_deps;
|
||||
mod folder_deps;
|
||||
mod util;
|
||||
|
||||
mod database_deps;
|
||||
mod search_deps;
|
||||
mod user_deps;
|
||||
|
12
frontend/rust-lib/flowy-core/src/deps_resolve/search_deps.rs
Normal file
12
frontend/rust-lib/flowy-core/src/deps_resolve/search_deps.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use flowy_search::folder::handler::FolderSearchHandler;
|
||||
use flowy_search::folder::indexer::FolderIndexManagerImpl;
|
||||
use flowy_search::services::manager::SearchManager;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct SearchDepsResolver();
|
||||
impl SearchDepsResolver {
|
||||
pub async fn resolve(folder_indexer: Arc<FolderIndexManagerImpl>) -> Arc<SearchManager> {
|
||||
let folder_handler = Arc::new(FolderSearchHandler::new(folder_indexer));
|
||||
Arc::new(SearchManager::new(vec![folder_handler]))
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
|
@ -25,11 +25,7 @@ pub(crate) fn init_log(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create_log_filter(
|
||||
level: String,
|
||||
with_crates: Vec<String>,
|
||||
platform: Platform,
|
||||
) -> String {
|
||||
pub fn create_log_filter(level: String, with_crates: Vec<String>, platform: Platform) -> String {
|
||||
let mut level = std::env::var("RUST_LOG").unwrap_or(level);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
@ -55,18 +51,15 @@ pub(crate) fn create_log_filter(
|
||||
filters.push(format!("flowy_server={}", level));
|
||||
filters.push(format!("flowy_notification={}", "info"));
|
||||
filters.push(format!("lib_infra={}", level));
|
||||
filters.push(format!("dart_ffi={}", level));
|
||||
filters.push(format!("flowy_search={}", level));
|
||||
|
||||
// ⚠️Enable debug log for dart_ffi, flowy_sqlite and lib_dispatch as needed. Don't enable them by default.
|
||||
{
|
||||
// filters.push(format!("flowy_sqlite={}", "info"));
|
||||
// filters.push(format!("lib_dispatch={}", level));
|
||||
}
|
||||
// Most of the time, we don't need to see the logs from the following crates
|
||||
// filters.push(format!("flowy_sqlite={}", "info"));
|
||||
// filters.push(format!("lib_dispatch={}", level));
|
||||
|
||||
filters.push(format!("client_api={}", level));
|
||||
#[cfg(feature = "profiling")]
|
||||
filters.push(format!("tokio={}", level));
|
||||
|
||||
#[cfg(feature = "profiling")]
|
||||
filters.push(format!("runtime={}", level));
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
pub(crate) mod collab_interact;
|
||||
pub(crate) mod log;
|
||||
pub mod log;
|
||||
pub(crate) mod server;
|
||||
mod trait_impls;
|
||||
pub(crate) mod user;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#![allow(unused_doc_comments)]
|
||||
|
||||
use flowy_search::folder::indexer::FolderIndexManagerImpl;
|
||||
use flowy_search::services::manager::SearchManager;
|
||||
use flowy_storage::ObjectStorageService;
|
||||
use semver::Version;
|
||||
use std::sync::Arc;
|
||||
@ -12,6 +14,7 @@ use collab_integrate::collab_builder::{AppFlowyCollabBuilder, CollabPluginProvid
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document::manager::DocumentManager;
|
||||
use flowy_folder::manager::FolderManager;
|
||||
|
||||
use flowy_sqlite::kv::StorePreferences;
|
||||
use flowy_user::services::authenticate_user::AuthenticateUser;
|
||||
use flowy_user::services::entities::UserConfig;
|
||||
@ -33,7 +36,7 @@ use crate::integrate::user::UserStatusCallbackImpl;
|
||||
|
||||
pub mod config;
|
||||
mod deps_resolve;
|
||||
mod integrate;
|
||||
pub mod integrate;
|
||||
pub mod module;
|
||||
|
||||
/// This name will be used as to identify the current [AppFlowyCore] instance.
|
||||
@ -52,6 +55,7 @@ pub struct AppFlowyCore {
|
||||
pub server_provider: Arc<ServerProvider>,
|
||||
pub task_dispatcher: Arc<RwLock<TaskDispatcher>>,
|
||||
pub store_preference: Arc<StorePreferences>,
|
||||
pub search_manager: Arc<SearchManager>,
|
||||
}
|
||||
|
||||
impl AppFlowyCore {
|
||||
@ -117,6 +121,7 @@ impl AppFlowyCore {
|
||||
database_manager,
|
||||
document_manager,
|
||||
collab_builder,
|
||||
search_manager,
|
||||
) = async {
|
||||
/// The shared collab builder is used to build the [Collab] instance. The plugins will be loaded
|
||||
/// on demand based on the [CollabPluginConfig].
|
||||
@ -157,17 +162,21 @@ impl AppFlowyCore {
|
||||
Arc::downgrade(&(server_provider.clone() as Arc<dyn ObjectStorageService>)),
|
||||
);
|
||||
|
||||
let folder_indexer = Arc::new(FolderIndexManagerImpl::new(Arc::downgrade(
|
||||
&authenticate_user,
|
||||
)));
|
||||
let folder_manager = FolderDepsResolver::resolve(
|
||||
Arc::downgrade(&authenticate_user),
|
||||
&document_manager,
|
||||
&database_manager,
|
||||
collab_builder.clone(),
|
||||
server_provider.clone(),
|
||||
folder_indexer.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
let user_manager = UserDepsResolver::resolve(
|
||||
authenticate_user,
|
||||
authenticate_user.clone(),
|
||||
collab_builder.clone(),
|
||||
server_provider.clone(),
|
||||
store_preference.clone(),
|
||||
@ -176,6 +185,8 @@ impl AppFlowyCore {
|
||||
)
|
||||
.await;
|
||||
|
||||
let search_manager = SearchDepsResolver::resolve(folder_indexer).await;
|
||||
|
||||
(
|
||||
user_manager,
|
||||
folder_manager,
|
||||
@ -183,6 +194,7 @@ impl AppFlowyCore {
|
||||
database_manager,
|
||||
document_manager,
|
||||
collab_builder,
|
||||
search_manager,
|
||||
)
|
||||
}
|
||||
.await;
|
||||
@ -217,6 +229,7 @@ impl AppFlowyCore {
|
||||
Arc::downgrade(&database_manager),
|
||||
Arc::downgrade(&user_manager),
|
||||
Arc::downgrade(&document_manager),
|
||||
Arc::downgrade(&search_manager),
|
||||
),
|
||||
));
|
||||
|
||||
@ -230,6 +243,7 @@ impl AppFlowyCore {
|
||||
server_provider,
|
||||
task_dispatcher,
|
||||
store_preference,
|
||||
search_manager,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ use std::sync::Weak;
|
||||
use flowy_database2::DatabaseManager;
|
||||
use flowy_document::manager::DocumentManager as DocumentManager2;
|
||||
use flowy_folder::manager::FolderManager;
|
||||
use flowy_search::services::manager::SearchManager;
|
||||
use flowy_user::user_manager::UserManager;
|
||||
use lib_dispatch::prelude::AFPlugin;
|
||||
|
||||
@ -11,6 +12,7 @@ pub fn make_plugins(
|
||||
database_manager: Weak<DatabaseManager>,
|
||||
user_session: Weak<UserManager>,
|
||||
document_manager2: Weak<DocumentManager2>,
|
||||
search_manager: Weak<SearchManager>,
|
||||
) -> Vec<AFPlugin> {
|
||||
let store_preferences = user_session
|
||||
.upgrade()
|
||||
@ -22,6 +24,7 @@ pub fn make_plugins(
|
||||
let document_plugin2 = flowy_document::event_map::init(document_manager2);
|
||||
let config_plugin = flowy_config::event_map::init(store_preferences);
|
||||
let date_plugin = flowy_date::event_map::init();
|
||||
let search_plugin = flowy_search::event_map::init(search_manager);
|
||||
vec![
|
||||
user_plugin,
|
||||
folder_plugin,
|
||||
@ -29,5 +32,6 @@ pub fn make_plugins(
|
||||
document_plugin2,
|
||||
config_plugin,
|
||||
date_plugin,
|
||||
search_plugin,
|
||||
]
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ where
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
pub(crate) fn delete_group(&mut self, deleted_group_id: &str) -> FlowyResult<()> {
|
||||
self.group_by_id.remove(deleted_group_id);
|
||||
self.group_by_id.shift_remove(deleted_group_id);
|
||||
self.mut_configuration(|configuration| {
|
||||
configuration
|
||||
.groups
|
||||
|
@ -19,9 +19,9 @@ date_time_parser = { version = "0.2.0" }
|
||||
chrono.workspace = true
|
||||
fancy-regex = { version = "0.11.0" }
|
||||
|
||||
[build-dependencies]
|
||||
flowy-codegen.workspace = true
|
||||
|
||||
[features]
|
||||
dart = ["flowy-codegen/dart"]
|
||||
tauri_ts = ["flowy-codegen/ts"]
|
||||
|
||||
[build-dependencies]
|
||||
flowy-codegen.workspace = true
|
||||
|
@ -3,6 +3,7 @@ use crate::entities::{
|
||||
};
|
||||
use crate::notification::{send_notification, DocumentNotification};
|
||||
use collab::core::collab::MutexCollab;
|
||||
use collab_document::document::DocumentIndexContent;
|
||||
use collab_document::{blocks::DocumentData, document::Document};
|
||||
use flowy_error::FlowyResult;
|
||||
use futures::StreamExt;
|
||||
@ -141,3 +142,10 @@ impl DerefMut for MutexDocument {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&MutexDocument> for DocumentIndexContent {
|
||||
fn from(doc: &MutexDocument) -> Self {
|
||||
let doc = doc.lock();
|
||||
DocumentIndexContent::from(&*doc)
|
||||
}
|
||||
}
|
||||
|
@ -11,3 +11,4 @@ pub mod deps;
|
||||
pub mod notification;
|
||||
mod parse;
|
||||
pub mod reminder;
|
||||
pub use collab_document::document::DocumentIndexContent;
|
||||
|
@ -14,7 +14,7 @@ bytes.workspace = true
|
||||
anyhow.workspace = true
|
||||
thiserror = "1.0"
|
||||
validator = "0.16.0"
|
||||
tokio = { workspace = true, features = ["sync"]}
|
||||
tokio = { workspace = true, features = ["sync", "rt"] }
|
||||
|
||||
fancy-regex = { version = "0.11.0" }
|
||||
lib-dispatch = { workspace = true, optional = true }
|
||||
@ -32,16 +32,23 @@ collab-document = { version = "0.1.0", optional = true }
|
||||
collab-plugins = { version = "0.1.0", optional = true }
|
||||
collab-folder = { version = "0.1.0", optional = true }
|
||||
client-api = { version = "0.1.0", optional = true }
|
||||
tantivy = { version = "0.21.1", optional = true }
|
||||
|
||||
|
||||
[features]
|
||||
impl_from_dispatch_error = ["lib-dispatch"]
|
||||
impl_from_serde = []
|
||||
impl_from_reqwest = ["reqwest"]
|
||||
impl_from_collab_persistence = ["collab-plugins"]
|
||||
impl_from_collab_document = ["collab-document", "impl_from_reqwest", "collab-plugins"]
|
||||
impl_from_collab_document = [
|
||||
"collab-document",
|
||||
"impl_from_reqwest",
|
||||
"collab-plugins",
|
||||
]
|
||||
impl_from_collab_folder = ["collab-folder"]
|
||||
impl_from_collab_database= ["collab-database"]
|
||||
impl_from_collab_database = ["collab-database"]
|
||||
impl_from_url = ["url"]
|
||||
impl_from_tantivy = ["tantivy"]
|
||||
|
||||
impl_from_sqlite = ["flowy-sqlite", "r2d2"]
|
||||
impl_from_appflowy_cloud = ["client-api"]
|
||||
@ -50,6 +57,4 @@ tauri_ts = ["flowy-codegen/ts"]
|
||||
web_ts = ["flowy-codegen/ts"]
|
||||
|
||||
[build-dependencies]
|
||||
flowy-codegen = { workspace = true, features = [
|
||||
"proto_gen",
|
||||
] }
|
||||
flowy-codegen = { workspace = true, features = ["proto_gen"] }
|
||||
|
@ -265,6 +265,18 @@ pub enum ErrorCode {
|
||||
|
||||
#[error("Workspace member limit exceeded")]
|
||||
WorkspaceMemberLimitExceeded = 92,
|
||||
|
||||
#[error("IndexWriter failed to commit")]
|
||||
IndexWriterFailedCommit = 93,
|
||||
|
||||
#[error("Failed to open Index directory")]
|
||||
FailedToOpenIndexDir = 94,
|
||||
|
||||
#[error("Failed to parse query")]
|
||||
FailedToParseQuery = 95,
|
||||
|
||||
#[error("FolderIndexManager or its dependencies are unavailable")]
|
||||
FolderIndexManagerUnavailable = 96,
|
||||
}
|
||||
|
||||
impl ErrorCode {
|
||||
|
@ -113,6 +113,10 @@ impl FlowyError {
|
||||
static_flowy_error!(server_error, ErrorCode::InternalServerError);
|
||||
static_flowy_error!(not_support, ErrorCode::NotSupportYet);
|
||||
static_flowy_error!(local_version_not_support, ErrorCode::LocalVersionNotSupport);
|
||||
static_flowy_error!(
|
||||
folder_index_manager_unavailable,
|
||||
ErrorCode::FolderIndexManagerUnavailable
|
||||
);
|
||||
}
|
||||
|
||||
impl std::convert::From<ErrorCode> for FlowyError {
|
||||
|
@ -24,3 +24,6 @@ mod cloud;
|
||||
|
||||
#[cfg(feature = "impl_from_url")]
|
||||
mod url;
|
||||
|
||||
#[cfg(feature = "impl_from_tantivy")]
|
||||
mod tantivy;
|
||||
|
21
frontend/rust-lib/flowy-error/src/impl_from/tantivy.rs
Normal file
21
frontend/rust-lib/flowy-error/src/impl_from/tantivy.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use tantivy::{directory::error::OpenDirectoryError, query::QueryParserError, TantivyError};
|
||||
|
||||
use crate::{ErrorCode, FlowyError};
|
||||
|
||||
impl std::convert::From<TantivyError> for FlowyError {
|
||||
fn from(error: TantivyError) -> Self {
|
||||
FlowyError::new(ErrorCode::IndexWriterFailedCommit, error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<OpenDirectoryError> for FlowyError {
|
||||
fn from(error: OpenDirectoryError) -> Self {
|
||||
FlowyError::new(ErrorCode::FailedToOpenIndexDir, error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<QueryParserError> for FlowyError {
|
||||
fn from(error: QueryParserError) -> Self {
|
||||
FlowyError::new(ErrorCode::FailedToParseQuery, error)
|
||||
}
|
||||
}
|
@ -23,3 +23,19 @@ pub struct ImportViews {
|
||||
/// Used to update the [DatabaseViewTrackerList] when importing the database.
|
||||
pub database_view_ids_by_database_id: HashMap<String, Vec<String>>,
|
||||
}
|
||||
|
||||
pub struct SearchData {
|
||||
/// The type of data that is stored in the search index row.
|
||||
pub index_type: String,
|
||||
|
||||
/// The `View` that the row references.
|
||||
pub view_id: String,
|
||||
|
||||
/// The ID that corresponds to the type that is stored.
|
||||
/// View: view_id
|
||||
/// Document: page_id
|
||||
pub id: String,
|
||||
|
||||
/// The data that is stored in the search index row.
|
||||
pub data: String,
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
pub mod cloud;
|
||||
pub mod entities;
|
||||
pub mod folder_builder;
|
||||
mod folder_service;
|
||||
|
@ -8,24 +8,29 @@ edition = "2021"
|
||||
[dependencies]
|
||||
collab = { version = "0.1.0" }
|
||||
collab-folder = { version = "0.1.0" }
|
||||
collab-document = { version = "0.1.0" }
|
||||
collab-entity = { version = "0.1.0" }
|
||||
collab-plugins = { version = "0.1.0" }
|
||||
collab-integrate = { workspace = true }
|
||||
flowy-folder-pub = { workspace = true }
|
||||
flowy-search-pub = { workspace = true }
|
||||
|
||||
flowy-derive.workspace = true
|
||||
flowy-notification = { workspace = true }
|
||||
flowy-notification = { workspace = true }
|
||||
parking_lot.workspace = true
|
||||
unicode-segmentation = "1.10"
|
||||
tracing.workspace = true
|
||||
flowy-error = { path = "../flowy-error", features = ["impl_from_dispatch_error", "impl_from_collab_folder"]}
|
||||
flowy-error = { path = "../flowy-error", features = [
|
||||
"impl_from_dispatch_error",
|
||||
"impl_from_collab_folder",
|
||||
] }
|
||||
lib-dispatch = { workspace = true }
|
||||
bytes.workspace = true
|
||||
lib-infra = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
nanoid = "0.4.0"
|
||||
lazy_static = "1.4.0"
|
||||
chrono = { workspace = true, default-features = false, features = ["clock"] }
|
||||
chrono = { workspace = true, default-features = false, features = ["clock"] }
|
||||
strum_macros = "0.21"
|
||||
protobuf.workspace = true
|
||||
uuid.workspace = true
|
||||
|
@ -28,6 +28,7 @@ use collab_integrate::{CollabKVDB, CollabPersistenceConfig};
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_folder_pub::cloud::{gen_view_id, FolderCloudService};
|
||||
use flowy_folder_pub::folder_builder::ParentChildViews;
|
||||
use flowy_search_pub::entities::FolderIndexManager;
|
||||
use lib_infra::conditional_send_sync_trait;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use std::fmt::{Display, Formatter};
|
||||
@ -44,12 +45,16 @@ conditional_send_sync_trait! {
|
||||
}
|
||||
|
||||
pub struct FolderManager {
|
||||
/// workspace_id represents as the id of the Folder.
|
||||
pub(crate) workspace_id: RwLock<Option<String>>,
|
||||
|
||||
/// MutexFolder is the folder that is used to store the data.
|
||||
pub(crate) mutex_folder: Arc<MutexFolder>,
|
||||
pub(crate) collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
pub(crate) user: Arc<dyn FolderUser>,
|
||||
pub(crate) operation_handlers: FolderOperationHandlers,
|
||||
pub cloud_service: Arc<dyn FolderCloudService>,
|
||||
pub(crate) folder_indexer: Arc<dyn FolderIndexManager>,
|
||||
}
|
||||
|
||||
impl FolderManager {
|
||||
@ -58,6 +63,7 @@ impl FolderManager {
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
operation_handlers: FolderOperationHandlers,
|
||||
cloud_service: Arc<dyn FolderCloudService>,
|
||||
folder_indexer: Arc<dyn FolderIndexManager>,
|
||||
) -> FlowyResult<Self> {
|
||||
let mutex_folder = Arc::new(MutexFolder::default());
|
||||
let manager = Self {
|
||||
@ -67,6 +73,7 @@ impl FolderManager {
|
||||
operation_handlers,
|
||||
cloud_service,
|
||||
workspace_id: Default::default(),
|
||||
folder_indexer,
|
||||
};
|
||||
|
||||
Ok(manager)
|
||||
@ -134,7 +141,7 @@ impl FolderManager {
|
||||
if let Some(workspace_id) = workspace_id {
|
||||
self.get_workspace_public_views(&workspace_id).await
|
||||
} else {
|
||||
tracing::warn!("Can't get current workspace views");
|
||||
tracing::warn!("Can't get the workspace id from the folder. Return empty list.");
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
@ -463,6 +470,13 @@ impl FolderManager {
|
||||
},
|
||||
);
|
||||
|
||||
if let Ok(workspace_id) = self.get_current_workspace_id().await {
|
||||
let folder = &self.mutex_folder.lock();
|
||||
if let Some(folder) = folder.as_ref() {
|
||||
notify_did_update_workspace(&workspace_id, folder);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(view)
|
||||
}
|
||||
|
||||
@ -1301,6 +1315,8 @@ pub(crate) fn get_workspace_private_view_pbs(_workspace_id: &str, folder: &Folde
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// The MutexFolder is a wrapper of the [Folder] that is used to share the folder between different
|
||||
/// threads.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct MutexFolder(Arc<Mutex<Option<Folder>>>);
|
||||
impl Deref for MutexFolder {
|
||||
|
@ -1,6 +1,8 @@
|
||||
use collab_entity::CollabType;
|
||||
|
||||
use collab_folder::{Folder, FolderNotify, UserId};
|
||||
use tokio::task::spawn_blocking;
|
||||
use tracing::{event, Level};
|
||||
|
||||
use collab_integrate::CollabKVDB;
|
||||
|
||||
@ -8,7 +10,6 @@ use flowy_error::{FlowyError, FlowyResult};
|
||||
|
||||
use collab::core::collab::DocStateSource;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{event, Level};
|
||||
|
||||
use crate::manager::{FolderInitDataSource, FolderManager};
|
||||
use crate::manager_observer::{
|
||||
@ -129,6 +130,22 @@ impl FolderManager {
|
||||
};
|
||||
|
||||
let folder_state_rx = folder.subscribe_sync_state();
|
||||
let index_content_rx = folder.subscribe_index_content();
|
||||
self
|
||||
.folder_indexer
|
||||
.set_index_content_receiver(index_content_rx);
|
||||
|
||||
// Index all views in the folder if needed
|
||||
if !self.folder_indexer.is_indexed() {
|
||||
let views = folder.get_all_views_recursively();
|
||||
let folder_indexer = self.folder_indexer.clone();
|
||||
|
||||
// We spawn a blocking task to index all views in the folder
|
||||
spawn_blocking(move || {
|
||||
folder_indexer.index_all_views(views);
|
||||
});
|
||||
}
|
||||
|
||||
*self.mutex_folder.lock() = Some(folder);
|
||||
|
||||
let weak_mutex_folder = Arc::downgrade(&self.mutex_folder);
|
||||
|
12
frontend/rust-lib/flowy-search-pub/Cargo.toml
Normal file
12
frontend/rust-lib/flowy-search-pub/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "flowy-search-pub"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
collab = { version = "0.1.0" }
|
||||
collab-folder = { version = "0.1.0" }
|
||||
|
||||
flowy-error = { workspace = true }
|
26
frontend/rust-lib/flowy-search-pub/src/entities.rs
Normal file
26
frontend/rust-lib/flowy-search-pub/src/entities.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use std::any::Any;
|
||||
|
||||
use collab::core::collab::IndexContentReceiver;
|
||||
use collab_folder::{View, ViewIcon, ViewLayout};
|
||||
use flowy_error::FlowyError;
|
||||
|
||||
pub struct IndexableData {
|
||||
pub id: String,
|
||||
pub data: String,
|
||||
pub icon: Option<ViewIcon>,
|
||||
pub layout: ViewLayout,
|
||||
}
|
||||
|
||||
pub trait IndexManager: Send + Sync {
|
||||
fn set_index_content_receiver(&self, rx: IndexContentReceiver);
|
||||
fn add_index(&self, data: IndexableData) -> Result<(), FlowyError>;
|
||||
fn update_index(&self, data: IndexableData) -> Result<(), FlowyError>;
|
||||
fn remove_indices(&self, ids: Vec<String>) -> Result<(), FlowyError>;
|
||||
fn is_indexed(&self) -> bool;
|
||||
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
}
|
||||
|
||||
pub trait FolderIndexManager: IndexManager {
|
||||
fn index_all_views(&self, views: Vec<View>);
|
||||
}
|
1
frontend/rust-lib/flowy-search-pub/src/lib.rs
Normal file
1
frontend/rust-lib/flowy-search-pub/src/lib.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod entities;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user