refactor: group event (#2640)

* refactor: group event

* fix: tauri build
This commit is contained in:
Nathan.fooo 2023-05-28 22:54:03 +08:00 committed by GitHub
parent 75d40b79d0
commit 6bbdc7ceff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 602 additions and 504 deletions

View File

@ -178,7 +178,7 @@ class FilterBackendService {
required FieldType fieldType, required FieldType fieldType,
required List<int> data, required List<int> data,
}) { }) {
var insertFilterPayload = AlterFilterPayloadPB.create() var insertFilterPayload = UpdateFilterPayloadPB.create()
..fieldId = fieldId ..fieldId = fieldId
..fieldType = fieldType ..fieldType = fieldType
..viewId = viewId ..viewId = viewId
@ -190,7 +190,7 @@ class FilterBackendService {
final payload = DatabaseSettingChangesetPB.create() final payload = DatabaseSettingChangesetPB.create()
..viewId = viewId ..viewId = viewId
..alterFilter = insertFilterPayload; ..updateFilter = insertFilterPayload;
return DatabaseEventUpdateDatabaseSetting(payload).send().then((result) { return DatabaseEventUpdateDatabaseSetting(payload).send().then((result) {
return result.fold( return result.fold(
(l) => left(l), (l) => left(l),

View File

@ -8,7 +8,7 @@ import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/group_changeset.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/group_changeset.pb.dart';
typedef GroupUpdateValue = Either<GroupChangesetPB, FlowyError>; typedef GroupUpdateValue = Either<GroupChangesPB, FlowyError>;
typedef GroupByNewFieldValue = Either<List<GroupPB>, FlowyError>; typedef GroupByNewFieldValue = Either<List<GroupPB>, FlowyError>;
class DatabaseGroupListener { class DatabaseGroupListener {
@ -36,17 +36,17 @@ class DatabaseGroupListener {
Either<Uint8List, FlowyError> result, Either<Uint8List, FlowyError> result,
) { ) {
switch (ty) { switch (ty) {
case DatabaseNotification.DidUpdateGroups: case DatabaseNotification.DidUpdateNumOfGroups:
result.fold( result.fold(
(payload) => _numOfGroupsNotifier?.value = (payload) => _numOfGroupsNotifier?.value =
left(GroupChangesetPB.fromBuffer(payload)), left(GroupChangesPB.fromBuffer(payload)),
(error) => _numOfGroupsNotifier?.value = right(error), (error) => _numOfGroupsNotifier?.value = right(error),
); );
break; break;
case DatabaseNotification.DidGroupByField: case DatabaseNotification.DidGroupByField:
result.fold( result.fold(
(payload) => _groupByFieldNotifier?.value = (payload) => _groupByFieldNotifier?.value =
left(GroupChangesetPB.fromBuffer(payload).initialGroups), left(GroupChangesPB.fromBuffer(payload).initialGroups),
(error) => _groupByFieldNotifier?.value = right(error), (error) => _groupByFieldNotifier?.value = right(error),
); );
break; break;

View File

@ -0,0 +1,37 @@
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:dartz/dartz.dart';
class GroupBackendService {
final String viewId;
GroupBackendService(this.viewId);
Future<Either<Unit, FlowyError>> groupByField({
required String fieldId,
required FieldType fieldType,
}) {
final payload = GroupByFieldPayloadPB.create()
..viewId = viewId
..fieldId = fieldId
..fieldType = fieldType;
return DatabaseEventSetGroupByField(payload).send();
}
Future<Either<Unit, FlowyError>> updateGroup({
required String groupId,
String? name,
bool? visible,
}) {
final payload = UpdateGroupPB.create()..groupId = groupId;
if (name != null) {
payload.name = name;
}
if (visible != null) {
payload.visible = visible;
}
return DatabaseEventUpdateGroup(payload).send();
}
}

View File

@ -1,23 +1,24 @@
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart'; import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/application/setting/setting_service.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async'; import 'dart:async';
import '../group/group_service.dart';
part 'group_bloc.freezed.dart'; part 'group_bloc.freezed.dart';
class DatabaseGroupBloc extends Bloc<DatabaseGroupEvent, DatabaseGroupState> { class DatabaseGroupBloc extends Bloc<DatabaseGroupEvent, DatabaseGroupState> {
final FieldController _fieldController; final FieldController _fieldController;
final SettingBackendService _settingBackendSvc; final GroupBackendService _groupBackendSvc;
Function(List<FieldInfo>)? _onFieldsFn; Function(List<FieldInfo>)? _onFieldsFn;
DatabaseGroupBloc({ DatabaseGroupBloc({
required String viewId, required String viewId,
required FieldController fieldController, required FieldController fieldController,
}) : _fieldController = fieldController, }) : _fieldController = fieldController,
_settingBackendSvc = SettingBackendService(viewId: viewId), _groupBackendSvc = GroupBackendService(viewId),
super(DatabaseGroupState.initial(viewId, fieldController.fieldInfos)) { super(DatabaseGroupState.initial(viewId, fieldController.fieldInfos)) {
on<DatabaseGroupEvent>( on<DatabaseGroupEvent>(
(event, emit) async { (event, emit) async {
@ -29,7 +30,7 @@ class DatabaseGroupBloc extends Bloc<DatabaseGroupEvent, DatabaseGroupState> {
emit(state.copyWith(fieldContexts: fieldContexts)); emit(state.copyWith(fieldContexts: fieldContexts));
}, },
setGroupByField: (String fieldId, FieldType fieldType) async { setGroupByField: (String fieldId, FieldType fieldType) async {
final result = await _settingBackendSvc.groupByField( final result = await _groupBackendSvc.groupByField(
fieldId: fieldId, fieldId: fieldId,
fieldType: fieldType, fieldType: fieldType,
); );

View File

@ -2,8 +2,6 @@ import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.d
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart'; import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/group.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart';
class SettingBackendService { class SettingBackendService {
@ -15,19 +13,4 @@ class SettingBackendService {
final payload = DatabaseViewIdPB.create()..value = viewId; final payload = DatabaseViewIdPB.create()..value = viewId;
return DatabaseEventGetDatabaseSetting(payload).send(); return DatabaseEventGetDatabaseSetting(payload).send();
} }
Future<Either<Unit, FlowyError>> groupByField({
required String fieldId,
required FieldType fieldType,
}) {
final insertGroupPayload = InsertGroupPayloadPB.create()
..viewId = viewId
..fieldId = fieldId
..fieldType = fieldType;
final payload = DatabaseSettingChangesetPB.create()
..viewId = viewId
..insertGroup = insertGroupPayload;
return DatabaseEventUpdateDatabaseSetting(payload).send();
}
} }

View File

@ -29,7 +29,7 @@ class SortBackendService {
required FieldType fieldType, required FieldType fieldType,
required SortConditionPB condition, required SortConditionPB condition,
}) { }) {
var insertSortPayload = AlterSortPayloadPB.create() var insertSortPayload = UpdateSortPayloadPB.create()
..fieldId = fieldId ..fieldId = fieldId
..fieldType = fieldType ..fieldType = fieldType
..viewId = viewId ..viewId = viewId
@ -38,7 +38,7 @@ class SortBackendService {
final payload = DatabaseSettingChangesetPB.create() final payload = DatabaseSettingChangesetPB.create()
..viewId = viewId ..viewId = viewId
..alterSort = insertSortPayload; ..updateSort = insertSortPayload;
return DatabaseEventUpdateDatabaseSetting(payload).send().then((result) { return DatabaseEventUpdateDatabaseSetting(payload).send().then((result) {
return result.fold( return result.fold(
(l) => left(l), (l) => left(l),
@ -55,7 +55,7 @@ class SortBackendService {
required FieldType fieldType, required FieldType fieldType,
required SortConditionPB condition, required SortConditionPB condition,
}) { }) {
var insertSortPayload = AlterSortPayloadPB.create() var insertSortPayload = UpdateSortPayloadPB.create()
..fieldId = fieldId ..fieldId = fieldId
..fieldType = fieldType ..fieldType = fieldType
..viewId = viewId ..viewId = viewId
@ -63,7 +63,7 @@ class SortBackendService {
final payload = DatabaseSettingChangesetPB.create() final payload = DatabaseSettingChangesetPB.create()
..viewId = viewId ..viewId = viewId
..alterSort = insertSortPayload; ..updateSort = insertSortPayload;
return DatabaseEventUpdateDatabaseSetting(payload).send().then((result) { return DatabaseEventUpdateDatabaseSetting(payload).send().then((result) {
return result.fold( return result.fold(
(l) => left(l), (l) => left(l),

View File

@ -1,18 +1,17 @@
import { ChangeNotifier } from "$app/utils/change_notifier"; import { ChangeNotifier } from '$app/utils/change_notifier';
import { Ok, Result } from "ts-results"; import { Ok, Result } from 'ts-results';
import { DatabaseNotification, FlowyError, GroupChangesetPB, GroupPB } from "@/services/backend"; import { DatabaseNotification, FlowyError, GroupChangesPB, GroupPB } from '@/services/backend';
import { DatabaseNotificationObserver } from "../notifications/observer"; import { DatabaseNotificationObserver } from '../notifications/observer';
export type GroupByFieldCallback = (value: Result<GroupPB[], FlowyError>) => void; export type GroupByFieldCallback = (value: Result<GroupPB[], FlowyError>) => void;
export type GroupChangesetSubscribeCallback = (value: Result<GroupChangesetPB, FlowyError>) => void; export type GroupChangesetSubscribeCallback = (value: Result<GroupChangesPB, FlowyError>) => void;
export class DatabaseGroupObserver { export class DatabaseGroupObserver {
private groupByNotifier?: ChangeNotifier<Result<GroupPB[], FlowyError>>; private groupByNotifier?: ChangeNotifier<Result<GroupPB[], FlowyError>>;
private groupChangesetNotifier?: ChangeNotifier<Result<GroupChangesetPB, FlowyError>>; private groupChangesetNotifier?: ChangeNotifier<Result<GroupChangesPB, FlowyError>>;
private listener?: DatabaseNotificationObserver; private listener?: DatabaseNotificationObserver;
constructor(public readonly viewId: string) { constructor(public readonly viewId: string) {}
}
subscribe = async (callbacks: { subscribe = async (callbacks: {
onGroupBy: GroupByFieldCallback; onGroupBy: GroupByFieldCallback;
@ -30,14 +29,14 @@ export class DatabaseGroupObserver {
switch (notification) { switch (notification) {
case DatabaseNotification.DidGroupByField: case DatabaseNotification.DidGroupByField:
if (result.ok) { if (result.ok) {
this.groupByNotifier?.notify(Ok(GroupChangesetPB.deserializeBinary(result.val).initial_groups)); this.groupByNotifier?.notify(Ok(GroupChangesPB.deserializeBinary(result.val).initial_groups));
} else { } else {
this.groupByNotifier?.notify(result); this.groupByNotifier?.notify(result);
} }
break; break;
case DatabaseNotification.DidUpdateGroups: case DatabaseNotification.DidUpdateNumOfGroups:
if (result.ok) { if (result.ok) {
this.groupChangesetNotifier?.notify(Ok(GroupChangesetPB.deserializeBinary(result.val))); this.groupChangesetNotifier?.notify(Ok(GroupChangesPB.deserializeBinary(result.val)));
} else { } else {
this.groupChangesetNotifier?.notify(result); this.groupChangesetNotifier?.notify(result);
} }
@ -45,7 +44,7 @@ export class DatabaseGroupObserver {
default: default:
break; break;
} }
} },
}); });
await this.listener.start(); await this.listener.start();

View File

@ -125,7 +125,7 @@ pub struct DeleteFilterParams {
} }
#[derive(ProtoBuf, Debug, Default, Clone)] #[derive(ProtoBuf, Debug, Default, Clone)]
pub struct AlterFilterPayloadPB { pub struct UpdateFilterPayloadPB {
#[pb(index = 1)] #[pb(index = 1)]
pub field_id: String, pub field_id: String,
@ -143,7 +143,7 @@ pub struct AlterFilterPayloadPB {
pub view_id: String, pub view_id: String,
} }
impl AlterFilterPayloadPB { impl UpdateFilterPayloadPB {
#[allow(dead_code)] #[allow(dead_code)]
pub fn new<T: TryInto<Bytes, Error = ::protobuf::ProtobufError>>( pub fn new<T: TryInto<Bytes, Error = ::protobuf::ProtobufError>>(
view_id: &str, view_id: &str,
@ -162,10 +162,10 @@ impl AlterFilterPayloadPB {
} }
} }
impl TryInto<AlterFilterParams> for AlterFilterPayloadPB { impl TryInto<UpdateFilterParams> for UpdateFilterPayloadPB {
type Error = ErrorCode; type Error = ErrorCode;
fn try_into(self) -> Result<AlterFilterParams, Self::Error> { fn try_into(self) -> Result<UpdateFilterParams, Self::Error> {
let view_id = NotEmptyStr::parse(self.view_id) let view_id = NotEmptyStr::parse(self.view_id)
.map_err(|_| ErrorCode::DatabaseViewIdIsEmpty)? .map_err(|_| ErrorCode::DatabaseViewIdIsEmpty)?
.0; .0;
@ -217,7 +217,7 @@ impl TryInto<AlterFilterParams> for AlterFilterPayloadPB {
}, },
} }
Ok(AlterFilterParams { Ok(UpdateFilterParams {
view_id, view_id,
field_id, field_id,
filter_id, filter_id,
@ -229,7 +229,7 @@ impl TryInto<AlterFilterParams> for AlterFilterPayloadPB {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct AlterFilterParams { pub struct UpdateFilterParams {
pub view_id: String, pub view_id: String,
pub field_id: String, pub field_id: String,
/// Create a new filter if the filter_id is None /// Create a new filter if the filter_id is None

View File

@ -5,7 +5,7 @@ use flowy_error::ErrorCode;
use crate::entities::parser::NotEmptyStr; use crate::entities::parser::NotEmptyStr;
use crate::entities::{FieldType, RowPB}; use crate::entities::{FieldType, RowPB};
use crate::services::group::{GroupData, GroupSetting}; use crate::services::group::{GroupChangeset, GroupData, GroupSetting};
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct GroupSettingPB { pub struct GroupSettingPB {
@ -25,6 +25,29 @@ impl std::convert::From<&GroupSetting> for GroupSettingPB {
} }
} }
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedGroupSettingPB {
#[pb(index = 1)]
pub items: Vec<GroupSettingPB>,
}
impl std::convert::From<Vec<GroupSettingPB>> for RepeatedGroupSettingPB {
fn from(items: Vec<GroupSettingPB>) -> Self {
Self { items }
}
}
impl std::convert::From<Vec<GroupSetting>> for RepeatedGroupSettingPB {
fn from(group_settings: Vec<GroupSetting>) -> Self {
RepeatedGroupSettingPB {
items: group_settings
.iter()
.map(|setting| setting.into())
.collect(),
}
}
}
#[derive(ProtoBuf, Debug, Default, Clone)] #[derive(ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedGroupPB { pub struct RepeatedGroupPB {
#[pb(index = 1)] #[pb(index = 1)]
@ -79,107 +102,97 @@ impl std::convert::From<GroupData> for GroupPB {
} }
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct RepeatedGroupSettingPB { pub struct GroupByFieldPayloadPB {
#[pb(index = 1)]
pub items: Vec<GroupSettingPB>,
}
impl std::convert::From<Vec<GroupSettingPB>> for RepeatedGroupSettingPB {
fn from(items: Vec<GroupSettingPB>) -> Self {
Self { items }
}
}
impl std::convert::From<Vec<GroupSetting>> for RepeatedGroupSettingPB {
fn from(group_settings: Vec<GroupSetting>) -> Self {
RepeatedGroupSettingPB {
items: group_settings
.iter()
.map(|setting| setting.into())
.collect(),
}
}
}
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct InsertGroupPayloadPB {
#[pb(index = 1)] #[pb(index = 1)]
pub field_id: String, pub field_id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub field_type: FieldType,
#[pb(index = 3)]
pub view_id: String, pub view_id: String,
}
impl TryInto<InsertGroupParams> for InsertGroupPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<InsertGroupParams, Self::Error> {
let field_id = NotEmptyStr::parse(self.field_id)
.map_err(|_| ErrorCode::FieldIdIsEmpty)?
.0;
let view_id = NotEmptyStr::parse(self.view_id)
.map_err(|_| ErrorCode::ViewIdIsInvalid)?
.0;
Ok(InsertGroupParams {
field_id,
field_type: self.field_type,
view_id,
})
}
}
pub struct InsertGroupParams {
pub view_id: String,
pub field_id: String,
pub field_type: FieldType,
}
#[derive(ProtoBuf, Debug, Default, Clone)]
pub struct DeleteGroupPayloadPB {
#[pb(index = 1)]
pub field_id: String,
#[pb(index = 2)]
pub group_id: String,
#[pb(index = 3)] #[pb(index = 3)]
pub field_type: FieldType, pub field_type: FieldType,
#[pb(index = 4)]
pub view_id: String,
} }
impl TryInto<DeleteGroupParams> for DeleteGroupPayloadPB { impl TryInto<GroupByFieldParams> for GroupByFieldPayloadPB {
type Error = ErrorCode; type Error = ErrorCode;
fn try_into(self) -> Result<DeleteGroupParams, Self::Error> { fn try_into(self) -> Result<GroupByFieldParams, Self::Error> {
let field_id = NotEmptyStr::parse(self.field_id) let field_id = NotEmptyStr::parse(self.field_id)
.map_err(|_| ErrorCode::FieldIdIsEmpty)? .map_err(|_| ErrorCode::FieldIdIsEmpty)?
.0; .0;
let group_id = NotEmptyStr::parse(self.group_id)
.map_err(|_| ErrorCode::FieldIdIsEmpty)?
.0;
let view_id = NotEmptyStr::parse(self.view_id) let view_id = NotEmptyStr::parse(self.view_id)
.map_err(|_| ErrorCode::ViewIdIsInvalid)? .map_err(|_| ErrorCode::ViewIdIsInvalid)?
.0; .0;
Ok(DeleteGroupParams { Ok(GroupByFieldParams {
field_id, field_id,
field_type: self.field_type,
group_id,
view_id, view_id,
field_type: self.field_type,
}) })
} }
} }
pub struct GroupByFieldParams {
pub field_id: String,
pub view_id: String,
pub field_type: FieldType,
}
pub struct DeleteGroupParams { pub struct DeleteGroupParams {
pub view_id: String, pub view_id: String,
pub field_id: String, pub field_id: String,
pub group_id: String, pub group_id: String,
pub field_type: FieldType, pub field_type: FieldType,
} }
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct UpdateGroupPB {
#[pb(index = 1)]
pub view_id: String,
#[pb(index = 2)]
pub group_id: String,
#[pb(index = 3, one_of)]
pub name: Option<String>,
#[pb(index = 4, one_of)]
pub visible: Option<bool>,
}
impl TryInto<UpdateGroupParams> for UpdateGroupPB {
type Error = ErrorCode;
fn try_into(self) -> Result<UpdateGroupParams, Self::Error> {
let view_id = NotEmptyStr::parse(self.view_id)
.map_err(|_| ErrorCode::ViewIdIsInvalid)?
.0;
let group_id = NotEmptyStr::parse(self.group_id)
.map_err(|_| ErrorCode::GroupIdIsEmpty)?
.0;
Ok(UpdateGroupParams {
view_id,
group_id,
name: self.name,
visible: self.visible,
})
}
}
pub struct UpdateGroupParams {
pub view_id: String,
pub group_id: String,
pub name: Option<String>,
pub visible: Option<bool>,
}
impl From<UpdateGroupParams> for GroupChangeset {
fn from(params: UpdateGroupParams) -> Self {
Self {
group_id: params.group_id,
name: params.name,
visible: params.visible,
}
}
}

View File

@ -129,7 +129,7 @@ impl TryInto<MoveGroupParams> for MoveGroupPayloadPB {
} }
#[derive(Debug, Default, ProtoBuf)] #[derive(Debug, Default, ProtoBuf)]
pub struct GroupChangesetPB { pub struct GroupChangesPB {
#[pb(index = 1)] #[pb(index = 1)]
pub view_id: String, pub view_id: String,
@ -146,7 +146,7 @@ pub struct GroupChangesetPB {
pub update_groups: Vec<GroupPB>, pub update_groups: Vec<GroupPB>,
} }
impl GroupChangesetPB { impl GroupChangesPB {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.initial_groups.is_empty() self.initial_groups.is_empty()
&& self.inserted_groups.is_empty() && self.inserted_groups.is_empty()

View File

@ -8,10 +8,9 @@ use flowy_error::ErrorCode;
use crate::entities::parser::NotEmptyStr; use crate::entities::parser::NotEmptyStr;
use crate::entities::{ use crate::entities::{
AlterFilterParams, AlterFilterPayloadPB, AlterSortParams, AlterSortPayloadPB, CalendarLayoutSettingPB, DeleteFilterParams, DeleteFilterPayloadPB, DeleteSortParams,
CalendarLayoutSettingPB, DeleteFilterParams, DeleteFilterPayloadPB, DeleteGroupParams, DeleteSortPayloadPB, RepeatedFilterPB, RepeatedGroupSettingPB, RepeatedSortPB,
DeleteGroupPayloadPB, DeleteSortParams, DeleteSortPayloadPB, InsertGroupParams, UpdateFilterParams, UpdateFilterPayloadPB, UpdateGroupPB, UpdateSortParams, UpdateSortPayloadPB,
InsertGroupPayloadPB, RepeatedFilterPB, RepeatedGroupSettingPB, RepeatedSortPB,
}; };
use crate::services::setting::CalendarLayoutSetting; use crate::services::setting::CalendarLayoutSetting;
@ -77,21 +76,18 @@ pub struct DatabaseSettingChangesetPB {
pub layout_type: DatabaseLayoutPB, pub layout_type: DatabaseLayoutPB,
#[pb(index = 3, one_of)] #[pb(index = 3, one_of)]
pub alter_filter: Option<AlterFilterPayloadPB>, pub update_filter: Option<UpdateFilterPayloadPB>,
#[pb(index = 4, one_of)] #[pb(index = 4, one_of)]
pub delete_filter: Option<DeleteFilterPayloadPB>, pub delete_filter: Option<DeleteFilterPayloadPB>,
#[pb(index = 5, one_of)] #[pb(index = 5, one_of)]
pub insert_group: Option<InsertGroupPayloadPB>, pub update_group: Option<UpdateGroupPB>,
#[pb(index = 6, one_of)] #[pb(index = 6, one_of)]
pub delete_group: Option<DeleteGroupPayloadPB>, pub update_sort: Option<UpdateSortPayloadPB>,
#[pb(index = 7, one_of)] #[pb(index = 7, one_of)]
pub alter_sort: Option<AlterSortPayloadPB>,
#[pb(index = 8, one_of)]
pub delete_sort: Option<DeleteSortPayloadPB>, pub delete_sort: Option<DeleteSortPayloadPB>,
} }
@ -103,7 +99,7 @@ impl TryInto<DatabaseSettingChangesetParams> for DatabaseSettingChangesetPB {
.map_err(|_| ErrorCode::ViewIdIsInvalid)? .map_err(|_| ErrorCode::ViewIdIsInvalid)?
.0; .0;
let insert_filter = match self.alter_filter { let insert_filter = match self.update_filter {
None => None, None => None,
Some(payload) => Some(payload.try_into()?), Some(payload) => Some(payload.try_into()?),
}; };
@ -113,17 +109,7 @@ impl TryInto<DatabaseSettingChangesetParams> for DatabaseSettingChangesetPB {
Some(payload) => Some(payload.try_into()?), Some(payload) => Some(payload.try_into()?),
}; };
let insert_group = match self.insert_group { let alert_sort = match self.update_sort {
Some(payload) => Some(payload.try_into()?),
None => None,
};
let delete_group = match self.delete_group {
Some(payload) => Some(payload.try_into()?),
None => None,
};
let alert_sort = match self.alter_sort {
None => None, None => None,
Some(payload) => Some(payload.try_into()?), Some(payload) => Some(payload.try_into()?),
}; };
@ -138,8 +124,6 @@ impl TryInto<DatabaseSettingChangesetParams> for DatabaseSettingChangesetPB {
layout_type: self.layout_type.into(), layout_type: self.layout_type.into(),
insert_filter, insert_filter,
delete_filter, delete_filter,
insert_group,
delete_group,
alert_sort, alert_sort,
delete_sort, delete_sort,
}) })
@ -149,11 +133,9 @@ impl TryInto<DatabaseSettingChangesetParams> for DatabaseSettingChangesetPB {
pub struct DatabaseSettingChangesetParams { pub struct DatabaseSettingChangesetParams {
pub view_id: String, pub view_id: String,
pub layout_type: DatabaseLayout, pub layout_type: DatabaseLayout,
pub insert_filter: Option<AlterFilterParams>, pub insert_filter: Option<UpdateFilterParams>,
pub delete_filter: Option<DeleteFilterParams>, pub delete_filter: Option<DeleteFilterParams>,
pub insert_group: Option<InsertGroupParams>, pub alert_sort: Option<UpdateSortParams>,
pub delete_group: Option<DeleteGroupParams>,
pub alert_sort: Option<AlterSortParams>,
pub delete_sort: Option<DeleteSortParams>, pub delete_sort: Option<DeleteSortParams>,
} }

View File

@ -92,7 +92,7 @@ impl std::convert::From<SortConditionPB> for SortCondition {
} }
#[derive(ProtoBuf, Debug, Default, Clone)] #[derive(ProtoBuf, Debug, Default, Clone)]
pub struct AlterSortPayloadPB { pub struct UpdateSortPayloadPB {
#[pb(index = 1)] #[pb(index = 1)]
pub view_id: String, pub view_id: String,
@ -110,10 +110,10 @@ pub struct AlterSortPayloadPB {
pub condition: SortConditionPB, pub condition: SortConditionPB,
} }
impl TryInto<AlterSortParams> for AlterSortPayloadPB { impl TryInto<UpdateSortParams> for UpdateSortPayloadPB {
type Error = ErrorCode; type Error = ErrorCode;
fn try_into(self) -> Result<AlterSortParams, Self::Error> { fn try_into(self) -> Result<UpdateSortParams, Self::Error> {
let view_id = NotEmptyStr::parse(self.view_id) let view_id = NotEmptyStr::parse(self.view_id)
.map_err(|_| ErrorCode::DatabaseViewIdIsEmpty)? .map_err(|_| ErrorCode::DatabaseViewIdIsEmpty)?
.0; .0;
@ -131,7 +131,7 @@ impl TryInto<AlterSortParams> for AlterSortPayloadPB {
), ),
}; };
Ok(AlterSortParams { Ok(UpdateSortParams {
view_id, view_id,
field_id, field_id,
sort_id, sort_id,
@ -142,7 +142,7 @@ impl TryInto<AlterSortParams> for AlterSortPayloadPB {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct AlterSortParams { pub struct UpdateSortParams {
pub view_id: String, pub view_id: String,
pub field_id: String, pub field_id: String,
/// Create a new sort if the sort is None /// Create a new sort if the sort is None

View File

@ -15,9 +15,10 @@ use crate::services::cell::CellBuilder;
use crate::services::field::{ use crate::services::field::{
type_option_data_from_pb_or_default, DateCellChangeset, SelectOptionCellChangeset, type_option_data_from_pb_or_default, DateCellChangeset, SelectOptionCellChangeset,
}; };
use crate::services::group::{GroupChangeset, GroupSettingChangeset};
use crate::services::share::csv::CSVFormat; use crate::services::share::csv::CSVFormat;
#[tracing::instrument(level = "trace", skip(data, manager), err)] #[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) async fn get_database_data_handler( pub(crate) async fn get_database_data_handler(
data: AFPluginData<DatabaseViewIdPB>, data: AFPluginData<DatabaseViewIdPB>,
manager: AFPluginState<Arc<DatabaseManager2>>, manager: AFPluginState<Arc<DatabaseManager2>>,
@ -49,24 +50,16 @@ pub(crate) async fn update_database_setting_handler(
let params: DatabaseSettingChangesetParams = data.into_inner().try_into()?; let params: DatabaseSettingChangesetParams = data.into_inner().try_into()?;
let editor = manager.get_database_with_view_id(&params.view_id).await?; let editor = manager.get_database_with_view_id(&params.view_id).await?;
if let Some(insert_params) = params.insert_group { if let Some(update_filter) = params.insert_filter {
editor.insert_group(insert_params).await?; editor.create_or_update_filter(update_filter).await?;
}
if let Some(delete_params) = params.delete_group {
editor.delete_group(delete_params).await?;
}
if let Some(alter_filter) = params.insert_filter {
editor.create_or_update_filter(alter_filter).await?;
} }
if let Some(delete_filter) = params.delete_filter { if let Some(delete_filter) = params.delete_filter {
editor.delete_filter(delete_filter).await?; editor.delete_filter(delete_filter).await?;
} }
if let Some(alter_sort) = params.alert_sort { if let Some(update_sort) = params.alert_sort {
let _ = editor.create_or_update_sort(alter_sort).await?; let _ = editor.create_or_update_sort(update_sort).await?;
} }
if let Some(delete_sort) = params.delete_sort { if let Some(delete_sort) = params.delete_sort {
editor.delete_sort(delete_sort).await?; editor.delete_sort(delete_sort).await?;
@ -525,6 +518,36 @@ pub(crate) async fn get_group_handler(
data_result_ok(group) data_result_ok(group)
} }
#[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) async fn set_group_by_field_handler(
data: AFPluginData<GroupByFieldPayloadPB>,
manager: AFPluginState<Arc<DatabaseManager2>>,
) -> FlowyResult<()> {
let params: GroupByFieldParams = data.into_inner().try_into()?;
let database_editor = manager.get_database_with_view_id(&params.view_id).await?;
database_editor
.set_group_by_field(&params.view_id, &params.field_id)
.await?;
Ok(())
}
#[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) async fn update_group_handler(
data: AFPluginData<UpdateGroupPB>,
manager: AFPluginState<Arc<DatabaseManager2>>,
) -> FlowyResult<()> {
let params: UpdateGroupParams = data.into_inner().try_into()?;
let view_id = params.view_id.clone();
let database_editor = manager.get_database_with_view_id(&view_id).await?;
let group_setting_changeset = GroupSettingChangeset {
update_groups: vec![GroupChangeset::from(params)],
};
database_editor
.update_group_setting(&view_id, group_setting_changeset)
.await?;
Ok(())
}
#[tracing::instrument(level = "debug", skip(data, manager), err)] #[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn move_group_handler( pub(crate) async fn move_group_handler(
data: AFPluginData<MoveGroupPayloadPB>, data: AFPluginData<MoveGroupPayloadPB>,

View File

@ -51,6 +51,8 @@ pub fn init(database_manager: Arc<DatabaseManager2>) -> AFPlugin {
.event(DatabaseEvent::MoveGroupRow, move_group_row_handler) .event(DatabaseEvent::MoveGroupRow, move_group_row_handler)
.event(DatabaseEvent::GetGroups, get_groups_handler) .event(DatabaseEvent::GetGroups, get_groups_handler)
.event(DatabaseEvent::GetGroup, get_group_handler) .event(DatabaseEvent::GetGroup, get_group_handler)
.event(DatabaseEvent::SetGroupByField, set_group_by_field_handler)
.event(DatabaseEvent::UpdateGroup, update_group_handler)
// Database // Database
.event(DatabaseEvent::GetDatabases, get_databases_handler) .event(DatabaseEvent::GetDatabases, get_databases_handler)
// Calendar // Calendar
@ -243,25 +245,31 @@ pub enum DatabaseEvent {
#[event(input = "MoveGroupRowPayloadPB")] #[event(input = "MoveGroupRowPayloadPB")]
MoveGroupRow = 112, MoveGroupRow = 112,
#[event(input = "GroupByFieldPayloadPB")]
SetGroupByField = 113,
#[event(input = "UpdateGroupPB")]
UpdateGroup = 114,
/// Returns all the databases /// Returns all the databases
#[event(output = "RepeatedDatabaseDescriptionPB")] #[event(output = "RepeatedDatabaseDescriptionPB")]
GetDatabases = 114, GetDatabases = 120,
#[event(input = "LayoutSettingChangesetPB")] #[event(input = "LayoutSettingChangesetPB")]
SetLayoutSetting = 115, SetLayoutSetting = 121,
#[event(input = "DatabaseLayoutIdPB", output = "LayoutSettingPB")] #[event(input = "DatabaseLayoutIdPB", output = "LayoutSettingPB")]
GetLayoutSetting = 116, GetLayoutSetting = 122,
#[event(input = "CalendarEventRequestPB", output = "RepeatedCalendarEventPB")] #[event(input = "CalendarEventRequestPB", output = "RepeatedCalendarEventPB")]
GetAllCalendarEvents = 117, GetAllCalendarEvents = 123,
#[event(input = "RowIdPB", output = "CalendarEventPB")] #[event(input = "RowIdPB", output = "CalendarEventPB")]
GetCalendarEvent = 118, GetCalendarEvent = 124,
#[event(input = "MoveCalendarEventPB")] #[event(input = "MoveCalendarEventPB")]
MoveCalendarEvent = 119, MoveCalendarEvent = 125,
#[event(input = "DatabaseImportPB")] #[event(input = "DatabaseImportPB")]
ImportCSV = 120, ImportCSV = 130,
} }

View File

@ -16,7 +16,7 @@ pub enum DatabaseNotification {
/// Trigger after editing a field properties including rename,update type option, etc /// Trigger after editing a field properties including rename,update type option, etc
DidUpdateField = 50, DidUpdateField = 50,
/// Trigger after the number of groups is changed /// Trigger after the number of groups is changed
DidUpdateGroups = 60, DidUpdateNumOfGroups = 60,
/// Trigger after inserting/deleting/updating/moving a row /// Trigger after inserting/deleting/updating/moving a row
DidUpdateGroupRow = 61, DidUpdateGroupRow = 61,
/// Trigger when setting a new grouping field /// Trigger when setting a new grouping field

View File

@ -15,11 +15,11 @@ use flowy_task::TaskDispatcher;
use lib_infra::future::{to_fut, Fut}; use lib_infra::future::{to_fut, Fut};
use crate::entities::{ use crate::entities::{
AlterFilterParams, AlterSortParams, CalendarEventPB, CellChangesetNotifyPB, CellPB, CalendarEventPB, CellChangesetNotifyPB, CellPB, DatabaseFieldChangesetPB, DatabasePB,
DatabaseFieldChangesetPB, DatabasePB, DatabaseViewSettingPB, DeleteFilterParams, DatabaseViewSettingPB, DeleteFilterParams, DeleteGroupParams, DeleteSortParams,
DeleteGroupParams, DeleteSortParams, FieldChangesetParams, FieldIdPB, FieldPB, FieldType, FieldChangesetParams, FieldIdPB, FieldPB, FieldType, GroupPB, IndexFieldPB, InsertedRowPB,
GroupPB, IndexFieldPB, InsertGroupParams, InsertedRowPB, LayoutSettingParams, RepeatedFilterPB, LayoutSettingParams, RepeatedFilterPB, RepeatedGroupPB, RepeatedSortPB, RowPB, RowsChangePB,
RepeatedGroupPB, RepeatedSortPB, RowPB, RowsChangePB, SelectOptionCellDataPB, SelectOptionPB, SelectOptionCellDataPB, SelectOptionPB, UpdateFilterParams, UpdateSortParams,
}; };
use crate::notification::{send_notification, DatabaseNotification}; use crate::notification::{send_notification, DatabaseNotification};
use crate::services::cell::{ use crate::services::cell::{
@ -34,7 +34,9 @@ use crate::services::field::{
SelectOptionIds, TypeOptionCellDataHandler, TypeOptionCellExt, SelectOptionIds, TypeOptionCellDataHandler, TypeOptionCellExt,
}; };
use crate::services::filter::Filter; use crate::services::filter::Filter;
use crate::services::group::{default_group_setting, GroupSetting, RowChangeset}; use crate::services::group::{
default_group_setting, GroupSetting, GroupSettingChangeset, RowChangeset,
};
use crate::services::share::csv::{CSVExport, CSVFormat}; use crate::services::share::csv::{CSVExport, CSVFormat};
use crate::services::sort::Sort; use crate::services::sort::Sort;
@ -85,18 +87,18 @@ impl DatabaseEditor {
self.database.lock().fields.get_field(field_id) self.database.lock().fields.get_field(field_id)
} }
pub async fn insert_group(&self, params: InsertGroupParams) -> FlowyResult<()> { pub async fn set_group_by_field(&self, view_id: &str, field_id: &str) -> FlowyResult<()> {
{ {
let database = self.database.lock(); let database = self.database.lock();
let field = database.fields.get_field(&params.field_id); let field = database.fields.get_field(field_id);
if let Some(field) = field { if let Some(field) = field {
let group_setting = default_group_setting(&field); let group_setting = default_group_setting(&field);
database.insert_group_setting(&params.view_id, group_setting); database.insert_group_setting(view_id, group_setting);
} }
} }
let view_editor = self.database_views.get_view_editor(&params.view_id).await?; let view_editor = self.database_views.get_view_editor(view_id).await?;
view_editor.v_initialize_new_group(params).await?; view_editor.v_initialize_new_group(field_id).await?;
Ok(()) Ok(())
} }
@ -111,8 +113,20 @@ impl DatabaseEditor {
Ok(()) Ok(())
} }
pub async fn update_group_setting(
&self,
view_id: &str,
group_setting_changeset: GroupSettingChangeset,
) -> FlowyResult<()> {
let view_editor = self.database_views.get_view_editor(view_id).await?;
view_editor
.update_group_setting(group_setting_changeset)
.await?;
Ok(())
}
#[tracing::instrument(level = "trace", skip_all, err)] #[tracing::instrument(level = "trace", skip_all, err)]
pub async fn create_or_update_filter(&self, params: AlterFilterParams) -> FlowyResult<()> { pub async fn create_or_update_filter(&self, params: UpdateFilterParams) -> FlowyResult<()> {
let view_editor = self.database_views.get_view_editor(&params.view_id).await?; let view_editor = self.database_views.get_view_editor(&params.view_id).await?;
view_editor.v_insert_filter(params).await?; view_editor.v_insert_filter(params).await?;
Ok(()) Ok(())
@ -124,7 +138,7 @@ impl DatabaseEditor {
Ok(()) Ok(())
} }
pub async fn create_or_update_sort(&self, params: AlterSortParams) -> FlowyResult<Sort> { pub async fn create_or_update_sort(&self, params: UpdateSortParams) -> FlowyResult<Sort> {
let view_editor = self.database_views.get_view_editor(&params.view_id).await?; let view_editor = self.database_views.get_view_editor(&params.view_id).await?;
let sort = view_editor.v_insert_sort(params).await?; let sort = view_editor.v_insert_sort(params).await?;
Ok(sort) Ok(sort)
@ -549,6 +563,8 @@ impl DatabaseEditor {
Some(SelectOptionPB::from(select_option)) Some(SelectOptionPB::from(select_option))
} }
/// Insert the options into the field's type option and update the cell content with the new options.
/// Only used for single select and multiple select.
pub async fn insert_select_options( pub async fn insert_select_options(
&self, &self,
view_id: &str, view_id: &str,
@ -556,30 +572,25 @@ impl DatabaseEditor {
row_id: RowId, row_id: RowId,
options: Vec<SelectOptionPB>, options: Vec<SelectOptionPB>,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
let field = match self.database.lock().fields.get_field(field_id) { let field = self.database.lock().fields.get_field(field_id).ok_or(
Some(field) => Ok(field), FlowyError::record_not_found().context(format!("Field with id:{} not found", &field_id)),
None => { )?;
let msg = format!("Field with id:{} not found", &field_id); debug_assert!(FieldType::from(field.field_type).is_select_option());
Err(FlowyError::internal().context(msg))
},
}?;
let mut type_option = select_type_option_from_field(&field)?; let mut type_option = select_type_option_from_field(&field)?;
let cell_changeset = SelectOptionCellChangeset { let cell_changeset = SelectOptionCellChangeset {
insert_option_ids: options.iter().map(|option| option.id.clone()).collect(), insert_option_ids: options.iter().map(|option| option.id.clone()).collect(),
..Default::default() ..Default::default()
}; };
options
.into_iter()
.for_each(|option| type_option.insert_option(option.into()));
for option in options { // Update the field's type option
type_option.insert_option(option.into());
}
self self
.database .update_field_type_option(view_id, field_id, type_option.to_type_option_data(), field)
.lock() .await?;
.fields // Insert the options into the cell
.update_field(field_id, |update| {
update.set_type_option(field.field_type, Some(type_option.to_type_option_data()));
});
self self
.update_cell_with_changeset(view_id, row_id, field_id, cell_changeset) .update_cell_with_changeset(view_id, row_id, field_id, cell_changeset)
.await?; .await?;
@ -709,7 +720,7 @@ impl DatabaseEditor {
pub async fn group_by_field(&self, view_id: &str, field_id: &str) -> FlowyResult<()> { pub async fn group_by_field(&self, view_id: &str, field_id: &str) -> FlowyResult<()> {
let view = self.database_views.get_view_editor(view_id).await?; let view = self.database_views.get_view_editor(view_id).await?;
view.v_update_group_setting(field_id).await?; view.v_update_grouping_field(field_id).await?;
Ok(()) Ok(())
} }

View File

@ -1,6 +1,6 @@
#![allow(clippy::while_let_loop)] #![allow(clippy::while_let_loop)]
use crate::entities::{ use crate::entities::{
DatabaseViewSettingPB, FilterChangesetNotificationPB, GroupChangesetPB, GroupRowsNotificationPB, DatabaseViewSettingPB, FilterChangesetNotificationPB, GroupChangesPB, GroupRowsNotificationPB,
ReorderAllRowsPB, ReorderSingleRowPB, RowsVisibilityChangePB, SortChangesetNotificationPB, ReorderAllRowsPB, ReorderSingleRowPB, RowsVisibilityChangePB, SortChangesetNotificationPB,
}; };
use crate::notification::{send_notification, DatabaseNotification}; use crate::notification::{send_notification, DatabaseNotification};
@ -102,8 +102,8 @@ pub async fn notify_did_update_sort(notification: SortChangesetNotificationPB) {
} }
} }
pub(crate) async fn notify_did_update_groups(view_id: &str, changeset: GroupChangesetPB) { pub(crate) async fn notify_did_update_num_of_groups(view_id: &str, changeset: GroupChangesPB) {
send_notification(view_id, DatabaseNotification::DidUpdateGroups) send_notification(view_id, DatabaseNotification::DidUpdateNumOfGroups)
.payload(changeset) .payload(changeset)
.send(); .send();
} }

View File

@ -13,10 +13,10 @@ use flowy_task::TaskDispatcher;
use lib_infra::future::Fut; use lib_infra::future::Fut;
use crate::entities::{ use crate::entities::{
AlterFilterParams, AlterSortParams, CalendarEventPB, DeleteFilterParams, DeleteGroupParams, CalendarEventPB, DeleteFilterParams, DeleteGroupParams, DeleteSortParams, FieldType,
DeleteSortParams, FieldType, GroupChangesetPB, GroupPB, GroupRowsNotificationPB, GroupChangesPB, GroupPB, GroupRowsNotificationPB, InsertedRowPB, LayoutSettingPB,
InsertGroupParams, InsertedGroupPB, InsertedRowPB, LayoutSettingPB, LayoutSettingParams, RowPB, LayoutSettingParams, RowPB, RowsChangePB, SortChangesetNotificationPB, SortPB,
RowsChangePB, SortChangesetNotificationPB, SortPB, UpdateFilterParams, UpdateSortParams,
}; };
use crate::notification::{send_notification, DatabaseNotification}; use crate::notification::{send_notification, DatabaseNotification};
use crate::services::cell::CellCache; use crate::services::cell::CellCache;
@ -27,7 +27,7 @@ use crate::services::database_view::view_group::{
}; };
use crate::services::database_view::view_sort::make_sort_controller; use crate::services::database_view::view_sort::make_sort_controller;
use crate::services::database_view::{ use crate::services::database_view::{
notify_did_update_filter, notify_did_update_group_rows, notify_did_update_groups, notify_did_update_filter, notify_did_update_group_rows, notify_did_update_num_of_groups,
notify_did_update_setting, notify_did_update_sort, DatabaseViewChangedNotifier, notify_did_update_setting, notify_did_update_sort, DatabaseViewChangedNotifier,
DatabaseViewChangedReceiverRunner, DatabaseViewChangedReceiverRunner,
}; };
@ -35,7 +35,9 @@ use crate::services::field::TypeOptionCellDataHandler;
use crate::services::filter::{ use crate::services::filter::{
Filter, FilterChangeset, FilterController, FilterType, UpdatedFilterType, Filter, FilterChangeset, FilterController, FilterType, UpdatedFilterType,
}; };
use crate::services::group::{GroupController, GroupSetting, MoveGroupRowContext, RowChangeset}; use crate::services::group::{
GroupController, GroupSetting, GroupSettingChangeset, MoveGroupRowContext, RowChangeset,
};
use crate::services::setting::CalendarLayoutSetting; use crate::services::setting::CalendarLayoutSetting;
use crate::services::sort::{DeletedSortType, Sort, SortChangeset, SortController, SortType}; use crate::services::sort::{DeletedSortType, Sort, SortChangeset, SortController, SortType};
@ -237,26 +239,28 @@ impl DatabaseViewEditor {
.await; .await;
if let Some(Ok(result)) = result { if let Some(Ok(result)) = result {
let mut changeset = GroupChangesetPB { let mut group_changes = GroupChangesPB {
view_id: self.view_id.clone(), view_id: self.view_id.clone(),
..Default::default() ..Default::default()
}; };
if let Some(inserted_group) = result.inserted_group { if let Some(inserted_group) = result.inserted_group {
tracing::trace!("Create group after editing the row: {:?}", inserted_group); tracing::trace!("Create group after editing the row: {:?}", inserted_group);
changeset.inserted_groups.push(inserted_group); group_changes.inserted_groups.push(inserted_group);
} }
if let Some(delete_group) = result.deleted_group { if let Some(delete_group) = result.deleted_group {
tracing::trace!("Delete group after editing the row: {:?}", delete_group); tracing::trace!("Delete group after editing the row: {:?}", delete_group);
changeset.deleted_groups.push(delete_group.group_id); group_changes.deleted_groups.push(delete_group.group_id);
}
if !group_changes.is_empty() {
notify_did_update_num_of_groups(&self.view_id, group_changes).await;
} }
notify_did_update_groups(&self.view_id, changeset).await;
tracing::trace!(
"Group changesets after editing the row: {:?}",
result.row_changesets
);
for changeset in result.row_changesets { for changeset in result.row_changesets {
notify_did_update_group_rows(changeset).await; if !changeset.is_empty() {
tracing::trace!("Group change after editing the row: {:?}", changeset);
notify_did_update_group_rows(changeset).await;
}
} }
} else { } else {
let update_row = UpdatedRow { let update_row = UpdatedRow {
@ -326,15 +330,15 @@ impl DatabaseViewEditor {
.await; .await;
if let Some(result) = result { if let Some(result) = result {
let mut changeset = GroupChangesetPB {
view_id: self.view_id.clone(),
..Default::default()
};
if let Some(delete_group) = result.deleted_group { if let Some(delete_group) = result.deleted_group {
tracing::info!("Delete group after moving the row: {:?}", delete_group); tracing::trace!("Delete group after moving the row: {:?}", delete_group);
changeset.deleted_groups.push(delete_group.group_id); let mut changes = GroupChangesPB {
view_id: self.view_id.clone(),
..Default::default()
};
changes.deleted_groups.push(delete_group.group_id);
notify_did_update_num_of_groups(&self.view_id, changes).await;
} }
notify_did_update_groups(&self.view_id, changeset).await;
for changeset in result.row_changesets { for changeset in result.row_changesets {
notify_did_update_group_rows(changeset).await; notify_did_update_group_rows(changeset).await;
@ -371,25 +375,6 @@ impl DatabaseViewEditor {
.write() .write()
.await .await
.move_group(from_group, to_group)?; .move_group(from_group, to_group)?;
match self.group_controller.read().await.get_group(from_group) {
None => tracing::warn!("Can not find the group with id: {}", from_group),
Some((index, group)) => {
let inserted_group = InsertedGroupPB {
group: GroupPB::from(group),
index: index as i32,
};
let changeset = GroupChangesetPB {
view_id: self.view_id.clone(),
inserted_groups: vec![inserted_group],
deleted_groups: vec![from_group.to_string()],
update_groups: vec![],
initial_groups: vec![],
};
notify_did_update_groups(&self.view_id, changeset).await;
},
}
Ok(()) Ok(())
} }
@ -397,9 +382,9 @@ impl DatabaseViewEditor {
self.group_controller.read().await.field_id().to_string() self.group_controller.read().await.field_id().to_string()
} }
pub async fn v_initialize_new_group(&self, params: InsertGroupParams) -> FlowyResult<()> { pub async fn v_initialize_new_group(&self, field_id: &str) -> FlowyResult<()> {
if self.group_controller.read().await.field_id() != params.field_id { if self.group_controller.read().await.field_id() != field_id {
self.v_update_group_setting(&params.field_id).await?; self.v_update_grouping_field(field_id).await?;
if let Some(view) = self.delegate.get_view_setting(&self.view_id).await { if let Some(view) = self.delegate.get_view_setting(&self.view_id).await {
let setting = database_view_setting_pb_from_view(view); let setting = database_view_setting_pb_from_view(view);
@ -413,12 +398,20 @@ impl DatabaseViewEditor {
Ok(()) Ok(())
} }
pub async fn update_group_setting(&self, changeset: GroupSettingChangeset) -> FlowyResult<()> {
self
.group_controller
.write()
.await
.apply_group_setting_changeset(changeset)
}
pub async fn v_get_all_sorts(&self) -> Vec<Sort> { pub async fn v_get_all_sorts(&self) -> Vec<Sort> {
self.delegate.get_all_sorts(&self.view_id) self.delegate.get_all_sorts(&self.view_id)
} }
#[tracing::instrument(level = "trace", skip(self), err)] #[tracing::instrument(level = "trace", skip(self), err)]
pub async fn v_insert_sort(&self, params: AlterSortParams) -> FlowyResult<Sort> { pub async fn v_insert_sort(&self, params: UpdateSortParams) -> FlowyResult<Sort> {
let is_exist = params.sort_id.is_some(); let is_exist = params.sort_id.is_some();
let sort_id = match params.sort_id { let sort_id = match params.sort_id {
None => gen_database_sort_id(), None => gen_database_sort_id(),
@ -479,7 +472,7 @@ impl DatabaseViewEditor {
} }
#[tracing::instrument(level = "trace", skip(self), err)] #[tracing::instrument(level = "trace", skip(self), err)]
pub async fn v_insert_filter(&self, params: AlterFilterParams) -> FlowyResult<()> { pub async fn v_insert_filter(&self, params: UpdateFilterParams) -> FlowyResult<()> {
let is_exist = params.filter_id.is_some(); let is_exist = params.filter_id.is_some();
let filter_id = match params.filter_id { let filter_id = match params.filter_id {
None => gen_database_filter_id(), None => gen_database_filter_id(),
@ -634,9 +627,15 @@ impl DatabaseViewEditor {
.sort_controller .sort_controller
.read() .read()
.await .await
.did_update_view_field_type_option(&field) .did_update_field_type_option(&field)
.await; .await;
self
.group_controller
.write()
.await
.did_update_field_type_option(&field);
if let Some(filter) = self if let Some(filter) = self
.delegate .delegate
.get_filter_by_field_id(&self.view_id, field_id) .get_filter_by_field_id(&self.view_id, field_id)
@ -660,14 +659,9 @@ impl DatabaseViewEditor {
Ok(()) Ok(())
} }
/// /// Called when a grouping field is updated.
///
/// # Arguments
///
/// * `field_id`:
///
#[tracing::instrument(level = "debug", skip_all, err)] #[tracing::instrument(level = "debug", skip_all, err)]
pub async fn v_update_group_setting(&self, field_id: &str) -> FlowyResult<()> { pub async fn v_update_grouping_field(&self, field_id: &str) -> FlowyResult<()> {
if let Some(field) = self.delegate.get_field(field_id).await { if let Some(field) = self.delegate.get_field(field_id).await {
let new_group_controller = let new_group_controller =
new_group_controller_with_field(self.view_id.clone(), self.delegate.clone(), field).await?; new_group_controller_with_field(self.view_id.clone(), self.delegate.clone(), field).await?;
@ -679,7 +673,7 @@ impl DatabaseViewEditor {
.collect(); .collect();
*self.group_controller.write().await = new_group_controller; *self.group_controller.write().await = new_group_controller;
let changeset = GroupChangesetPB { let changeset = GroupChangesPB {
view_id: self.view_id.clone(), view_id: self.view_id.clone(),
initial_groups: new_groups, initial_groups: new_groups,
..Default::default() ..Default::default()

View File

@ -5,7 +5,6 @@ use collab_database::rows::RowId;
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use lib_infra::future::{to_fut, Fut}; use lib_infra::future::{to_fut, Fut};
use tracing::trace;
use crate::entities::FieldType; use crate::entities::FieldType;
use crate::services::database_view::DatabaseViewData; use crate::services::database_view::DatabaseViewData;
@ -43,7 +42,6 @@ pub async fn new_group_controller(
let fields = delegate.get_fields(&view_id, None).await; let fields = delegate.get_fields(&view_id, None).await;
let rows = delegate.get_rows(&view_id).await; let rows = delegate.get_rows(&view_id).await;
let layout = delegate.get_layout_for_view(&view_id); let layout = delegate.get_layout_for_view(&view_id);
trace!(?fields, ?rows, ?layout, "new_group_controller");
// Read the grouping field or find a new grouping field // Read the grouping field or find a new grouping field
let mut grouping_field = setting_reader let mut grouping_field = setting_reader

View File

@ -94,7 +94,7 @@ impl DatabaseViews {
// If the id of the grouping field is equal to the updated field's id, then we need to // If the id of the grouping field is equal to the updated field's id, then we need to
// update the group setting // update the group setting
if view_editor.group_id().await == field_id { if view_editor.group_id().await == field_id {
view_editor.v_update_group_setting(field_id).await?; view_editor.v_update_grouping_field(field_id).await?;
} }
view_editor view_editor
.v_did_update_field_type_option(field_id, old_field) .v_did_update_field_type_option(field_id, old_field)
@ -108,7 +108,6 @@ impl DatabaseViews {
return Ok(editor.clone()); return Ok(editor.clone());
} }
tracing::trace!("{:p} create view:{} editor", self, view_id);
let mut editor_map = self.editor_map.write().await; let mut editor_map = self.editor_map.write().await;
let editor = Arc::new( let editor = Arc::new(
DatabaseViewEditor::new( DatabaseViewEditor::new(

View File

@ -22,6 +22,8 @@ pub trait SelectTypeOptionSharedAction: Send + Sync {
fn number_of_max_options(&self) -> Option<usize>; fn number_of_max_options(&self) -> Option<usize>;
/// Insert the `SelectOption` into corresponding type option. /// Insert the `SelectOption` into corresponding type option.
/// If the option already exists, it will be updated.
/// If the option does not exist, it will be inserted at the beginning.
fn insert_option(&mut self, new_option: SelectOption) { fn insert_option(&mut self, new_option: SelectOption) {
let options = self.mut_options(); let options = self.mut_options();
if let Some(index) = options if let Some(index) = options

View File

@ -131,12 +131,12 @@ where
if let Some(cell_data_cache) = self.cell_data_cache.as_ref() { if let Some(cell_data_cache) = self.cell_data_cache.as_ref() {
let read_guard = cell_data_cache.read(); let read_guard = cell_data_cache.read();
if let Some(cell_data) = read_guard.get(key.as_ref()).cloned() { if let Some(cell_data) = read_guard.get(key.as_ref()).cloned() {
tracing::trace!( // tracing::trace!(
"Cell cache hit: field_type:{}, cell: {:?}, cell_data: {:?}", // "Cell cache hit: field_type:{}, cell: {:?}, cell_data: {:?}",
decoded_field_type, // decoded_field_type,
cell, // cell,
cell_data // cell_data
); // );
return Ok(cell_data); return Ok(cell_data);
} }
} }

View File

@ -219,12 +219,14 @@ impl FilterController {
} }
pub async fn did_receive_row_changed(&self, row_id: RowId) { pub async fn did_receive_row_changed(&self, row_id: RowId) {
self if !self.cell_filter_cache.read().is_empty() {
.gen_task( self
FilterEvent::RowDidChanged(row_id), .gen_task(
QualityOfService::UserInteractive, FilterEvent::RowDidChanged(row_id),
) QualityOfService::UserInteractive,
.await )
.await
}
} }
#[tracing::instrument(level = "trace", skip(self))] #[tracing::instrument(level = "trace", skip(self))]

View File

@ -1,7 +1,7 @@
use crate::entities::{GroupChangesetPB, GroupPB, GroupRowsNotificationPB, InsertedGroupPB}; use crate::entities::{GroupChangesPB, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
use crate::services::cell::DecodedCellData; use crate::services::cell::DecodedCellData;
use crate::services::group::controller::MoveGroupRowContext; use crate::services::group::controller::MoveGroupRowContext;
use crate::services::group::GroupData; use crate::services::group::{GroupData, GroupSettingChangeset};
use collab_database::fields::Field; use collab_database::fields::Field;
use collab_database::rows::{Cell, Row}; use collab_database::rows::{Cell, Row};
@ -65,7 +65,7 @@ pub trait GroupCustomize: Send + Sync {
} }
/// Defines the shared actions any group controller can perform. /// Defines the shared actions any group controller can perform.
pub trait GroupControllerActions: Send + Sync { pub trait GroupControllerOperation: Send + Sync {
/// The field that is used for grouping the rows /// The field that is used for grouping the rows
fn field_id(&self) -> &str; fn field_id(&self) -> &str;
@ -100,7 +100,9 @@ pub trait GroupControllerActions: Send + Sync {
fn move_group_row(&mut self, context: MoveGroupRowContext) -> FlowyResult<DidMoveGroupRowResult>; fn move_group_row(&mut self, context: MoveGroupRowContext) -> FlowyResult<DidMoveGroupRowResult>;
/// Update the group if the corresponding field is changed /// Update the group if the corresponding field is changed
fn did_update_group_field(&mut self, field: &Field) -> FlowyResult<Option<GroupChangesetPB>>; fn did_update_group_field(&mut self, field: &Field) -> FlowyResult<Option<GroupChangesPB>>;
fn apply_group_setting_changeset(&mut self, changeset: GroupSettingChangeset) -> FlowyResult<()>;
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -1,7 +1,7 @@
use crate::entities::{GroupChangesetPB, GroupPB, InsertedGroupPB}; use crate::entities::{GroupChangesPB, GroupPB, InsertedGroupPB};
use crate::services::field::RowSingleCellData; use crate::services::field::RowSingleCellData;
use crate::services::group::{ use crate::services::group::{
default_group_setting, GeneratedGroupContext, Group, GroupData, GroupSetting, default_group_setting, GeneratedGroups, Group, GroupChangeset, GroupData, GroupSetting,
}; };
use collab_database::fields::Field; use collab_database::fields::Field;
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
@ -25,7 +25,7 @@ pub trait GroupSettingWriter: Send + Sync + 'static {
impl<T> std::fmt::Display for GroupContext<T> { impl<T> std::fmt::Display for GroupContext<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.groups_map.iter().for_each(|(_, group)| { self.group_by_id.iter().for_each(|(_, group)| {
let _ = f.write_fmt(format_args!( let _ = f.write_fmt(format_args!(
"Group:{} has {} rows \n", "Group:{} has {} rows \n",
group.id, group.id,
@ -54,8 +54,9 @@ pub struct GroupContext<C> {
/// The grouping field /// The grouping field
field: Arc<Field>, field: Arc<Field>,
/// Cache all the groups /// Cache all the groups. Cache the group by its id.
groups_map: IndexMap<String, GroupData>, /// We use the id of the [Field] as the [No Status] group id.
group_by_id: IndexMap<String, GroupData>,
/// A reader that implement the [GroupSettingReader] trait /// A reader that implement the [GroupSettingReader] trait
/// ///
@ -93,7 +94,7 @@ where
Ok(Self { Ok(Self {
view_id, view_id,
field, field,
groups_map: IndexMap::new(), group_by_id: IndexMap::new(),
reader, reader,
writer, writer,
setting, setting,
@ -105,26 +106,26 @@ where
/// ///
/// We take the `id` of the `field` as the no status group id /// We take the `id` of the `field` as the no status group id
pub(crate) fn get_no_status_group(&self) -> Option<&GroupData> { pub(crate) fn get_no_status_group(&self) -> Option<&GroupData> {
self.groups_map.get(&self.field.id) self.group_by_id.get(&self.field.id)
} }
pub(crate) fn get_mut_no_status_group(&mut self) -> Option<&mut GroupData> { pub(crate) fn get_mut_no_status_group(&mut self) -> Option<&mut GroupData> {
self.groups_map.get_mut(&self.field.id) self.group_by_id.get_mut(&self.field.id)
} }
pub(crate) fn groups(&self) -> Vec<&GroupData> { pub(crate) fn groups(&self) -> Vec<&GroupData> {
self.groups_map.values().collect() self.group_by_id.values().collect()
} }
pub(crate) fn get_mut_group(&mut self, group_id: &str) -> Option<&mut GroupData> { pub(crate) fn get_mut_group(&mut self, group_id: &str) -> Option<&mut GroupData> {
self.groups_map.get_mut(group_id) self.group_by_id.get_mut(group_id)
} }
// Returns the index and group specified by the group_id // Returns the index and group specified by the group_id
pub(crate) fn get_group(&self, group_id: &str) -> Option<(usize, &GroupData)> { pub(crate) fn get_group(&self, group_id: &str) -> Option<(usize, &GroupData)> {
match ( match (
self.groups_map.get_index_of(group_id), self.group_by_id.get_index_of(group_id),
self.groups_map.get(group_id), self.group_by_id.get(group_id),
) { ) {
(Some(index), Some(group)) => Some((index, group)), (Some(index), Some(group)) => Some((index, group)),
_ => None, _ => None,
@ -133,7 +134,7 @@ where
/// Iterate mut the groups without `No status` group /// Iterate mut the groups without `No status` group
pub(crate) fn iter_mut_status_groups(&mut self, mut each: impl FnMut(&mut GroupData)) { pub(crate) fn iter_mut_status_groups(&mut self, mut each: impl FnMut(&mut GroupData)) {
self.groups_map.iter_mut().for_each(|(_, group)| { self.group_by_id.iter_mut().for_each(|(_, group)| {
if group.id != self.field.id { if group.id != self.field.id {
each(group); each(group);
} }
@ -141,7 +142,7 @@ where
} }
pub(crate) fn iter_mut_groups(&mut self, mut each: impl FnMut(&mut GroupData)) { pub(crate) fn iter_mut_groups(&mut self, mut each: impl FnMut(&mut GroupData)) {
self.groups_map.iter_mut().for_each(|(_, group)| { self.group_by_id.iter_mut().for_each(|(_, group)| {
each(group); each(group);
}); });
} }
@ -153,7 +154,7 @@ where
group.name.clone(), group.name.clone(),
group.id.clone(), group.id.clone(),
); );
self.groups_map.insert(group.id.clone(), group_data); self.group_by_id.insert(group.id.clone(), group_data);
let (index, group_data) = self.get_group(&group.id).unwrap(); let (index, group_data) = self.get_group(&group.id).unwrap();
let insert_group = InsertedGroupPB { let insert_group = InsertedGroupPB {
group: GroupPB::from(group_data.clone()), group: GroupPB::from(group_data.clone()),
@ -170,7 +171,7 @@ where
#[tracing::instrument(level = "trace", skip(self))] #[tracing::instrument(level = "trace", skip(self))]
pub(crate) fn delete_group(&mut self, deleted_group_id: &str) -> FlowyResult<()> { pub(crate) fn delete_group(&mut self, deleted_group_id: &str) -> FlowyResult<()> {
self.groups_map.remove(deleted_group_id); self.group_by_id.remove(deleted_group_id);
self.mut_configuration(|configuration| { self.mut_configuration(|configuration| {
configuration configuration
.groups .groups
@ -181,11 +182,11 @@ where
} }
pub(crate) fn move_group(&mut self, from_id: &str, to_id: &str) -> FlowyResult<()> { pub(crate) fn move_group(&mut self, from_id: &str, to_id: &str) -> FlowyResult<()> {
let from_index = self.groups_map.get_index_of(from_id); let from_index = self.group_by_id.get_index_of(from_id);
let to_index = self.groups_map.get_index_of(to_id); let to_index = self.group_by_id.get_index_of(to_id);
match (from_index, to_index) { match (from_index, to_index) {
(Some(from_index), Some(to_index)) => { (Some(from_index), Some(to_index)) => {
self.groups_map.move_index(from_index, to_index); self.group_by_id.move_index(from_index, to_index);
self.mut_configuration(|configuration| { self.mut_configuration(|configuration| {
let from_index = configuration let from_index = configuration
@ -205,7 +206,7 @@ where
let group = configuration.groups.remove(*from); let group = configuration.groups.remove(*from);
configuration.groups.insert(*to, group); configuration.groups.insert(*to, group);
} }
tracing::debug!( tracing::trace!(
"Group order: {:?} ", "Group order: {:?} ",
configuration configuration
.groups .groups
@ -237,15 +238,15 @@ where
/// [GroupConfigurationRevision] as old groups. The old groups and the new groups will be merged /// [GroupConfigurationRevision] as old groups. The old groups and the new groups will be merged
/// while keeping the order of the old groups. /// while keeping the order of the old groups.
/// ///
#[tracing::instrument(level = "trace", skip(self, generated_group_context), err)] #[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) fn init_groups( pub(crate) fn init_groups(
&mut self, &mut self,
generated_group_context: GeneratedGroupContext, generated_groups: GeneratedGroups,
) -> FlowyResult<Option<GroupChangesetPB>> { ) -> FlowyResult<Option<GroupChangesPB>> {
let GeneratedGroupContext { let GeneratedGroups {
no_status_group, no_status_group,
group_configs, group_configs,
} = generated_group_context; } = generated_groups;
let mut new_groups = vec![]; let mut new_groups = vec![];
let mut filter_content_map = HashMap::new(); let mut filter_content_map = HashMap::new();
@ -310,18 +311,13 @@ where
})?; })?;
// Update the memory cache of the groups // Update the memory cache of the groups
all_groups.into_iter().for_each(|group_rev| { all_groups.into_iter().for_each(|group| {
let filter_content = filter_content_map let filter_content = filter_content_map
.get(&group_rev.id) .get(&group.id)
.cloned() .cloned()
.unwrap_or_else(|| "".to_owned()); .unwrap_or_else(|| "".to_owned());
let group = GroupData::new( let group = GroupData::new(group.id, self.field.id.clone(), group.name, filter_content);
group_rev.id, self.group_by_id.insert(group.id.clone(), group);
self.field.id.clone(),
group_rev.name,
filter_content,
);
self.groups_map.insert(group.id.clone(), group);
}); });
let initial_groups = new_groups let initial_groups = new_groups
@ -338,13 +334,14 @@ where
}) })
.collect(); .collect();
let changeset = GroupChangesetPB { let changeset = GroupChangesPB {
view_id: self.view_id.clone(), view_id: self.view_id.clone(),
initial_groups, initial_groups,
deleted_groups: deleted_group_ids, deleted_groups: deleted_group_ids,
update_groups: vec![], update_groups: vec![],
inserted_groups: vec![], inserted_groups: vec![],
}; };
tracing::trace!("Group changeset: {:?}", changeset); tracing::trace!("Group changeset: {:?}", changeset);
if changeset.is_empty() { if changeset.is_empty() {
Ok(None) Ok(None)
@ -353,18 +350,15 @@ where
} }
} }
#[allow(dead_code)] pub(crate) fn update_group(&mut self, group_changeset: GroupChangeset) -> FlowyResult<()> {
pub(crate) async fn hide_group(&mut self, group_id: &str) -> FlowyResult<()> { self.mut_group(&group_changeset.group_id, |group| {
self.mut_group_rev(group_id, |group_rev| { if let Some(visible) = group_changeset.visible {
group_rev.visible = false; group.visible = visible;
})?; }
Ok(())
}
#[allow(dead_code)] if let Some(name) = &group_changeset.name {
pub(crate) async fn show_group(&mut self, group_id: &str) -> FlowyResult<()> { group.name = name.clone();
self.mut_group_rev(group_id, |group_rev| { }
group_rev.visible = true;
})?; })?;
Ok(()) Ok(())
} }
@ -398,11 +392,7 @@ where
Ok(()) Ok(())
} }
fn mut_group_rev( fn mut_group(&mut self, group_id: &str, mut_groups_fn: impl Fn(&mut Group)) -> FlowyResult<()> {
&mut self,
group_id: &str,
mut_groups_fn: impl Fn(&mut Group),
) -> FlowyResult<()> {
self.mut_configuration(|configuration| { self.mut_configuration(|configuration| {
match configuration match configuration
.groups .groups

View File

@ -9,14 +9,14 @@ use serde::Serialize;
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use crate::entities::{FieldType, GroupChangesetPB, GroupRowsNotificationPB, InsertedRowPB}; use crate::entities::{FieldType, GroupChangesPB, GroupRowsNotificationPB, InsertedRowPB};
use crate::services::cell::{get_cell_protobuf, CellProtobufBlobParser, DecodedCellData}; use crate::services::cell::{get_cell_protobuf, CellProtobufBlobParser, DecodedCellData};
use crate::services::group::action::{ use crate::services::group::action::{
DidMoveGroupRowResult, DidUpdateGroupRowResult, GroupControllerActions, GroupCustomize, DidMoveGroupRowResult, DidUpdateGroupRowResult, GroupControllerOperation, GroupCustomize,
}; };
use crate::services::group::configuration::GroupContext; use crate::services::group::configuration::GroupContext;
use crate::services::group::entities::GroupData; use crate::services::group::entities::GroupData;
use crate::services::group::Group; use crate::services::group::{Group, GroupSettingChangeset};
// use collab_database::views::Group; // use collab_database::views::Group;
@ -28,24 +28,30 @@ use crate::services::group::Group;
/// If the [FieldType] doesn't implement its group controller, then the [DefaultGroupController] will /// If the [FieldType] doesn't implement its group controller, then the [DefaultGroupController] will
/// be used. /// be used.
/// ///
pub trait GroupController: GroupControllerActions + Send + Sync { pub trait GroupController: GroupControllerOperation + Send + Sync {
/// Called when the type option of the [Field] was updated.
fn did_update_field_type_option(&mut self, field: &Arc<Field>);
/// Called before the row was created.
fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str); fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str);
/// Called after the row was created.
fn did_create_row(&mut self, row: &Row, group_id: &str); fn did_create_row(&mut self, row: &Row, group_id: &str);
} }
/// The [GroupGenerator] trait is used to generate the groups for different [FieldType] /// The [GroupsBuilder] trait is used to generate the groups for different [FieldType]
pub trait GroupGenerator { pub trait GroupsBuilder {
type Context; type Context;
type TypeOptionType; type TypeOptionType;
fn generate_groups( fn build(
field: &Field, field: &Field,
group_ctx: &Self::Context, context: &Self::Context,
type_option: &Option<Self::TypeOptionType>, type_option: &Option<Self::TypeOptionType>,
) -> GeneratedGroupContext; ) -> GeneratedGroups;
} }
pub struct GeneratedGroupContext { pub struct GeneratedGroups {
pub no_status_group: Option<Group>, pub no_status_group: Option<Group>,
pub group_configs: Vec<GeneratedGroupConfig>, pub group_configs: Vec<GeneratedGroupConfig>,
} }
@ -90,21 +96,21 @@ impl RowChangeset {
/// C: represents the group configuration that impl [GroupConfigurationSerde] /// C: represents the group configuration that impl [GroupConfigurationSerde]
/// T: the type-option data deserializer that impl [TypeOptionDataDeserializer] /// T: the type-option data deserializer that impl [TypeOptionDataDeserializer]
/// G: the group generator, [GroupGenerator] /// G: the group generator, [GroupsBuilder]
/// P: the parser that impl [CellProtobufBlobParser] for the CellBytes /// P: the parser that impl [CellProtobufBlobParser] for the CellBytes
pub struct GenericGroupController<C, T, G, P> { pub struct BaseGroupController<C, T, G, P> {
pub grouping_field_id: String, pub grouping_field_id: String,
pub type_option: Option<T>, pub type_option: Option<T>,
pub group_ctx: GroupContext<C>, pub context: GroupContext<C>,
group_action_phantom: PhantomData<G>, group_action_phantom: PhantomData<G>,
cell_parser_phantom: PhantomData<P>, cell_parser_phantom: PhantomData<P>,
} }
impl<C, T, G, P> GenericGroupController<C, T, G, P> impl<C, T, G, P> BaseGroupController<C, T, G, P>
where where
C: Serialize + DeserializeOwned, C: Serialize + DeserializeOwned,
T: From<TypeOptionData>, T: From<TypeOptionData>,
G: GroupGenerator<Context = GroupContext<C>, TypeOptionType = T>, G: GroupsBuilder<Context = GroupContext<C>, TypeOptionType = T>,
{ {
pub async fn new( pub async fn new(
grouping_field: &Arc<Field>, grouping_field: &Arc<Field>,
@ -112,13 +118,13 @@ where
) -> FlowyResult<Self> { ) -> FlowyResult<Self> {
let field_type = FieldType::from(grouping_field.field_type); let field_type = FieldType::from(grouping_field.field_type);
let type_option = grouping_field.get_type_option::<T>(field_type); let type_option = grouping_field.get_type_option::<T>(field_type);
let generated_group_context = G::generate_groups(grouping_field, &configuration, &type_option); let generated_groups = G::build(grouping_field, &configuration, &type_option);
let _ = configuration.init_groups(generated_group_context)?; let _ = configuration.init_groups(generated_groups)?;
Ok(Self { Ok(Self {
grouping_field_id: grouping_field.id.clone(), grouping_field_id: grouping_field.id.clone(),
type_option, type_option,
group_ctx: configuration, context: configuration,
group_action_phantom: PhantomData, group_action_phantom: PhantomData,
cell_parser_phantom: PhantomData, cell_parser_phantom: PhantomData,
}) })
@ -131,7 +137,7 @@ where
row: &Row, row: &Row,
other_group_changesets: &[GroupRowsNotificationPB], other_group_changesets: &[GroupRowsNotificationPB],
) -> Option<GroupRowsNotificationPB> { ) -> Option<GroupRowsNotificationPB> {
let no_status_group = self.group_ctx.get_mut_no_status_group()?; let no_status_group = self.context.get_mut_no_status_group()?;
// [other_group_inserted_row] contains all the inserted rows except the default group. // [other_group_inserted_row] contains all the inserted rows except the default group.
let other_group_inserted_row = other_group_changesets let other_group_inserted_row = other_group_changesets
@ -196,12 +202,12 @@ where
} }
} }
impl<C, T, G, P> GroupControllerActions for GenericGroupController<C, T, G, P> impl<C, T, G, P> GroupControllerOperation for BaseGroupController<C, T, G, P>
where where
P: CellProtobufBlobParser, P: CellProtobufBlobParser,
C: Serialize + DeserializeOwned, C: Serialize + DeserializeOwned,
T: From<TypeOptionData>, T: From<TypeOptionData>,
G: GroupGenerator<Context = GroupContext<C>, TypeOptionType = T>, G: GroupsBuilder<Context = GroupContext<C>, TypeOptionType = T>,
Self: GroupCustomize<CellData = P::Object>, Self: GroupCustomize<CellData = P::Object>,
{ {
@ -210,11 +216,11 @@ where
} }
fn groups(&self) -> Vec<&GroupData> { fn groups(&self) -> Vec<&GroupData> {
self.group_ctx.groups() self.context.groups()
} }
fn get_group(&self, group_id: &str) -> Option<(usize, GroupData)> { fn get_group(&self, group_id: &str) -> Option<(usize, GroupData)> {
let group = self.group_ctx.get_group(group_id)?; let group = self.context.get_group(group_id)?;
Some((group.0, group.1.clone())) Some((group.0, group.1.clone()))
} }
@ -230,7 +236,7 @@ where
let mut grouped_rows: Vec<GroupedRow> = vec![]; let mut grouped_rows: Vec<GroupedRow> = vec![];
let cell_bytes = get_cell_protobuf(&cell, field, None); let cell_bytes = get_cell_protobuf(&cell, field, None);
let cell_data = cell_bytes.parser::<P>()?; let cell_data = cell_bytes.parser::<P>()?;
for group in self.group_ctx.groups() { for group in self.context.groups() {
if self.can_group(&group.filter_content, &cell_data) { if self.can_group(&group.filter_content, &cell_data) {
grouped_rows.push(GroupedRow { grouped_rows.push(GroupedRow {
row: (*row).clone(), row: (*row).clone(),
@ -241,25 +247,25 @@ where
if !grouped_rows.is_empty() { if !grouped_rows.is_empty() {
for group_row in grouped_rows { for group_row in grouped_rows {
if let Some(group) = self.group_ctx.get_mut_group(&group_row.group_id) { if let Some(group) = self.context.get_mut_group(&group_row.group_id) {
group.add_row(group_row.row); group.add_row(group_row.row);
} }
} }
continue; continue;
} }
} }
match self.group_ctx.get_mut_no_status_group() { match self.context.get_mut_no_status_group() {
None => {}, None => {},
Some(no_status_group) => no_status_group.add_row((*row).clone()), Some(no_status_group) => no_status_group.add_row((*row).clone()),
} }
} }
tracing::Span::current().record("group_result", format!("{},", self.group_ctx,).as_str()); tracing::Span::current().record("group_result", format!("{},", self.context,).as_str());
Ok(()) Ok(())
} }
fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> { fn move_group(&mut self, from_group_id: &str, to_group_id: &str) -> FlowyResult<()> {
self.group_ctx.move_group(from_group_id, to_group_id) self.context.move_group(from_group_id, to_group_id)
} }
fn did_update_group_row( fn did_update_group_row(
@ -320,7 +326,7 @@ where
} }
} }
match self.group_ctx.get_no_status_group() { match self.context.get_no_status_group() {
None => { None => {
tracing::error!("Unexpected None value. It should have the no status group"); tracing::error!("Unexpected None value. It should have the no status group");
}, },
@ -359,9 +365,18 @@ where
Ok(result) Ok(result)
} }
fn did_update_group_field(&mut self, _field: &Field) -> FlowyResult<Option<GroupChangesetPB>> { fn did_update_group_field(&mut self, _field: &Field) -> FlowyResult<Option<GroupChangesPB>> {
Ok(None) Ok(None)
} }
fn apply_group_setting_changeset(&mut self, changeset: GroupSettingChangeset) -> FlowyResult<()> {
for group_changeset in changeset.update_groups {
if let Err(e) = self.context.update_group(group_changeset) {
tracing::error!("Failed to update group: {:?}", e);
}
}
Ok(())
}
} }
struct GroupedRow { struct GroupedRow {

View File

@ -1,6 +1,7 @@
use collab_database::fields::Field; use collab_database::fields::Field;
use collab_database::rows::{new_cell_builder, Cell, Cells, Row}; use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc;
use crate::entities::{FieldType, GroupRowsNotificationPB, InsertedRowPB, RowPB}; use crate::entities::{FieldType, GroupRowsNotificationPB, InsertedRowPB, RowPB};
use crate::services::cell::insert_checkbox_cell; use crate::services::cell::insert_checkbox_cell;
@ -10,16 +11,16 @@ use crate::services::field::{
use crate::services::group::action::GroupCustomize; use crate::services::group::action::GroupCustomize;
use crate::services::group::configuration::GroupContext; use crate::services::group::configuration::GroupContext;
use crate::services::group::controller::{ use crate::services::group::controller::{
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext, BaseGroupController, GroupController, GroupsBuilder, MoveGroupRowContext,
}; };
use crate::services::group::{move_group_row, GeneratedGroupConfig, GeneratedGroupContext, Group}; use crate::services::group::{move_group_row, GeneratedGroupConfig, GeneratedGroups, Group};
#[derive(Default, Serialize, Deserialize)] #[derive(Default, Serialize, Deserialize)]
pub struct CheckboxGroupConfiguration { pub struct CheckboxGroupConfiguration {
pub hide_empty: bool, pub hide_empty: bool,
} }
pub type CheckboxGroupController = GenericGroupController< pub type CheckboxGroupController = BaseGroupController<
CheckboxGroupConfiguration, CheckboxGroupConfiguration,
CheckboxTypeOption, CheckboxTypeOption,
CheckboxGroupGenerator, CheckboxGroupGenerator,
@ -52,7 +53,7 @@ impl GroupCustomize for CheckboxGroupController {
cell_data: &Self::CellData, cell_data: &Self::CellData,
) -> Vec<GroupRowsNotificationPB> { ) -> Vec<GroupRowsNotificationPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.group_ctx.iter_mut_status_groups(|group| { self.context.iter_mut_status_groups(|group| {
let mut changeset = GroupRowsNotificationPB::new(group.id.clone()); let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
let is_not_contained = !group.contains_row(&row.id); let is_not_contained = !group.contains_row(&row.id);
if group.id == CHECK { if group.id == CHECK {
@ -96,7 +97,7 @@ impl GroupCustomize for CheckboxGroupController {
fn delete_row(&mut self, row: &Row, _cell_data: &Self::CellData) -> Vec<GroupRowsNotificationPB> { fn delete_row(&mut self, row: &Row, _cell_data: &Self::CellData) -> Vec<GroupRowsNotificationPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.group_ctx.iter_mut_groups(|group| { self.context.iter_mut_groups(|group| {
let mut changeset = GroupRowsNotificationPB::new(group.id.clone()); let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
if group.contains_row(&row.id) { if group.contains_row(&row.id) {
changeset.deleted_rows.push(row.id.clone().into_inner()); changeset.deleted_rows.push(row.id.clone().into_inner());
@ -116,7 +117,7 @@ impl GroupCustomize for CheckboxGroupController {
mut context: MoveGroupRowContext, mut context: MoveGroupRowContext,
) -> Vec<GroupRowsNotificationPB> { ) -> Vec<GroupRowsNotificationPB> {
let mut group_changeset = vec![]; let mut group_changeset = vec![];
self.group_ctx.iter_mut_groups(|group| { self.context.iter_mut_groups(|group| {
if let Some(changeset) = move_group_row(group, &mut context) { if let Some(changeset) = move_group_row(group, &mut context) {
group_changeset.push(changeset); group_changeset.push(changeset);
} }
@ -126,8 +127,12 @@ impl GroupCustomize for CheckboxGroupController {
} }
impl GroupController for CheckboxGroupController { impl GroupController for CheckboxGroupController {
fn did_update_field_type_option(&mut self, _field: &Arc<Field>) {
// Do nothing
}
fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str) { fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str) {
match self.group_ctx.get_group(group_id) { match self.context.get_group(group_id) {
None => tracing::warn!("Can not find the group: {}", group_id), None => tracing::warn!("Can not find the group: {}", group_id),
Some((_, group)) => { Some((_, group)) => {
let is_check = group.id == CHECK; let is_check = group.id == CHECK;
@ -138,22 +143,22 @@ impl GroupController for CheckboxGroupController {
} }
fn did_create_row(&mut self, row: &Row, group_id: &str) { fn did_create_row(&mut self, row: &Row, group_id: &str) {
if let Some(group) = self.group_ctx.get_mut_group(group_id) { if let Some(group) = self.context.get_mut_group(group_id) {
group.add_row(row.clone()) group.add_row(row.clone())
} }
} }
} }
pub struct CheckboxGroupGenerator(); pub struct CheckboxGroupGenerator();
impl GroupGenerator for CheckboxGroupGenerator { impl GroupsBuilder for CheckboxGroupGenerator {
type Context = CheckboxGroupContext; type Context = CheckboxGroupContext;
type TypeOptionType = CheckboxTypeOption; type TypeOptionType = CheckboxTypeOption;
fn generate_groups( fn build(
_field: &Field, _field: &Field,
_group_ctx: &Self::Context, _context: &Self::Context,
_type_option: &Option<Self::TypeOptionType>, _type_option: &Option<Self::TypeOptionType>,
) -> GeneratedGroupContext { ) -> GeneratedGroups {
let check_group = GeneratedGroupConfig { let check_group = GeneratedGroupConfig {
group: Group::new(CHECK.to_string(), "".to_string()), group: Group::new(CHECK.to_string(), "".to_string()),
filter_content: CHECK.to_string(), filter_content: CHECK.to_string(),
@ -164,7 +169,7 @@ impl GroupGenerator for CheckboxGroupGenerator {
filter_content: UNCHECK.to_string(), filter_content: UNCHECK.to_string(),
}; };
GeneratedGroupContext { GeneratedGroups {
no_status_group: None, no_status_group: None,
group_configs: vec![check_group, uncheck_group], group_configs: vec![check_group, uncheck_group],
} }

View File

@ -5,11 +5,13 @@ use collab_database::rows::{Cells, Row};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use crate::entities::GroupChangesetPB; use crate::entities::GroupChangesPB;
use crate::services::group::action::{ use crate::services::group::action::{
DidMoveGroupRowResult, DidUpdateGroupRowResult, GroupControllerActions, DidMoveGroupRowResult, DidUpdateGroupRowResult, GroupControllerOperation,
};
use crate::services::group::{
GroupController, GroupData, GroupSettingChangeset, MoveGroupRowContext,
}; };
use crate::services::group::{GroupController, GroupData, MoveGroupRowContext};
/// A [DefaultGroupController] is used to handle the group actions for the [FieldType] that doesn't /// A [DefaultGroupController] is used to handle the group actions for the [FieldType] that doesn't
/// implement its own group controller. The default group controller only contains one group, which /// implement its own group controller. The default group controller only contains one group, which
@ -37,7 +39,7 @@ impl DefaultGroupController {
} }
} }
impl GroupControllerActions for DefaultGroupController { impl GroupControllerOperation for DefaultGroupController {
fn field_id(&self) -> &str { fn field_id(&self) -> &str {
&self.field_id &self.field_id
} }
@ -95,12 +97,23 @@ impl GroupControllerActions for DefaultGroupController {
}) })
} }
fn did_update_group_field(&mut self, _field: &Field) -> FlowyResult<Option<GroupChangesetPB>> { fn did_update_group_field(&mut self, _field: &Field) -> FlowyResult<Option<GroupChangesPB>> {
Ok(None) Ok(None)
} }
fn apply_group_setting_changeset(
&mut self,
_changeset: GroupSettingChangeset,
) -> FlowyResult<()> {
Ok(())
}
} }
impl GroupController for DefaultGroupController { impl GroupController for DefaultGroupController {
fn did_update_field_type_option(&mut self, _field: &Arc<Field>) {
// Do nothing
}
fn will_create_row(&mut self, _cells: &mut Cells, _field: &Field, _group_id: &str) {} fn will_create_row(&mut self, _cells: &mut Cells, _field: &Field, _group_id: &str) {}
fn did_create_row(&mut self, _row: &Row, _group_id: &str) {} fn did_create_row(&mut self, _row: &Row, _group_id: &str) {}

View File

@ -3,14 +3,15 @@ use crate::services::cell::insert_select_option_cell;
use crate::services::field::{MultiSelectTypeOption, SelectOptionCellDataParser}; use crate::services::field::{MultiSelectTypeOption, SelectOptionCellDataParser};
use crate::services::group::action::GroupCustomize; use crate::services::group::action::GroupCustomize;
use crate::services::group::controller::{ use crate::services::group::controller::{
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext, BaseGroupController, GroupController, GroupsBuilder, MoveGroupRowContext,
}; };
use crate::services::group::{ use crate::services::group::{
add_or_remove_select_option_row, generate_select_option_groups, make_no_status_group, add_or_remove_select_option_row, generate_select_option_groups, make_no_status_group,
move_group_row, remove_select_option_row, GeneratedGroupContext, GroupContext, move_group_row, remove_select_option_row, GeneratedGroups, GroupContext,
}; };
use collab_database::fields::Field; use collab_database::fields::Field;
use collab_database::rows::{Cells, Row}; use collab_database::rows::{Cells, Row};
use std::sync::Arc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -21,7 +22,7 @@ pub struct MultiSelectGroupConfiguration {
pub type MultiSelectOptionGroupContext = GroupContext<MultiSelectGroupConfiguration>; pub type MultiSelectOptionGroupContext = GroupContext<MultiSelectGroupConfiguration>;
// MultiSelect // MultiSelect
pub type MultiSelectGroupController = GenericGroupController< pub type MultiSelectGroupController = BaseGroupController<
MultiSelectGroupConfiguration, MultiSelectGroupConfiguration,
MultiSelectTypeOption, MultiSelectTypeOption,
MultiSelectGroupGenerator, MultiSelectGroupGenerator,
@ -44,7 +45,7 @@ impl GroupCustomize for MultiSelectGroupController {
cell_data: &Self::CellData, cell_data: &Self::CellData,
) -> Vec<GroupRowsNotificationPB> { ) -> Vec<GroupRowsNotificationPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.group_ctx.iter_mut_status_groups(|group| { self.context.iter_mut_status_groups(|group| {
if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row) { if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row) {
changesets.push(changeset); changesets.push(changeset);
} }
@ -54,7 +55,7 @@ impl GroupCustomize for MultiSelectGroupController {
fn delete_row(&mut self, row: &Row, cell_data: &Self::CellData) -> Vec<GroupRowsNotificationPB> { fn delete_row(&mut self, row: &Row, cell_data: &Self::CellData) -> Vec<GroupRowsNotificationPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.group_ctx.iter_mut_status_groups(|group| { self.context.iter_mut_status_groups(|group| {
if let Some(changeset) = remove_select_option_row(group, cell_data, row) { if let Some(changeset) = remove_select_option_row(group, cell_data, row) {
changesets.push(changeset); changesets.push(changeset);
} }
@ -68,7 +69,7 @@ impl GroupCustomize for MultiSelectGroupController {
mut context: MoveGroupRowContext, mut context: MoveGroupRowContext,
) -> Vec<GroupRowsNotificationPB> { ) -> Vec<GroupRowsNotificationPB> {
let mut group_changeset = vec![]; let mut group_changeset = vec![];
self.group_ctx.iter_mut_groups(|group| { self.context.iter_mut_groups(|group| {
if let Some(changeset) = move_group_row(group, &mut context) { if let Some(changeset) = move_group_row(group, &mut context) {
group_changeset.push(changeset); group_changeset.push(changeset);
} }
@ -78,8 +79,10 @@ impl GroupCustomize for MultiSelectGroupController {
} }
impl GroupController for MultiSelectGroupController { impl GroupController for MultiSelectGroupController {
fn did_update_field_type_option(&mut self, _field: &Arc<Field>) {}
fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str) { fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str) {
match self.group_ctx.get_group(group_id) { match self.context.get_group(group_id) {
None => tracing::warn!("Can not find the group: {}", group_id), None => tracing::warn!("Can not find the group: {}", group_id),
Some((_, group)) => { Some((_, group)) => {
let cell = insert_select_option_cell(vec![group.id.clone()], field); let cell = insert_select_option_cell(vec![group.id.clone()], field);
@ -89,28 +92,28 @@ impl GroupController for MultiSelectGroupController {
} }
fn did_create_row(&mut self, row: &Row, group_id: &str) { fn did_create_row(&mut self, row: &Row, group_id: &str) {
if let Some(group) = self.group_ctx.get_mut_group(group_id) { if let Some(group) = self.context.get_mut_group(group_id) {
group.add_row(row.clone()) group.add_row(row.clone())
} }
} }
} }
pub struct MultiSelectGroupGenerator(); pub struct MultiSelectGroupGenerator;
impl GroupGenerator for MultiSelectGroupGenerator { impl GroupsBuilder for MultiSelectGroupGenerator {
type Context = MultiSelectOptionGroupContext; type Context = MultiSelectOptionGroupContext;
type TypeOptionType = MultiSelectTypeOption; type TypeOptionType = MultiSelectTypeOption;
fn generate_groups( fn build(
field: &Field, field: &Field,
_group_ctx: &Self::Context, _context: &Self::Context,
type_option: &Option<Self::TypeOptionType>, type_option: &Option<Self::TypeOptionType>,
) -> GeneratedGroupContext { ) -> GeneratedGroups {
let group_configs = match type_option { let group_configs = match type_option {
None => vec![], None => vec![],
Some(type_option) => generate_select_option_groups(&field.id, &type_option.options), Some(type_option) => generate_select_option_groups(&field.id, &type_option.options),
}; };
GeneratedGroupContext { GeneratedGroups {
no_status_group: Some(make_no_status_group(field)), no_status_group: Some(make_no_status_group(field)),
group_configs, group_configs,
} }

View File

@ -4,13 +4,14 @@ use crate::services::field::{SelectOptionCellDataParser, SingleSelectTypeOption}
use crate::services::group::action::GroupCustomize; use crate::services::group::action::GroupCustomize;
use collab_database::fields::Field; use collab_database::fields::Field;
use collab_database::rows::{Cells, Row}; use collab_database::rows::{Cells, Row};
use std::sync::Arc;
use crate::services::group::controller::{ use crate::services::group::controller::{
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext, BaseGroupController, GroupController, GroupsBuilder, MoveGroupRowContext,
}; };
use crate::services::group::controller_impls::select_option_controller::util::*; use crate::services::group::controller_impls::select_option_controller::util::*;
use crate::services::group::entities::GroupData; use crate::services::group::entities::GroupData;
use crate::services::group::{make_no_status_group, GeneratedGroupContext, GroupContext}; use crate::services::group::{make_no_status_group, GeneratedGroups, GroupContext};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -22,7 +23,7 @@ pub struct SingleSelectGroupConfiguration {
pub type SingleSelectOptionGroupContext = GroupContext<SingleSelectGroupConfiguration>; pub type SingleSelectOptionGroupContext = GroupContext<SingleSelectGroupConfiguration>;
// SingleSelect // SingleSelect
pub type SingleSelectGroupController = GenericGroupController< pub type SingleSelectGroupController = BaseGroupController<
SingleSelectGroupConfiguration, SingleSelectGroupConfiguration,
SingleSelectTypeOption, SingleSelectTypeOption,
SingleSelectGroupGenerator, SingleSelectGroupGenerator,
@ -44,7 +45,7 @@ impl GroupCustomize for SingleSelectGroupController {
cell_data: &Self::CellData, cell_data: &Self::CellData,
) -> Vec<GroupRowsNotificationPB> { ) -> Vec<GroupRowsNotificationPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.group_ctx.iter_mut_status_groups(|group| { self.context.iter_mut_status_groups(|group| {
if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row) { if let Some(changeset) = add_or_remove_select_option_row(group, cell_data, row) {
changesets.push(changeset); changesets.push(changeset);
} }
@ -54,7 +55,7 @@ impl GroupCustomize for SingleSelectGroupController {
fn delete_row(&mut self, row: &Row, cell_data: &Self::CellData) -> Vec<GroupRowsNotificationPB> { fn delete_row(&mut self, row: &Row, cell_data: &Self::CellData) -> Vec<GroupRowsNotificationPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.group_ctx.iter_mut_status_groups(|group| { self.context.iter_mut_status_groups(|group| {
if let Some(changeset) = remove_select_option_row(group, cell_data, row) { if let Some(changeset) = remove_select_option_row(group, cell_data, row) {
changesets.push(changeset); changesets.push(changeset);
} }
@ -68,7 +69,7 @@ impl GroupCustomize for SingleSelectGroupController {
mut context: MoveGroupRowContext, mut context: MoveGroupRowContext,
) -> Vec<GroupRowsNotificationPB> { ) -> Vec<GroupRowsNotificationPB> {
let mut group_changeset = vec![]; let mut group_changeset = vec![];
self.group_ctx.iter_mut_groups(|group| { self.context.iter_mut_groups(|group| {
if let Some(changeset) = move_group_row(group, &mut context) { if let Some(changeset) = move_group_row(group, &mut context) {
group_changeset.push(changeset); group_changeset.push(changeset);
} }
@ -78,8 +79,10 @@ impl GroupCustomize for SingleSelectGroupController {
} }
impl GroupController for SingleSelectGroupController { impl GroupController for SingleSelectGroupController {
fn did_update_field_type_option(&mut self, _field: &Arc<Field>) {}
fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str) { fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str) {
let group: Option<&mut GroupData> = self.group_ctx.get_mut_group(group_id); let group: Option<&mut GroupData> = self.context.get_mut_group(group_id);
match group { match group {
None => {}, None => {},
Some(group) => { Some(group) => {
@ -89,27 +92,27 @@ impl GroupController for SingleSelectGroupController {
} }
} }
fn did_create_row(&mut self, row: &Row, group_id: &str) { fn did_create_row(&mut self, row: &Row, group_id: &str) {
if let Some(group) = self.group_ctx.get_mut_group(group_id) { if let Some(group) = self.context.get_mut_group(group_id) {
group.add_row(row.clone()) group.add_row(row.clone())
} }
} }
} }
pub struct SingleSelectGroupGenerator(); pub struct SingleSelectGroupGenerator();
impl GroupGenerator for SingleSelectGroupGenerator { impl GroupsBuilder for SingleSelectGroupGenerator {
type Context = SingleSelectOptionGroupContext; type Context = SingleSelectOptionGroupContext;
type TypeOptionType = SingleSelectTypeOption; type TypeOptionType = SingleSelectTypeOption;
fn generate_groups( fn build(
field: &Field, field: &Field,
_group_ctx: &Self::Context, _context: &Self::Context,
type_option: &Option<Self::TypeOptionType>, type_option: &Option<Self::TypeOptionType>,
) -> GeneratedGroupContext { ) -> GeneratedGroups {
let group_configs = match type_option { let group_configs = match type_option {
None => vec![], None => vec![],
Some(type_option) => generate_select_option_groups(&field.id, &type_option.options), Some(type_option) => generate_select_option_groups(&field.id, &type_option.options),
}; };
GeneratedGroupContext { GeneratedGroups {
no_status_group: Some(make_no_status_group(field)), no_status_group: Some(make_no_status_group(field)),
group_configs, group_configs,
} }

View File

@ -1,6 +1,7 @@
use collab_database::fields::Field; use collab_database::fields::Field;
use collab_database::rows::{new_cell_builder, Cell, Cells, Row}; use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc;
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
@ -12,10 +13,10 @@ use crate::services::field::{URLCellData, URLCellDataParser, URLTypeOption};
use crate::services::group::action::GroupCustomize; use crate::services::group::action::GroupCustomize;
use crate::services::group::configuration::GroupContext; use crate::services::group::configuration::GroupContext;
use crate::services::group::controller::{ use crate::services::group::controller::{
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext, BaseGroupController, GroupController, GroupsBuilder, MoveGroupRowContext,
}; };
use crate::services::group::{ use crate::services::group::{
make_no_status_group, move_group_row, GeneratedGroupConfig, GeneratedGroupContext, Group, make_no_status_group, move_group_row, GeneratedGroupConfig, GeneratedGroups, Group,
}; };
#[derive(Default, Serialize, Deserialize)] #[derive(Default, Serialize, Deserialize)]
@ -23,12 +24,8 @@ pub struct URLGroupConfiguration {
pub hide_empty: bool, pub hide_empty: bool,
} }
pub type URLGroupController = GenericGroupController< pub type URLGroupController =
URLGroupConfiguration, BaseGroupController<URLGroupConfiguration, URLTypeOption, URLGroupGenerator, URLCellDataParser>;
URLTypeOption,
URLGroupGenerator,
URLCellDataParser,
>;
pub type URLGroupContext = GroupContext<URLGroupConfiguration>; pub type URLGroupContext = GroupContext<URLGroupConfiguration>;
@ -55,17 +52,17 @@ impl GroupCustomize for URLGroupController {
) -> FlowyResult<(Option<InsertedGroupPB>, Option<GroupPB>)> { ) -> FlowyResult<(Option<InsertedGroupPB>, Option<GroupPB>)> {
// Just return if the group with this url already exists // Just return if the group with this url already exists
let mut inserted_group = None; let mut inserted_group = None;
if self.group_ctx.get_group(&_cell_data.url).is_none() { if self.context.get_group(&_cell_data.url).is_none() {
let cell_data: URLCellData = _cell_data.clone().into(); let cell_data: URLCellData = _cell_data.clone().into();
let group = make_group_from_url_cell(&cell_data); let group = make_group_from_url_cell(&cell_data);
let mut new_group = self.group_ctx.add_new_group(group)?; let mut new_group = self.context.add_new_group(group)?;
new_group.group.rows.push(RowPB::from(row)); new_group.group.rows.push(RowPB::from(row));
inserted_group = Some(new_group); inserted_group = Some(new_group);
} }
// Delete the old url group if there are no rows in that group // Delete the old url group if there are no rows in that group
let deleted_group = match _old_cell_data let deleted_group = match _old_cell_data
.and_then(|old_cell_data| self.group_ctx.get_group(&old_cell_data.content)) .and_then(|old_cell_data| self.context.get_group(&old_cell_data.content))
{ {
None => None, None => None,
Some((_, group)) => { Some((_, group)) => {
@ -80,7 +77,7 @@ impl GroupCustomize for URLGroupController {
let deleted_group = match deleted_group { let deleted_group = match deleted_group {
None => None, None => None,
Some(group) => { Some(group) => {
self.group_ctx.delete_group(&group.id)?; self.context.delete_group(&group.id)?;
Some(GroupPB::from(group.clone())) Some(GroupPB::from(group.clone()))
}, },
}; };
@ -94,7 +91,7 @@ impl GroupCustomize for URLGroupController {
cell_data: &Self::CellData, cell_data: &Self::CellData,
) -> Vec<GroupRowsNotificationPB> { ) -> Vec<GroupRowsNotificationPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.group_ctx.iter_mut_status_groups(|group| { self.context.iter_mut_status_groups(|group| {
let mut changeset = GroupRowsNotificationPB::new(group.id.clone()); let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
if group.id == cell_data.content { if group.id == cell_data.content {
if !group.contains_row(&row.id) { if !group.contains_row(&row.id) {
@ -117,7 +114,7 @@ impl GroupCustomize for URLGroupController {
fn delete_row(&mut self, row: &Row, _cell_data: &Self::CellData) -> Vec<GroupRowsNotificationPB> { fn delete_row(&mut self, row: &Row, _cell_data: &Self::CellData) -> Vec<GroupRowsNotificationPB> {
let mut changesets = vec![]; let mut changesets = vec![];
self.group_ctx.iter_mut_groups(|group| { self.context.iter_mut_groups(|group| {
let mut changeset = GroupRowsNotificationPB::new(group.id.clone()); let mut changeset = GroupRowsNotificationPB::new(group.id.clone());
if group.contains_row(&row.id) { if group.contains_row(&row.id) {
group.remove_row(&row.id); group.remove_row(&row.id);
@ -137,7 +134,7 @@ impl GroupCustomize for URLGroupController {
mut context: MoveGroupRowContext, mut context: MoveGroupRowContext,
) -> Vec<GroupRowsNotificationPB> { ) -> Vec<GroupRowsNotificationPB> {
let mut group_changeset = vec![]; let mut group_changeset = vec![];
self.group_ctx.iter_mut_groups(|group| { self.context.iter_mut_groups(|group| {
if let Some(changeset) = move_group_row(group, &mut context) { if let Some(changeset) = move_group_row(group, &mut context) {
group_changeset.push(changeset); group_changeset.push(changeset);
} }
@ -151,14 +148,14 @@ impl GroupCustomize for URLGroupController {
_cell_data: &Self::CellData, _cell_data: &Self::CellData,
) -> Option<GroupPB> { ) -> Option<GroupPB> {
let mut deleted_group = None; let mut deleted_group = None;
if let Some((_, group)) = self.group_ctx.get_group(&_cell_data.content) { if let Some((_, group)) = self.context.get_group(&_cell_data.content) {
if group.rows.len() == 1 { if group.rows.len() == 1 {
deleted_group = Some(GroupPB::from(group.clone())); deleted_group = Some(GroupPB::from(group.clone()));
} }
} }
if deleted_group.is_some() { if deleted_group.is_some() {
let _ = self let _ = self
.group_ctx .context
.delete_group(&deleted_group.as_ref().unwrap().group_id); .delete_group(&deleted_group.as_ref().unwrap().group_id);
} }
deleted_group deleted_group
@ -166,8 +163,10 @@ impl GroupCustomize for URLGroupController {
} }
impl GroupController for URLGroupController { impl GroupController for URLGroupController {
fn did_update_field_type_option(&mut self, _field: &Arc<Field>) {}
fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str) { fn will_create_row(&mut self, cells: &mut Cells, field: &Field, group_id: &str) {
match self.group_ctx.get_group(group_id) { match self.context.get_group(group_id) {
None => tracing::warn!("Can not find the group: {}", group_id), None => tracing::warn!("Can not find the group: {}", group_id),
Some((_, group)) => { Some((_, group)) => {
let cell = insert_url_cell(group.id.clone(), field); let cell = insert_url_cell(group.id.clone(), field);
@ -177,24 +176,24 @@ impl GroupController for URLGroupController {
} }
fn did_create_row(&mut self, row: &Row, group_id: &str) { fn did_create_row(&mut self, row: &Row, group_id: &str) {
if let Some(group) = self.group_ctx.get_mut_group(group_id) { if let Some(group) = self.context.get_mut_group(group_id) {
group.add_row(row.clone()) group.add_row(row.clone())
} }
} }
} }
pub struct URLGroupGenerator(); pub struct URLGroupGenerator();
impl GroupGenerator for URLGroupGenerator { impl GroupsBuilder for URLGroupGenerator {
type Context = URLGroupContext; type Context = URLGroupContext;
type TypeOptionType = URLTypeOption; type TypeOptionType = URLTypeOption;
fn generate_groups( fn build(
field: &Field, field: &Field,
group_ctx: &Self::Context, context: &Self::Context,
_type_option: &Option<Self::TypeOptionType>, _type_option: &Option<Self::TypeOptionType>,
) -> GeneratedGroupContext { ) -> GeneratedGroups {
// Read all the cells for the grouping field // Read all the cells for the grouping field
let cells = futures::executor::block_on(group_ctx.get_all_cells()); let cells = futures::executor::block_on(context.get_all_cells());
// Generate the groups // Generate the groups
let group_configs = cells let group_configs = cells
@ -208,7 +207,7 @@ impl GroupGenerator for URLGroupGenerator {
.collect(); .collect();
let no_status_group = Some(make_no_status_group(field)); let no_status_group = Some(make_no_status_group(field));
GeneratedGroupContext { GeneratedGroups {
no_status_group, no_status_group,
group_configs, group_configs,
} }

View File

@ -14,6 +14,16 @@ pub struct GroupSetting {
pub content: String, pub content: String,
} }
pub struct GroupSettingChangeset {
pub update_groups: Vec<GroupChangeset>,
}
pub struct GroupChangeset {
pub group_id: String,
pub name: Option<String>,
pub visible: Option<bool>,
}
impl GroupSetting { impl GroupSetting {
pub fn new(field_id: String, field_type: i64, content: String) -> Self { pub fn new(field_id: String, field_type: i64, content: String) -> Self {
Self { Self {
@ -75,7 +85,7 @@ impl From<GroupSetting> for GroupSettingMap {
pub struct Group { pub struct Group {
pub id: String, pub id: String,
pub name: String, pub name: String,
#[serde(default = "GROUP_REV_VISIBILITY")] #[serde(default = "GROUP_VISIBILITY")]
pub visible: bool, pub visible: bool,
} }
@ -104,7 +114,7 @@ impl From<Group> for GroupMap {
} }
} }
const GROUP_REV_VISIBILITY: fn() -> bool = || true; const GROUP_VISIBILITY: fn() -> bool = || true;
impl Group { impl Group {
pub fn new(id: String, name: String) -> Self { pub fn new(id: String, name: String) -> Self {

View File

@ -42,7 +42,7 @@ where
W: GroupSettingWriter, W: GroupSettingWriter,
{ {
let grouping_field_type = FieldType::from(grouping_field.field_type); let grouping_field_type = FieldType::from(grouping_field.field_type);
tracing::Span::current().record("grouping_field_type", &grouping_field_type.default_name()); tracing::Span::current().record("grouping_field", &grouping_field_type.default_name());
let mut group_controller: Box<dyn GroupController>; let mut group_controller: Box<dyn GroupController>;
let configuration_reader = Arc::new(setting_reader); let configuration_reader = Arc::new(setting_reader);

View File

@ -82,7 +82,9 @@ impl SortController {
pub async fn did_receive_row_changed(&self, row_id: RowId) { pub async fn did_receive_row_changed(&self, row_id: RowId) {
let task_type = SortEvent::RowDidChanged(row_id); let task_type = SortEvent::RowDidChanged(row_id);
self.gen_task(task_type, QualityOfService::Background).await; if !self.sorts.is_empty() {
self.gen_task(task_type, QualityOfService::Background).await;
}
} }
// #[tracing::instrument(name = "process_sort_task", level = "trace", skip_all, err)] // #[tracing::instrument(name = "process_sort_task", level = "trace", skip_all, err)]
@ -169,7 +171,7 @@ impl SortController {
.await; .await;
} }
pub async fn did_update_view_field_type_option(&self, _field_rev: &Field) { pub async fn did_update_field_type_option(&self, _field: &Field) {
// //
} }

View File

@ -10,7 +10,7 @@ use collab_database::rows::{Row, RowId};
use futures::TryFutureExt; use futures::TryFutureExt;
use tokio::sync::broadcast::Receiver; use tokio::sync::broadcast::Receiver;
use flowy_database2::entities::{AlterFilterParams, AlterFilterPayloadPB, CheckboxFilterConditionPB, CheckboxFilterPB, ChecklistFilterConditionPB, ChecklistFilterPB, DatabaseViewSettingPB, DateFilterConditionPB, DateFilterPB, DeleteFilterParams, FieldType, FilterPB, NumberFilterConditionPB, NumberFilterPB, SelectOptionConditionPB, SelectOptionFilterPB, TextFilterConditionPB, TextFilterPB}; use flowy_database2::entities::{UpdateFilterParams, UpdateFilterPayloadPB, CheckboxFilterConditionPB, CheckboxFilterPB, ChecklistFilterConditionPB, ChecklistFilterPB, DatabaseViewSettingPB, DateFilterConditionPB, DateFilterPB, DeleteFilterParams, FieldType, FilterPB, NumberFilterConditionPB, NumberFilterPB, SelectOptionConditionPB, SelectOptionFilterPB, TextFilterConditionPB, TextFilterPB};
use flowy_database2::services::database_view::DatabaseViewChanged; use flowy_database2::services::database_view::DatabaseViewChanged;
use flowy_database2::services::filter::FilterType; use flowy_database2::services::filter::FilterType;
@ -33,7 +33,7 @@ pub enum FilterScript {
changed: Option<FilterRowChanged>, changed: Option<FilterRowChanged>,
}, },
InsertFilter { InsertFilter {
payload: AlterFilterPayloadPB, payload: UpdateFilterPayloadPB,
}, },
CreateTextFilter { CreateTextFilter {
condition: TextFilterConditionPB, condition: TextFilterConditionPB,
@ -151,7 +151,7 @@ impl DatabaseFilterTest {
content content
}; };
let payload = let payload =
AlterFilterPayloadPB::new( UpdateFilterPayloadPB::new(
& self.view_id(), & self.view_id(),
&field, text_filter); &field, text_filter);
self.insert_filter(payload).await; self.insert_filter(payload).await;
@ -159,7 +159,7 @@ impl DatabaseFilterTest {
FilterScript::UpdateTextFilter { filter, condition, content, changed} => { FilterScript::UpdateTextFilter { filter, condition, content, changed} => {
self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap()); self.recv = Some(self.editor.subscribe_view_changed(&self.view_id()).await.unwrap());
self.assert_future_changed(changed).await; self.assert_future_changed(changed).await;
let params = AlterFilterParams { let params = UpdateFilterParams {
view_id: self.view_id(), view_id: self.view_id(),
field_id: filter.field_id, field_id: filter.field_id,
filter_id: Some(filter.id), filter_id: Some(filter.id),
@ -178,7 +178,7 @@ impl DatabaseFilterTest {
content content
}; };
let payload = let payload =
AlterFilterPayloadPB::new( UpdateFilterPayloadPB::new(
&self.view_id(), &self.view_id(),
&field, number_filter); &field, number_filter);
self.insert_filter(payload).await; self.insert_filter(payload).await;
@ -191,7 +191,7 @@ impl DatabaseFilterTest {
condition condition
}; };
let payload = let payload =
AlterFilterPayloadPB::new(& self.view_id(), &field, checkbox_filter); UpdateFilterPayloadPB::new(& self.view_id(), &field, checkbox_filter);
self.insert_filter(payload).await; self.insert_filter(payload).await;
} }
FilterScript::CreateDateFilter { condition, start, end, timestamp, changed} => { FilterScript::CreateDateFilter { condition, start, end, timestamp, changed} => {
@ -206,7 +206,7 @@ impl DatabaseFilterTest {
}; };
let payload = let payload =
AlterFilterPayloadPB::new(&self.view_id(), &field, date_filter); UpdateFilterPayloadPB::new(&self.view_id(), &field, date_filter);
self.insert_filter(payload).await; self.insert_filter(payload).await;
} }
FilterScript::CreateMultiSelectFilter { condition, option_ids} => { FilterScript::CreateMultiSelectFilter { condition, option_ids} => {
@ -214,7 +214,7 @@ impl DatabaseFilterTest {
let field = self.get_first_field(FieldType::MultiSelect); let field = self.get_first_field(FieldType::MultiSelect);
let filter = SelectOptionFilterPB { condition, option_ids }; let filter = SelectOptionFilterPB { condition, option_ids };
let payload = let payload =
AlterFilterPayloadPB::new(&self.view_id(), &field, filter); UpdateFilterPayloadPB::new(&self.view_id(), &field, filter);
self.insert_filter(payload).await; self.insert_filter(payload).await;
} }
FilterScript::CreateSingleSelectFilter { condition, option_ids, changed} => { FilterScript::CreateSingleSelectFilter { condition, option_ids, changed} => {
@ -223,7 +223,7 @@ impl DatabaseFilterTest {
let field = self.get_first_field(FieldType::SingleSelect); let field = self.get_first_field(FieldType::SingleSelect);
let filter = SelectOptionFilterPB { condition, option_ids }; let filter = SelectOptionFilterPB { condition, option_ids };
let payload = let payload =
AlterFilterPayloadPB::new(& self.view_id(), &field, filter); UpdateFilterPayloadPB::new(& self.view_id(), &field, filter);
self.insert_filter(payload).await; self.insert_filter(payload).await;
} }
FilterScript::CreateChecklistFilter { condition,changed} => { FilterScript::CreateChecklistFilter { condition,changed} => {
@ -233,7 +233,7 @@ impl DatabaseFilterTest {
// let type_option = self.get_checklist_type_option(&field_rev.id); // let type_option = self.get_checklist_type_option(&field_rev.id);
let filter = ChecklistFilterPB { condition }; let filter = ChecklistFilterPB { condition };
let payload = let payload =
AlterFilterPayloadPB::new(& self.view_id(), &field, filter); UpdateFilterPayloadPB::new(& self.view_id(), &field, filter);
self.insert_filter(payload).await; self.insert_filter(payload).await;
} }
FilterScript::AssertFilterCount { count } => { FilterScript::AssertFilterCount { count } => {
@ -289,8 +289,8 @@ impl DatabaseFilterTest {
} }
async fn insert_filter(&self, payload: AlterFilterPayloadPB) { async fn insert_filter(&self, payload: UpdateFilterPayloadPB) {
let params: AlterFilterParams = payload.try_into().unwrap(); let params: UpdateFilterParams = payload.try_into().unwrap();
let _ = self.editor.create_or_update_filter(params).await.unwrap(); let _ = self.editor.create_or_update_filter(params).await.unwrap();
} }

View File

@ -1,7 +1,7 @@
use crate::database::filter_test::script::FilterScript::*; use crate::database::filter_test::script::FilterScript::*;
use crate::database::filter_test::script::*; use crate::database::filter_test::script::*;
use flowy_database2::entities::{ use flowy_database2::entities::{
AlterFilterPayloadPB, FieldType, TextFilterConditionPB, TextFilterPB, FieldType, TextFilterConditionPB, TextFilterPB, UpdateFilterPayloadPB,
}; };
use flowy_database2::services::filter::FilterType; use flowy_database2::services::filter::FilterType;
@ -195,7 +195,7 @@ async fn grid_filter_delete_test() {
condition: TextFilterConditionPB::TextIsEmpty, condition: TextFilterConditionPB::TextIsEmpty,
content: "".to_string(), content: "".to_string(),
}; };
let payload = AlterFilterPayloadPB::new(&test.view_id(), &field, text_filter); let payload = UpdateFilterPayloadPB::new(&test.view_id(), &field, text_filter);
let scripts = vec![ let scripts = vec![
InsertFilter { payload }, InsertFilter { payload },
AssertFilterCount { count: 1 }, AssertFilterCount { count: 1 },

View File

@ -8,7 +8,7 @@ use collab_database::rows::RowId;
use futures::stream::StreamExt; use futures::stream::StreamExt;
use tokio::sync::broadcast::Receiver; use tokio::sync::broadcast::Receiver;
use flowy_database2::entities::{AlterSortParams, DeleteSortParams, FieldType}; use flowy_database2::entities::{DeleteSortParams, FieldType, UpdateSortParams};
use flowy_database2::services::cell::stringify_cell_data; use flowy_database2::services::cell::stringify_cell_data;
use flowy_database2::services::database_view::DatabaseViewChanged; use flowy_database2::services::database_view::DatabaseViewChanged;
use flowy_database2::services::sort::{Sort, SortCondition, SortType}; use flowy_database2::services::sort::{Sort, SortCondition, SortType};
@ -72,7 +72,7 @@ impl DatabaseSortTest {
.await .await
.unwrap(), .unwrap(),
); );
let params = AlterSortParams { let params = UpdateSortParams {
view_id: self.view_id.clone(), view_id: self.view_id.clone(),
field_id: field.id.clone(), field_id: field.id.clone(),
sort_id: None, sort_id: None,

View File

@ -13,7 +13,7 @@ const MESSAGE: &str = "msg";
const LOG_MODULE_PATH: &str = "log.module_path"; const LOG_MODULE_PATH: &str = "log.module_path";
const LOG_TARGET_PATH: &str = "log.target"; const LOG_TARGET_PATH: &str = "log.target";
const FLOWY_RESERVED_FIELDS: [&str; 3] = [LEVEL, TIME, MESSAGE]; const RESERVED_FIELDS: [&str; 3] = [LEVEL, TIME, MESSAGE];
const IGNORE_FIELDS: [&str; 2] = [LOG_MODULE_PATH, LOG_TARGET_PATH]; const IGNORE_FIELDS: [&str; 2] = [LOG_MODULE_PATH, LOG_TARGET_PATH];
pub struct FlowyFormattingLayer<W: MakeWriter + 'static> { pub struct FlowyFormattingLayer<W: MakeWriter + 'static> {
@ -29,7 +29,7 @@ impl<W: MakeWriter + 'static> FlowyFormattingLayer<W> {
} }
} }
fn serialize_flowy_folder_fields( fn serialize_fields(
&self, &self,
map_serializer: &mut impl SerializeMap<Error = serde_json::Error>, map_serializer: &mut impl SerializeMap<Error = serde_json::Error>,
message: &str, message: &str,
@ -45,12 +45,13 @@ impl<W: MakeWriter + 'static> FlowyFormattingLayer<W> {
&self, &self,
span: &SpanRef<S>, span: &SpanRef<S>,
ty: Type, ty: Type,
ctx: &Context<'_, S>,
) -> Result<Vec<u8>, std::io::Error> { ) -> Result<Vec<u8>, std::io::Error> {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
let mut serializer = serde_json::Serializer::new(&mut buffer); let mut serializer = serde_json::Serializer::new(&mut buffer);
let mut map_serializer = serializer.serialize_map(None)?; let mut map_serializer = serializer.serialize_map(None)?;
let message = format_span_context(span, ty); let message = format_span_context(span, ty, ctx);
self.serialize_flowy_folder_fields(&mut map_serializer, &message, span.metadata().level())?; self.serialize_fields(&mut map_serializer, &message, span.metadata().level())?;
if self.with_target { if self.with_target {
map_serializer.serialize_entry("target", &span.metadata().target())?; map_serializer.serialize_entry("target", &span.metadata().target())?;
} }
@ -61,7 +62,7 @@ impl<W: MakeWriter + 'static> FlowyFormattingLayer<W> {
let extensions = span.extensions(); let extensions = span.extensions();
if let Some(visitor) = extensions.get::<JsonStorage>() { if let Some(visitor) = extensions.get::<JsonStorage>() {
for (key, value) in visitor.values() { for (key, value) in visitor.values() {
if !FLOWY_RESERVED_FIELDS.contains(key) && !IGNORE_FIELDS.contains(key) { if !RESERVED_FIELDS.contains(key) && !IGNORE_FIELDS.contains(key) {
map_serializer.serialize_entry(key, value)?; map_serializer.serialize_entry(key, value)?;
} else { } else {
tracing::debug!( tracing::debug!(
@ -93,9 +94,9 @@ pub enum Type {
impl fmt::Display for Type { impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let repr = match self { let repr = match self {
Type::EnterSpan => "START", Type::EnterSpan => "Start",
Type::ExitSpan => "END", Type::ExitSpan => "End",
Type::Event => "EVENT", Type::Event => "Event",
}; };
write!(f, "{}", repr) write!(f, "{}", repr)
} }
@ -104,14 +105,27 @@ impl fmt::Display for Type {
fn format_span_context<S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>>( fn format_span_context<S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>>(
span: &SpanRef<S>, span: &SpanRef<S>,
ty: Type, ty: Type,
context: &Context<'_, S>,
) -> String { ) -> String {
format!("[⛳ {} - {}]", span.metadata().name().to_uppercase(), ty) match context.lookup_current() {
None => {
if matches!(ty, Type::EnterSpan) {
format!("[🟢 {} - {}]", span.metadata().name().to_uppercase(), ty)
} else {
format!("[🔵 {} - {}]", span.metadata().name().to_uppercase(), ty)
}
},
Some(_) => {
format!("[{} - {}]", span.metadata().name().to_uppercase(), ty)
},
}
} }
fn format_event_message<S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>>( fn format_event_message<S: Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>>(
current_span: &Option<SpanRef<S>>, current_span: &Option<SpanRef<S>>,
event: &Event, event: &Event,
event_visitor: &JsonStorage<'_>, event_visitor: &JsonStorage<'_>,
context: &Context<'_, S>,
) -> String { ) -> String {
// Extract the "message" field, if provided. Fallback to the target, if missing. // Extract the "message" field, if provided. Fallback to the target, if missing.
let mut message = event_visitor let mut message = event_visitor
@ -127,7 +141,11 @@ fn format_event_message<S: Subscriber + for<'a> tracing_subscriber::registry::Lo
// If the event is in the context of a span, prepend the span name to the // If the event is in the context of a span, prepend the span name to the
// message. // message.
if let Some(span) = &current_span { if let Some(span) = &current_span {
message = format!("{} {}", format_span_context(span, Type::Event), message); message = format!(
"{} {}",
format_span_context(span, Type::Event, context),
message
);
} }
message message
@ -154,12 +172,8 @@ where
let mut serializer = serde_json::Serializer::new(&mut buffer); let mut serializer = serde_json::Serializer::new(&mut buffer);
let mut map_serializer = serializer.serialize_map(None)?; let mut map_serializer = serializer.serialize_map(None)?;
let message = format_event_message(&current_span, event, &event_visitor); let message = format_event_message(&current_span, event, &event_visitor, &ctx);
self.serialize_flowy_folder_fields( self.serialize_fields(&mut map_serializer, &message, event.metadata().level())?;
&mut map_serializer,
&message,
event.metadata().level(),
)?;
// Additional metadata useful for debugging // Additional metadata useful for debugging
// They should be nested under `src` (see https://github.com/trentm/node-bunyan#src ) // They should be nested under `src` (see https://github.com/trentm/node-bunyan#src )
// but `tracing` does not support nested values yet // but `tracing` does not support nested values yet
@ -174,7 +188,7 @@ where
// Add all the other fields associated with the event, expect the message we // Add all the other fields associated with the event, expect the message we
// already used. // already used.
for (key, value) in event_visitor.values().iter().filter(|(&key, _)| { for (key, value) in event_visitor.values().iter().filter(|(&key, _)| {
key != "message" && !FLOWY_RESERVED_FIELDS.contains(&key) && !IGNORE_FIELDS.contains(&key) key != "message" && !RESERVED_FIELDS.contains(&key) && !IGNORE_FIELDS.contains(&key)
}) { }) {
map_serializer.serialize_entry(key, value)?; map_serializer.serialize_entry(key, value)?;
} }
@ -184,7 +198,7 @@ where
let extensions = span.extensions(); let extensions = span.extensions();
if let Some(visitor) = extensions.get::<JsonStorage>() { if let Some(visitor) = extensions.get::<JsonStorage>() {
for (key, value) in visitor.values() { for (key, value) in visitor.values() {
if !FLOWY_RESERVED_FIELDS.contains(key) && !IGNORE_FIELDS.contains(key) { if !RESERVED_FIELDS.contains(key) && !IGNORE_FIELDS.contains(key) {
map_serializer.serialize_entry(key, value)?; map_serializer.serialize_entry(key, value)?;
} else { } else {
tracing::debug!( tracing::debug!(
@ -207,14 +221,14 @@ where
fn new_span(&self, _attrs: &Attributes, id: &Id, ctx: Context<'_, S>) { fn new_span(&self, _attrs: &Attributes, id: &Id, ctx: Context<'_, S>) {
let span = ctx.span(id).expect("Span not found, this is a bug"); let span = ctx.span(id).expect("Span not found, this is a bug");
if let Ok(serialized) = self.serialize_span(&span, Type::EnterSpan) { if let Ok(serialized) = self.serialize_span(&span, Type::EnterSpan, &ctx) {
let _ = self.emit(serialized); let _ = self.emit(serialized);
} }
} }
fn on_close(&self, id: Id, ctx: Context<'_, S>) { fn on_close(&self, id: Id, ctx: Context<'_, S>) {
let span = ctx.span(&id).expect("Span not found, this is a bug"); let span = ctx.span(&id).expect("Span not found, this is a bug");
if let Ok(serialized) = self.serialize_span(&span, Type::ExitSpan) { if let Ok(serialized) = self.serialize_span(&span, Type::ExitSpan, &ctx) {
let _ = self.emit(serialized); let _ = self.emit(serialized);
} }
} }

View File

@ -42,30 +42,20 @@ impl Builder {
let (non_blocking, guard) = tracing_appender::non_blocking(self.file_appender); let (non_blocking, guard) = tracing_appender::non_blocking(self.file_appender);
let subscriber = tracing_subscriber::fmt() let subscriber = tracing_subscriber::fmt()
// .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE) .with_ansi(true)
.with_ansi(false) .with_target(false)
.with_target(false) .with_max_level(tracing::Level::TRACE)
.with_max_level(tracing::Level::TRACE) .with_writer(std::io::stderr)
.with_writer(std::io::stderr) .with_thread_ids(true)
.with_thread_ids(true) .json()
// .with_writer(non_blocking) // .with_current_span(true)
.json() // .with_span_list(true)
.with_current_span(true) .compact()
.with_span_list(true) .finish()
.compact() .with(env_filter)
.finish() .with(JsonStorageLayer)
.with(env_filter) .with(FlowyFormattingLayer::new(std::io::stdout))
.with(JsonStorageLayer) .with(FlowyFormattingLayer::new(non_blocking));
.with(FlowyFormattingLayer::new(std::io::stdout))
.with(FlowyFormattingLayer::new(non_blocking));
// if cfg!(feature = "use_bunyan") {
// let formatting_layer = BunyanFormattingLayer::new(self.name.clone(),
// std::io::stdout); let _ =
// set_global_default(subscriber.with(JsonStorageLayer).with(formatting_layer)).
// map_err(|e| format!("{:?}", e))?; } else {
// let _ = set_global_default(subscriber).map_err(|e| format!("{:?}", e))?;
// }
set_global_default(subscriber).map_err(|e| format!("{:?}", e))?; set_global_default(subscriber).map_err(|e| format!("{:?}", e))?;
LogTracer::builder() LogTracer::builder()