docs: update code documentation (#1804)

* docs: update code documentation

* chore: fix bloc test

* chore: reduce lock granularity

* chore: fix bloc test
This commit is contained in:
Nathan.fooo 2023-02-06 15:59:30 +08:00 committed by GitHub
parent 4d5063de6a
commit 1df2619c9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 199 additions and 213 deletions

View File

@ -58,7 +58,7 @@
"label": "AF: Build Appflowy Core",
"type": "shell",
"windows": {
"command": "cargo make --profile development-windows appflowy-core-dev"
"command": "cargo make --profile development-windows-x86 appflowy-core-dev"
},
"linux": {
"command": "cargo make --profile \"development-linux-$(uname -m)\" appflowy-core-dev"

View File

@ -34,7 +34,7 @@ class DocumentPluginBuilder extends PluginBuilder {
PluginType get pluginType => PluginType.editor;
@override
ViewDataFormatPB get dataFormatType => ViewDataFormatPB.TreeFormat;
ViewDataFormatPB get dataFormatType => ViewDataFormatPB.NodeFormat;
}
class DocumentPlugin extends Plugin<int> {

View File

@ -147,8 +147,10 @@ class SelectOptionCellEditorBloc
}
void _filterOption(String optionName, Emitter<SelectOptionEditorState> emit) {
final _MakeOptionResult result =
_makeOptions(Some(optionName), state.allOptions);
final _MakeOptionResult result = _makeOptions(
Some(optionName),
state.allOptions,
);
emit(state.copyWith(
filter: Some(optionName),
options: result.options,
@ -159,6 +161,7 @@ class SelectOptionCellEditorBloc
Future<void> _loadOptions() async {
final result = await _selectOptionService.getOptionContext();
if (isClosed) {
Log.warn("Unexpected closing the bloc");
return;
}
@ -177,7 +180,9 @@ class SelectOptionCellEditorBloc
}
_MakeOptionResult _makeOptions(
Option<String> filter, List<SelectOptionPB> allOptions) {
Option<String> filter,
List<SelectOptionPB> allOptions,
) {
final List<SelectOptionPB> options = List.from(allOptions);
Option<String> createOption = filter;

View File

@ -12,7 +12,7 @@ import 'type_option_context.dart';
class TypeOptionDataController {
final String databaseId;
final IFieldTypeOptionLoader loader;
late TypeOptionPB _data;
late TypeOptionPB _typeOptiondata;
final PublishNotifier<FieldPB> _fieldNotifier = PublishNotifier();
/// Returns a [TypeOptionDataController] used to modify the specified
@ -27,7 +27,7 @@ class TypeOptionDataController {
FieldInfo? fieldInfo,
}) {
if (fieldInfo != null) {
_data = TypeOptionPB.create()
_typeOptiondata = TypeOptionPB.create()
..databaseId = databaseId
..field_2 = fieldInfo.field;
}
@ -38,7 +38,7 @@ class TypeOptionDataController {
return result.fold(
(data) {
data.freeze();
_data = data;
_typeOptiondata = data;
_fieldNotifier.value = data.field_2;
return left(data);
},
@ -50,28 +50,28 @@ class TypeOptionDataController {
}
FieldPB get field {
return _data.field_2;
return _typeOptiondata.field_2;
}
T getTypeOption<T>(TypeOptionDataParser<T> parser) {
return parser.fromBuffer(_data.typeOptionData);
return parser.fromBuffer(_typeOptiondata.typeOptionData);
}
set fieldName(String name) {
_data = _data.rebuild((rebuildData) {
_typeOptiondata = _typeOptiondata.rebuild((rebuildData) {
rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
rebuildField.name = name;
});
});
_fieldNotifier.value = _data.field_2;
_fieldNotifier.value = _typeOptiondata.field_2;
FieldService(databaseId: databaseId, fieldId: field.id)
.updateField(name: name);
}
set typeOptionData(List<int> typeOptionData) {
_data = _data.rebuild((rebuildData) {
_typeOptiondata = _typeOptiondata.rebuild((rebuildData) {
if (typeOptionData.isNotEmpty) {
rebuildData.typeOptionData = typeOptionData;
}

View File

@ -52,7 +52,7 @@ abstract class PluginBuilder {
PluginType get pluginType;
ViewDataFormatPB get dataFormatType => ViewDataFormatPB.TreeFormat;
ViewDataFormatPB get dataFormatType => ViewDataFormatPB.NodeFormat;
ViewLayoutTypePB? get layoutType => ViewLayoutTypePB.Document;
}

View File

@ -76,7 +76,7 @@ class AppService {
..to = toIndex
..ty = MoveFolderItemType.MoveView;
return FolderEventMoveFolderItem(payload).send();
return FolderEventMoveItem(payload).send();
}
Future<List<Tuple2<AppPB, List<ViewPB>>>> fetchViews(

View File

@ -65,6 +65,6 @@ class WorkspaceService {
..to = toIndex
..ty = MoveFolderItemType.MoveApp;
return FolderEventMoveFolderItem(payload).send();
return FolderEventMoveItem(payload).send();
}
}

View File

@ -33,7 +33,7 @@ void main() {
final gridGroupBloc = GridGroupBloc(
viewId: context.gridView.id,
fieldController: context.fieldController,
);
)..add(const GridGroupEvent.initial());
gridGroupBloc.add(GridGroupEvent.setGroupByField(
checkboxField.id,
checkboxField.fieldType,

View File

@ -14,7 +14,7 @@ void main() {
boardTest = await AppFlowyBoardTest.ensureInitialized();
});
test('group by multi select with no options test', () async {
test('no status group name test', () async {
final context = await boardTest.createTestBoard();
// create multi-select field
@ -27,7 +27,9 @@ void main() {
final gridGroupBloc = GridGroupBloc(
viewId: context.gridView.id,
fieldController: context.fieldController,
);
)..add(const GridGroupEvent.initial());
await boardResponseFuture();
gridGroupBloc.add(GridGroupEvent.setGroupByField(
multiSelectField.id,
multiSelectField.fieldType,
@ -72,7 +74,9 @@ void main() {
final gridGroupBloc = GridGroupBloc(
viewId: context.gridView.id,
fieldController: context.fieldController,
);
)..add(const GridGroupEvent.initial());
await boardResponseFuture();
gridGroupBloc.add(GridGroupEvent.setGroupByField(
multiSelectField.id,
multiSelectField.fieldType,

View File

@ -64,15 +64,24 @@ void main() {
bloc.add(const SelectOptionEditorEvent.newOption("A"));
await gridResponseFuture();
assert(bloc.state.options.length == 1,
"Expect 1 but receive ${bloc.state.options.length}, Options: ${bloc.state.options}");
bloc.add(const SelectOptionEditorEvent.newOption("B"));
await gridResponseFuture();
assert(bloc.state.options.length == 2,
"Expect 2 but receive ${bloc.state.options.length}, Options: ${bloc.state.options}");
bloc.add(const SelectOptionEditorEvent.newOption("C"));
await gridResponseFuture();
assert(bloc.state.options.length == 3,
"Expect 3 but receive ${bloc.state.options.length}. Options: ${bloc.state.options}");
bloc.add(const SelectOptionEditorEvent.deleteAllOptions());
await gridResponseFuture();
assert(bloc.state.options.isEmpty);
assert(bloc.state.options.isEmpty,
"Expect empty but receive ${bloc.state.options.length}");
});
test('select/unselect option', () async {
@ -161,18 +170,41 @@ void main() {
bloc.add(const SelectOptionEditorEvent.newOption("abcd"));
await gridResponseFuture();
expect(
bloc.state.options.length,
1,
reason: "Options: ${bloc.state.options}",
);
bloc.add(const SelectOptionEditorEvent.newOption("aaaa"));
await gridResponseFuture();
expect(
bloc.state.options.length,
2,
reason: "Options: ${bloc.state.options}",
);
bloc.add(const SelectOptionEditorEvent.newOption("defg"));
await gridResponseFuture();
expect(
bloc.state.options.length,
3,
reason: "Options: ${bloc.state.options}",
);
bloc.add(const SelectOptionEditorEvent.filterOption("a"));
await gridResponseFuture();
expect(bloc.state.options.length, 2);
expect(bloc.state.allOptions.length, 3);
expect(
bloc.state.options.length,
2,
reason: "Options: ${bloc.state.options}",
);
expect(
bloc.state.allOptions.length,
3,
reason: "Options: ${bloc.state.options}",
);
expect(bloc.state.createOption, const Some("a"));
expect(bloc.state.filter, const Some("a"));
});

View File

@ -1,6 +1,5 @@
import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
import 'package:flutter_test/flutter_test.dart';
import '../util.dart';
@ -28,75 +27,69 @@ void main() {
gridTest = await AppFlowyGridTest.ensureInitialized();
});
group('$FieldEditorBloc', () {
late FieldEditorBloc editorBloc;
test('rename field', () async {
final editorBloc = await makeEditorBloc(gridTest);
editorBloc.add(const FieldEditorEvent.updateName('Hello world'));
await gridResponseFuture();
setUp(() async {
final context = await gridTest.createTestGrid();
final fieldInfo = context.singleSelectFieldContext();
final loader = FieldTypeOptionLoader(
databaseId: context.gridView.id,
field: fieldInfo.field,
);
editorBloc = FieldEditorBloc(
databaseId: context.gridView.id,
fieldName: fieldInfo.name,
isGroupField: fieldInfo.isGroupField,
loader: loader,
)..add(const FieldEditorEvent.initial());
await gridResponseFuture();
});
blocTest<FieldEditorBloc, FieldEditorState>(
"rename field",
build: () => editorBloc,
act: (bloc) async {
editorBloc.add(const FieldEditorEvent.updateName('Hello world'));
},
wait: gridResponseDuration(),
verify: (bloc) {
bloc.state.field.fold(
() => throw Exception("The field should not be none"),
(field) {
assert(field.name == 'Hello world');
},
);
editorBloc.state.field.fold(
() => throw Exception("The field should not be none"),
(field) {
assert(field.name == 'Hello world');
},
);
});
blocTest<FieldEditorBloc, FieldEditorState>(
"switch to text field",
build: () => editorBloc,
act: (bloc) async {
editorBloc
.add(const FieldEditorEvent.switchToField(FieldType.RichText));
},
wait: gridResponseDuration(),
verify: (bloc) {
bloc.state.field.fold(
() => throw Exception("The field should not be none"),
(field) {
// The default length of the fields is 3. The length of the fields
// should not change after switching to other field type
// assert(gridTest.fieldContexts.length == 3);
assert(field.fieldType == FieldType.RichText);
},
);
test('switch to text field', () async {
final editorBloc = await makeEditorBloc(gridTest);
editorBloc.add(const FieldEditorEvent.switchToField(FieldType.RichText));
await gridResponseFuture();
editorBloc.state.field.fold(
() => throw Exception("The field should not be none"),
(field) {
// The default length of the fields is 3. The length of the fields
// should not change after switching to other field type
// assert(gridTest.fieldContexts.length == 3);
assert(field.fieldType == FieldType.RichText);
},
);
});
blocTest<FieldEditorBloc, FieldEditorState>(
"delete field",
build: () => editorBloc,
act: (bloc) async {
editorBloc.add(const FieldEditorEvent.deleteField());
},
wait: gridResponseDuration(),
verify: (bloc) {
// assert(gridTest.fieldContexts.length == 2);
test('delete field', () async {
final editorBloc = await makeEditorBloc(gridTest);
editorBloc.add(const FieldEditorEvent.switchToField(FieldType.RichText));
await gridResponseFuture();
editorBloc.state.field.fold(
() => throw Exception("The field should not be none"),
(field) {
// The default length of the fields is 3. The length of the fields
// should not change after switching to other field type
// assert(gridTest.fieldContexts.length == 3);
assert(field.fieldType == FieldType.RichText);
},
);
});
}
Future<FieldEditorBloc> makeEditorBloc(AppFlowyGridTest gridTest) async {
final context = await gridTest.createTestGrid();
final fieldInfo = context.singleSelectFieldContext();
final loader = FieldTypeOptionLoader(
databaseId: context.gridView.id,
field: fieldInfo.field,
);
final editorBloc = FieldEditorBloc(
databaseId: context.gridView.id,
fieldName: fieldInfo.name,
isGroupField: fieldInfo.isGroupField,
loader: loader,
)..add(const FieldEditorEvent.initial());
await gridResponseFuture();
return editorBloc;
}

View File

@ -210,7 +210,7 @@ class AppFlowyGridCellTest {
Future<GridSelectOptionCellController> makeSelectOptionCellController(
FieldType fieldType, int rowIndex) async {
return context.makeSelectOptionCellController(fieldType, rowIndex);
return await context.makeSelectOptionCellController(fieldType, rowIndex);
}
}

View File

@ -46,7 +46,7 @@ void main() {
viewBloc.add(const ViewEvent.duplicate());
await blocResponseFuture();
assert(appBloc.state.views.length == 2);
expect(appBloc.state.views.length, 2);
});
test('delete view test', () async {
@ -59,7 +59,7 @@ void main() {
DocumentPluginBuilder(),
));
await blocResponseFuture();
assert(appBloc.state.views.length == 1);
expect(appBloc.state.views.length, 1);
final viewBloc = ViewBloc(view: appBloc.state.views.first)
..add(const ViewEvent.initial());

View File

@ -211,7 +211,7 @@ impl ViewDataProcessor for DocumentViewDataProcessor {
}
fn data_types(&self) -> Vec<ViewDataFormatPB> {
vec![ViewDataFormatPB::DeltaFormat, ViewDataFormatPB::TreeFormat]
vec![ViewDataFormatPB::DeltaFormat, ViewDataFormatPB::NodeFormat]
}
}

View File

@ -297,7 +297,7 @@ impl UserStatusListener {
async fn did_sign_up(&self, user_profile: &UserProfile) -> FlowyResult<()> {
let view_data_type = match self.config.document.version {
DocumentVersionPB::V0 => ViewDataFormatPB::DeltaFormat,
DocumentVersionPB::V1 => ViewDataFormatPB::TreeFormat,
DocumentVersionPB::V1 => ViewDataFormatPB::NodeFormat,
};
self.folder_manager
.initialize_with_new_user(&user_profile.id, &user_profile.token, view_data_type)

View File

@ -5,6 +5,7 @@ use crate::services::field::*;
use crate::services::filter::{FilterChangeset, FilterResult, FilterResultNotification, FilterType};
use crate::services::row::DatabaseBlockRowRevision;
use crate::services::view_editor::{GridViewChanged, GridViewChangedNotifier};
use dashmap::DashMap;
use flowy_error::FlowyResult;
use flowy_task::{QualityOfService, Task, TaskContent, TaskDispatcher};
use grid_model::{CellRevision, FieldId, FieldRevision, FilterRevision, RowRevision};
@ -34,7 +35,7 @@ pub struct FilterController {
view_id: String,
handler_id: String,
delegate: Box<dyn FilterDelegate>,
result_by_row_id: HashMap<RowId, FilterResult>,
result_by_row_id: DashMap<RowId, FilterResult>,
cell_data_cache: AtomicCellDataCache,
cell_filter_cache: AtomicCellFilterCache,
task_scheduler: Arc<RwLock<TaskDispatcher>>,
@ -54,11 +55,11 @@ impl FilterController {
where
T: FilterDelegate + 'static,
{
let mut this = Self {
let this = Self {
view_id: view_id.to_string(),
handler_id: handler_id.to_string(),
delegate: Box::new(delegate),
result_by_row_id: HashMap::default(),
result_by_row_id: DashMap::default(),
cell_data_cache,
cell_filter_cache: AnyTypeCache::<FilterType>::new(),
task_scheduler,
@ -83,7 +84,7 @@ impl FilterController {
self.task_scheduler.write().await.add_task(task);
}
pub async fn filter_row_revs(&mut self, row_revs: &mut Vec<Arc<RowRevision>>) {
pub async fn filter_row_revs(&self, row_revs: &mut Vec<Arc<RowRevision>>) {
if self.cell_filter_cache.read().is_empty() {
return;
}
@ -91,7 +92,7 @@ impl FilterController {
row_revs.iter().for_each(|row_rev| {
let _ = filter_row(
row_rev,
&mut self.result_by_row_id,
&self.result_by_row_id,
&field_rev_by_field_id,
&self.cell_data_cache,
&self.cell_filter_cache,
@ -116,7 +117,7 @@ impl FilterController {
}
#[tracing::instrument(name = "process_filter_task", level = "trace", skip_all, fields(filter_result), err)]
pub async fn process(&mut self, predicate: &str) -> FlowyResult<()> {
pub async fn process(&self, predicate: &str) -> FlowyResult<()> {
let event_type = FilterEvent::from_str(predicate).unwrap();
match event_type {
FilterEvent::FilterDidChanged => self.filter_all_rows().await?,
@ -125,13 +126,13 @@ impl FilterController {
Ok(())
}
async fn filter_row(&mut self, row_id: String) -> FlowyResult<()> {
async fn filter_row(&self, row_id: String) -> FlowyResult<()> {
if let Some((_, row_rev)) = self.delegate.get_row_rev(&row_id).await {
let field_rev_by_field_id = self.get_filter_revs_map().await;
let mut notification = FilterResultNotification::new(self.view_id.clone(), row_rev.block_id.clone());
if let Some((row_id, is_visible)) = filter_row(
&row_rev,
&mut self.result_by_row_id,
&self.result_by_row_id,
&field_rev_by_field_id,
&self.cell_data_cache,
&self.cell_filter_cache,
@ -153,7 +154,7 @@ impl FilterController {
Ok(())
}
async fn filter_all_rows(&mut self) -> FlowyResult<()> {
async fn filter_all_rows(&self) -> FlowyResult<()> {
let field_rev_by_field_id = self.get_filter_revs_map().await;
for block in self.delegate.get_blocks().await.into_iter() {
// The row_ids contains the row that its visibility was changed.
@ -163,7 +164,7 @@ impl FilterController {
for (index, row_rev) in block.row_revs.iter().enumerate() {
if let Some((row_id, is_visible)) = filter_row(
row_rev,
&mut self.result_by_row_id,
&self.result_by_row_id,
&field_rev_by_field_id,
&self.cell_data_cache,
&self.cell_filter_cache,
@ -198,7 +199,7 @@ impl FilterController {
}
#[tracing::instrument(level = "trace", skip(self))]
pub async fn did_receive_changes(&mut self, changeset: FilterChangeset) -> Option<FilterChangesetNotificationPB> {
pub async fn did_receive_changes(&self, changeset: FilterChangeset) -> Option<FilterChangesetNotificationPB> {
let mut notification: Option<FilterChangesetNotificationPB> = None;
if let Some(filter_type) = &changeset.insert_filter {
if let Some(filter) = self.filter_from_filter_type(filter_type).await {
@ -258,7 +259,7 @@ impl FilterController {
}
#[tracing::instrument(level = "trace", skip_all)]
async fn refresh_filters(&mut self, filter_revs: Vec<Arc<FilterRevision>>) {
async fn refresh_filters(&self, filter_revs: Vec<Arc<FilterRevision>>) {
for filter_rev in filter_revs {
if let Some(field_rev) = self.delegate.get_field_rev(&filter_rev.field_id).await {
let filter_type = FilterType::from(&field_rev);
@ -309,13 +310,13 @@ impl FilterController {
#[tracing::instrument(level = "trace", skip_all)]
fn filter_row(
row_rev: &Arc<RowRevision>,
result_by_row_id: &mut HashMap<RowId, FilterResult>,
result_by_row_id: &DashMap<RowId, FilterResult>,
field_rev_by_field_id: &HashMap<FieldId, Arc<FieldRevision>>,
cell_data_cache: &AtomicCellDataCache,
cell_filter_cache: &AtomicCellFilterCache,
) -> Option<(String, bool)> {
// Create a filter result cache if it's not exist
let filter_result = result_by_row_id
let mut filter_result = result_by_row_id
.entry(row_rev.id.clone())
.or_insert_with(FilterResult::default);
let old_is_visible = filter_result.is_visible();

View File

@ -3,15 +3,14 @@ use flowy_task::{TaskContent, TaskHandler};
use lib_infra::future::BoxResultFuture;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
pub struct FilterTaskHandler {
handler_id: String,
filter_controller: Arc<RwLock<FilterController>>,
filter_controller: Arc<FilterController>,
}
impl FilterTaskHandler {
pub fn new(handler_id: String, filter_controller: Arc<RwLock<FilterController>>) -> Self {
pub fn new(handler_id: String, filter_controller: Arc<FilterController>) -> Self {
Self {
handler_id,
filter_controller,
@ -33,8 +32,6 @@ impl TaskHandler for FilterTaskHandler {
Box::pin(async move {
if let TaskContent::Text(predicate) = content {
filter_controller
.write()
.await
.process(&predicate)
.await
.map_err(anyhow::Error::from)?;

View File

@ -74,7 +74,7 @@ pub struct DatabaseViewRevisionEditor {
rev_manager: Arc<RevisionManager<Arc<ConnectionPool>>>,
delegate: Arc<dyn DatabaseViewEditorDelegate>,
group_controller: Arc<RwLock<Box<dyn GroupController>>>,
filter_controller: Arc<RwLock<FilterController>>,
filter_controller: Arc<FilterController>,
sort_controller: Arc<RwLock<SortController>>,
pub notifier: GridViewChangedNotifier,
}
@ -156,7 +156,7 @@ impl DatabaseViewRevisionEditor {
pub async fn close(&self) {
self.rev_manager.generate_snapshot().await;
self.rev_manager.close().await;
self.filter_controller.read().await.close().await;
self.filter_controller.close().await;
self.sort_controller.read().await.close().await;
}
@ -194,7 +194,7 @@ impl DatabaseViewRevisionEditor {
}
pub async fn filter_rows(&self, _block_id: &str, rows: &mut Vec<Arc<RowRevision>>) {
self.filter_controller.write().await.filter_row_revs(rows).await;
self.filter_controller.filter_row_revs(rows).await;
}
pub async fn duplicate_view_data(&self) -> FlowyResult<String> {
@ -286,7 +286,7 @@ impl DatabaseViewRevisionEditor {
let sort_controller = self.sort_controller.clone();
let row_id = row_rev.id.clone();
tokio::spawn(async move {
filter_controller.read().await.did_receive_row_changed(&row_id).await;
filter_controller.did_receive_row_changed(&row_id).await;
sort_controller.read().await.did_receive_row_changed(&row_id).await;
});
}
@ -514,7 +514,7 @@ impl DatabaseViewRevisionEditor {
condition: params.condition,
content: params.content,
};
let mut filter_controller = self.filter_controller.write().await;
let filter_controller = self.filter_controller.clone();
let changeset = if is_exist {
let old_filter_type = self
.delegate
@ -555,8 +555,6 @@ impl DatabaseViewRevisionEditor {
let filter_type = params.filter_type;
let changeset = self
.filter_controller
.write()
.await
.did_receive_changes(FilterChangeset::from_delete(filter_type.clone()))
.await;
@ -590,15 +588,14 @@ impl DatabaseViewRevisionEditor {
.did_update_view_field_type_option(&field_rev)
.await;
if let Some(changeset) = self
.filter_controller
.write()
.await
.did_receive_changes(filter_changeset)
.await
{
self.notify_did_update_filter(changeset).await;
}
let filter_controller = self.filter_controller.clone();
let _ = tokio::spawn(async move {
if let Some(notification) = filter_controller.did_receive_changes(filter_changeset).await {
send_notification(&notification.view_id, DatabaseNotification::DidUpdateFilter)
.payload(notification)
.send();
}
});
}
Ok(())
}
@ -830,7 +827,7 @@ async fn make_filter_controller(
notifier: GridViewChangedNotifier,
cell_data_cache: AtomicCellDataCache,
pad: Arc<RwLock<GridViewRevisionPad>>,
) -> Arc<RwLock<FilterController>> {
) -> Arc<FilterController> {
let field_revs = delegate.get_field_revs(None).await;
let filter_revs = pad.read().await.get_all_filters(&field_revs);
let task_scheduler = delegate.get_task_scheduler();
@ -849,7 +846,7 @@ async fn make_filter_controller(
notifier,
)
.await;
let filter_controller = Arc::new(RwLock::new(filter_controller));
let filter_controller = Arc::new(filter_controller);
task_scheduler
.write()
.await
@ -861,7 +858,7 @@ async fn make_sort_controller(
view_id: &str,
delegate: Arc<dyn DatabaseViewEditorDelegate>,
notifier: GridViewChangedNotifier,
filter_controller: Arc<RwLock<FilterController>>,
filter_controller: Arc<FilterController>,
pad: Arc<RwLock<GridViewRevisionPad>>,
cell_data_cache: AtomicCellDataCache,
) -> Arc<RwLock<SortController>> {

View File

@ -185,7 +185,7 @@ impl FilterDelegate for GridViewFilterDelegateImpl {
pub(crate) struct GridViewSortDelegateImpl {
pub(crate) editor_delegate: Arc<dyn DatabaseViewEditorDelegate>,
pub(crate) view_revision_pad: Arc<RwLock<GridViewRevisionPad>>,
pub(crate) filter_controller: Arc<RwLock<FilterController>>,
pub(crate) filter_controller: Arc<FilterController>,
}
impl SortDelegate for GridViewSortDelegateImpl {
@ -209,7 +209,7 @@ impl SortDelegate for GridViewSortDelegateImpl {
let editor_delegate = self.editor_delegate.clone();
to_fut(async move {
let mut row_revs = editor_delegate.get_row_revs(None).await;
filter_controller.write().await.filter_row_revs(&mut row_revs).await;
filter_controller.filter_row_revs(&mut row_revs).await;
row_revs
})
}

View File

@ -2,11 +2,9 @@ pub mod app;
mod parser;
pub mod trash;
pub mod view;
mod view_info;
pub mod workspace;
pub use app::*;
pub use trash::*;
pub use view::*;
pub use view_info::*;
pub use workspace::*;

View File

@ -50,9 +50,13 @@ impl std::convert::From<ViewRevision> for ViewPB {
#[derive(Eq, PartialEq, Hash, Debug, ProtoBuf_Enum, Clone)]
pub enum ViewDataFormatPB {
/// Indicate this view is using `Delta` for the persistence data format, it's deprecated.
DeltaFormat = 0,
/// Indicate this view is using `Database` for the persistence data format. It is used in AppFlowy database
/// views including Grid,Board, and Calendar.
DatabaseFormat = 1,
TreeFormat = 2,
/// Indicate this view is using `Node` for the persistence data format. It is used in AppFlowy document
NodeFormat = 2,
}
impl std::default::Default for ViewDataFormatPB {
@ -66,7 +70,7 @@ impl std::convert::From<ViewDataFormatRevision> for ViewDataFormatPB {
match rev {
ViewDataFormatRevision::DeltaFormat => ViewDataFormatPB::DeltaFormat,
ViewDataFormatRevision::DatabaseFormat => ViewDataFormatPB::DatabaseFormat,
ViewDataFormatRevision::TreeFormat => ViewDataFormatPB::TreeFormat,
ViewDataFormatRevision::NodeFormat => ViewDataFormatPB::NodeFormat,
}
}
}
@ -76,7 +80,7 @@ impl std::convert::From<ViewDataFormatPB> for ViewDataFormatRevision {
match ty {
ViewDataFormatPB::DeltaFormat => ViewDataFormatRevision::DeltaFormat,
ViewDataFormatPB::DatabaseFormat => ViewDataFormatRevision::DatabaseFormat,
ViewDataFormatPB::TreeFormat => ViewDataFormatRevision::TreeFormat,
ViewDataFormatPB::NodeFormat => ViewDataFormatRevision::NodeFormat,
}
}
}

View File

@ -1,26 +0,0 @@
use crate::entities::{RepeatedViewPB, ViewDataFormatPB};
use flowy_derive::ProtoBuf;
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct ViewInfoPB {
#[pb(index = 1)]
pub id: String,
#[pb(index = 2)]
pub belong_to_id: String,
#[pb(index = 3)]
pub name: String,
#[pb(index = 4)]
pub desc: String,
#[pb(index = 5)]
pub data_type: ViewDataFormatPB,
#[pb(index = 6)]
pub belongings: RepeatedViewPB,
#[pb(index = 7)]
pub ext_data: String,
}

View File

@ -63,12 +63,11 @@ pub fn init(folder: Arc<FolderManager>) -> AFPlugin {
.event(FolderEvent::CreateView, create_view_handler)
.event(FolderEvent::ReadView, read_view_handler)
.event(FolderEvent::UpdateView, update_view_handler)
.event(FolderEvent::ReadViewInfo, read_view_info_handler)
.event(FolderEvent::DeleteView, delete_view_handler)
.event(FolderEvent::DuplicateView, duplicate_view_handler)
.event(FolderEvent::SetLatestView, set_latest_view_handler)
.event(FolderEvent::CloseView, close_view_handler)
.event(FolderEvent::MoveFolderItem, move_item_handler);
.event(FolderEvent::MoveItem, move_item_handler);
// Trash
plugin = plugin
@ -84,78 +83,99 @@ pub fn init(folder: Arc<FolderManager>) -> AFPlugin {
#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
#[event_err = "FlowyError"]
pub enum FolderEvent {
/// Create a new workspace
#[event(input = "CreateWorkspacePayloadPB", output = "WorkspacePB")]
CreateWorkspace = 0,
/// Read the current opening workspace
#[event(output = "WorkspaceSettingPB")]
ReadCurrentWorkspace = 1,
/// Open the workspace and mark it as the current workspace
#[event(input = "WorkspaceIdPB", output = "RepeatedWorkspacePB")]
ReadWorkspaces = 2,
/// Delete the workspace
#[event(input = "WorkspaceIdPB")]
DeleteWorkspace = 3,
/// Open the workspace and mark it as the current workspace
#[event(input = "WorkspaceIdPB", output = "WorkspacePB")]
OpenWorkspace = 4,
/// Return a list of apps that belong to this workspace
#[event(input = "WorkspaceIdPB", output = "RepeatedAppPB")]
ReadWorkspaceApps = 5,
/// Create a new app
#[event(input = "CreateAppPayloadPB", output = "AppPB")]
CreateApp = 101,
/// Delete the app
#[event(input = "AppIdPB")]
DeleteApp = 102,
/// Read the app
#[event(input = "AppIdPB", output = "AppPB")]
ReadApp = 103,
/// Update the app's properties including the name,description, etc.
#[event(input = "UpdateAppPayloadPB")]
UpdateApp = 104,
/// Create a new view in the corresponding app
#[event(input = "CreateViewPayloadPB", output = "ViewPB")]
CreateView = 201,
/// Return the view info
#[event(input = "ViewIdPB", output = "ViewPB")]
ReadView = 202,
/// Update the view's properties including the name,description, etc.
#[event(input = "UpdateViewPayloadPB", output = "ViewPB")]
UpdateView = 203,
/// Move the view to the trash folder
#[event(input = "RepeatedViewIdPB")]
DeleteView = 204,
/// Duplicate the view
#[event(input = "ViewPB")]
DuplicateView = 205,
/// Close and release the resources that are used by this view.
/// It should get called when the 'View' page get destroy
#[event(input = "ViewIdPB")]
CloseView = 206,
#[event(input = "ViewIdPB", output = "ViewInfoPB")]
ReadViewInfo = 207,
#[event()]
CopyLink = 220,
/// Set the current visiting view
#[event(input = "ViewIdPB")]
SetLatestView = 221,
/// Move the view or app to another place
#[event(input = "MoveFolderItemPayloadPB")]
MoveFolderItem = 230,
MoveItem = 230,
/// Read the trash that was deleted by the user
#[event(output = "RepeatedTrashPB")]
ReadTrash = 300,
/// Put back the trash to the origin folder
#[event(input = "TrashIdPB")]
PutbackTrash = 301,
/// Delete the trash from the disk
#[event(input = "RepeatedTrashIdPB")]
DeleteTrash = 302,
/// Put back all the trash to its original folder
#[event()]
RestoreAllTrash = 303,
/// Delete all the trash from the disk
#[event()]
DeleteAllTrash = 304,
}

View File

@ -89,7 +89,7 @@ impl ViewTable {
let data_type = match view_rev.data_format {
ViewDataFormatRevision::DeltaFormat => SqlViewDataFormat::Delta,
ViewDataFormatRevision::DatabaseFormat => SqlViewDataFormat::Database,
ViewDataFormatRevision::TreeFormat => SqlViewDataFormat::Tree,
ViewDataFormatRevision::NodeFormat => SqlViewDataFormat::Tree,
};
ViewTable {
@ -113,7 +113,7 @@ impl std::convert::From<ViewTable> for ViewRevision {
let data_type = match table.view_type {
SqlViewDataFormat::Delta => ViewDataFormatRevision::DeltaFormat,
SqlViewDataFormat::Database => ViewDataFormatRevision::DatabaseFormat,
SqlViewDataFormat::Tree => ViewDataFormatRevision::TreeFormat,
SqlViewDataFormat::Tree => ViewDataFormatRevision::NodeFormat,
};
ViewRevision {

View File

@ -1,10 +1,10 @@
pub use crate::entities::view::ViewDataFormatPB;
use crate::entities::{AppPB, DeletedViewPB, ViewInfoPB, ViewLayoutTypePB};
use crate::entities::{AppPB, DeletedViewPB, ViewLayoutTypePB};
use crate::manager::{ViewDataProcessor, ViewDataProcessorMap};
use crate::{
entities::{
trash::{RepeatedTrashIdPB, TrashType},
view::{CreateViewParams, RepeatedViewPB, UpdateViewParams, ViewIdPB, ViewPB},
view::{CreateViewParams, UpdateViewParams, ViewIdPB, ViewPB},
},
errors::{FlowyError, FlowyResult},
event_map::{FolderCouldServiceV1, WorkspaceUser},
@ -139,35 +139,6 @@ impl ViewController {
Ok(view_rev)
}
#[tracing::instrument(level = "debug", skip(self, view_id), fields(view_id = %view_id.value), err)]
pub(crate) async fn read_view_pb(&self, view_id: ViewIdPB) -> Result<ViewInfoPB, FlowyError> {
let view_info = self
.persistence
.begin_transaction(|transaction| {
let view_rev = transaction.read_view(&view_id.value)?;
let items: Vec<ViewPB> = view_rev
.belongings
.into_iter()
.map(|view_rev| view_rev.into())
.collect();
let view_info = ViewInfoPB {
id: view_rev.id,
belong_to_id: view_rev.app_id,
name: view_rev.name,
desc: view_rev.desc,
data_type: view_rev.data_format.into(),
belongings: RepeatedViewPB { items },
ext_data: view_rev.ext_data,
};
Ok(view_info)
})
.await?;
Ok(view_info)
}
pub(crate) async fn read_local_views(&self, ids: Vec<String>) -> Result<Vec<ViewRevision>, FlowyError> {
self.persistence
.begin_transaction(|transaction| {

View File

@ -1,5 +1,4 @@
use crate::entities::view::{MoveFolderItemParams, MoveFolderItemPayloadPB, MoveFolderItemType};
use crate::entities::ViewInfoPB;
use crate::manager::FolderManager;
use crate::services::{notify_workspace_setting_did_change, AppController};
use crate::{
@ -35,15 +34,6 @@ pub(crate) async fn read_view_handler(
data_result(view_rev.into())
}
pub(crate) async fn read_view_info_handler(
data: AFPluginData<ViewIdPB>,
controller: AFPluginState<Arc<ViewController>>,
) -> DataResult<ViewInfoPB, FlowyError> {
let view_id: ViewIdPB = data.into_inner();
let view_info = controller.read_view_pb(view_id.clone()).await?;
data_result(view_info)
}
#[tracing::instrument(level = "debug", skip(data, controller), err)]
pub(crate) async fn update_view_handler(
data: AFPluginData<UpdateViewPayloadPB>,

View File

@ -182,7 +182,7 @@ impl FolderTest {
FolderScript::CreateView { name, desc, data_type } => {
let layout = match data_type {
ViewDataFormatPB::DeltaFormat => ViewLayoutTypePB::Document,
ViewDataFormatPB::TreeFormat => ViewLayoutTypePB::Document,
ViewDataFormatPB::NodeFormat => ViewLayoutTypePB::Document,
ViewDataFormatPB::DatabaseFormat => ViewLayoutTypePB::Grid,
};
let view = create_view(sdk, &self.app.id, &name, &desc, data_type, layout).await;

View File

@ -58,7 +58,7 @@ impl ViewTest {
pub async fn new_document_view(sdk: &FlowySDKTest) -> Self {
let view_data_format = match sdk.document_version() {
DocumentVersionPB::V0 => ViewDataFormatPB::DeltaFormat,
DocumentVersionPB::V1 => ViewDataFormatPB::TreeFormat,
DocumentVersionPB::V1 => ViewDataFormatPB::NodeFormat,
};
Self::new(sdk, view_data_format, ViewLayoutTypePB::Document, vec![]).await
}

View File

@ -59,7 +59,7 @@ impl std::convert::From<ViewRevision> for TrashRevision {
pub enum ViewDataFormatRevision {
DeltaFormat = 0,
DatabaseFormat = 1,
TreeFormat = 2,
NodeFormat = 2,
}
impl std::default::Default for ViewDataFormatRevision {