mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: config notification of grid
This commit is contained in:
parent
8c148e3b67
commit
1237962ab2
@ -4,7 +4,9 @@ import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
|
||||
// User
|
||||
typedef UserNotificationCallback = void Function(UserNotification, Either<Uint8List, FlowyError>);
|
||||
|
||||
class UserNotificationParser extends NotificationParser<UserNotification, FlowyError> {
|
||||
@ -17,10 +19,11 @@ class UserNotificationParser extends NotificationParser<UserNotification, FlowyE
|
||||
);
|
||||
}
|
||||
|
||||
typedef NotificationCallback = void Function(FolderNotification, Either<Uint8List, FlowyError>);
|
||||
// Folder
|
||||
typedef FolderNotificationCallback = void Function(FolderNotification, Either<Uint8List, FlowyError>);
|
||||
|
||||
class FolderNotificationParser extends NotificationParser<FolderNotification, FlowyError> {
|
||||
FolderNotificationParser({String? id, required NotificationCallback callback})
|
||||
FolderNotificationParser({String? id, required FolderNotificationCallback callback})
|
||||
: super(
|
||||
id: id,
|
||||
callback: callback,
|
||||
@ -29,6 +32,19 @@ class FolderNotificationParser extends NotificationParser<FolderNotification, Fl
|
||||
);
|
||||
}
|
||||
|
||||
// Grid
|
||||
typedef GridNotificationCallback = void Function(GridNotification, Either<Uint8List, FlowyError>);
|
||||
|
||||
class GridNotificationParser extends NotificationParser<GridNotification, FlowyError> {
|
||||
GridNotificationParser({String? id, required GridNotificationCallback callback})
|
||||
: super(
|
||||
id: id,
|
||||
callback: callback,
|
||||
tyParser: (ty) => GridNotification.valueOf(ty),
|
||||
errorParser: (bytes) => FlowyError.fromBuffer(bytes),
|
||||
);
|
||||
}
|
||||
|
||||
class NotificationParser<T, E> {
|
||||
String? id;
|
||||
void Function(T, Either<Uint8List, E>) callback;
|
||||
|
@ -16,6 +16,8 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
import '../workspace/application/grid/grid_listener.dart';
|
||||
|
||||
class HomeDepsResolver {
|
||||
static Future<void> resolve(GetIt getIt) async {
|
||||
getIt.registerFactoryParam<UserListener, UserProfile, void>(
|
||||
@ -90,10 +92,7 @@ class HomeDepsResolver {
|
||||
|
||||
// Grid
|
||||
getIt.registerFactoryParam<GridBloc, View, void>(
|
||||
(view, _) => GridBloc(
|
||||
view: view,
|
||||
service: GridService(),
|
||||
),
|
||||
(view, _) => GridBloc(view: view, service: GridService(), listener: GridListener(gridId: view.id)),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<RowBloc, GridRowData, void>(
|
||||
|
@ -1,13 +1,14 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import 'data.dart';
|
||||
import 'grid_listener.dart';
|
||||
import 'grid_service.dart';
|
||||
|
||||
part 'grid_bloc.freezed.dart';
|
||||
@ -15,14 +16,16 @@ part 'grid_bloc.freezed.dart';
|
||||
class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
final GridService service;
|
||||
final View view;
|
||||
final GridListener listener;
|
||||
Grid? _grid;
|
||||
List<Field>? _fields;
|
||||
|
||||
GridBloc({required this.view, required this.service}) : super(GridState.initial()) {
|
||||
GridBloc({required this.view, required this.service, required this.listener}) : super(GridState.initial()) {
|
||||
on<GridEvent>(
|
||||
(event, emit) async {
|
||||
await event.map(
|
||||
initial: (InitialGrid value) async {
|
||||
await _startGridListening();
|
||||
await _loadGrid(emit);
|
||||
await _loadFields(emit);
|
||||
await _loadGridInfo(emit);
|
||||
@ -40,9 +43,25 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await listener.close();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
Future<void> _startGridListening() async {
|
||||
listener.createRowNotifier.addPublishListener((result) {
|
||||
result.fold((row) {
|
||||
//
|
||||
Log.info("$row");
|
||||
}, (err) => null);
|
||||
});
|
||||
|
||||
listener.deleteRowNotifier.addPublishListener((result) {
|
||||
result.fold((l) => null, (r) => null);
|
||||
});
|
||||
|
||||
listener.start();
|
||||
}
|
||||
|
||||
Future<void> _loadGrid(Emitter<GridState> emit) async {
|
||||
final result = await service.openGrid(gridId: view.id);
|
||||
result.fold(
|
||||
|
@ -0,0 +1,60 @@
|
||||
import 'package:flowy_sdk/protobuf/dart-notify/subject.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'package:app_flowy/core/notification_helper.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
typedef CreateRowNotifiedValue = Either<RepeatedRow, FlowyError>;
|
||||
typedef DeleteRowNotifierValue = Either<RepeatedRow, FlowyError>;
|
||||
|
||||
class GridListener {
|
||||
final String gridId;
|
||||
PublishNotifier<CreateRowNotifiedValue> createRowNotifier = PublishNotifier<CreateRowNotifiedValue>();
|
||||
PublishNotifier<DeleteRowNotifierValue> deleteRowNotifier = PublishNotifier<DeleteRowNotifierValue>();
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
late GridNotificationParser _parser;
|
||||
|
||||
GridListener({required this.gridId});
|
||||
|
||||
void start() {
|
||||
_parser = GridNotificationParser(
|
||||
id: gridId,
|
||||
callback: (ty, result) {
|
||||
_handleObservableType(ty, result);
|
||||
},
|
||||
);
|
||||
|
||||
_subscription = RustStreamReceiver.listen((observable) => _parser.parse(observable));
|
||||
}
|
||||
|
||||
void _handleObservableType(GridNotification ty, Either<Uint8List, FlowyError> result) {
|
||||
switch (ty) {
|
||||
case GridNotification.GridDidCreateRows:
|
||||
result.fold(
|
||||
(payload) => createRowNotifier.value = left(RepeatedRow.fromBuffer(payload)),
|
||||
(error) => createRowNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
case GridNotification.GridDidDeleteRow:
|
||||
result.fold(
|
||||
(payload) => deleteRowNotifier.value = left(RepeatedRow.fromBuffer(payload)),
|
||||
(error) => deleteRowNotifier.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> close() async {
|
||||
await _subscription?.cancel();
|
||||
createRowNotifier.dispose();
|
||||
deleteRowNotifier.dispose();
|
||||
}
|
||||
}
|
@ -9,15 +9,15 @@ import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart';
|
||||
import 'package:flowy_sdk/rust_stream.dart';
|
||||
import 'package:flowy_infra/notifier.dart';
|
||||
|
||||
typedef DeleteNotifierValue = Either<View, FlowyError>;
|
||||
typedef UpdateNotifierValue = Either<View, FlowyError>;
|
||||
typedef RestoreNotifierValue = Either<View, FlowyError>;
|
||||
typedef DeleteViewNotifyValue = Either<View, FlowyError>;
|
||||
typedef UpdateViewNotifiedValue = Either<View, FlowyError>;
|
||||
typedef RestoreViewNotifiedValue = Either<View, FlowyError>;
|
||||
|
||||
class ViewListener {
|
||||
StreamSubscription<SubscribeObject>? _subscription;
|
||||
PublishNotifier<UpdateNotifierValue> updatedNotifier = PublishNotifier<UpdateNotifierValue>();
|
||||
PublishNotifier<DeleteNotifierValue> deletedNotifier = PublishNotifier<DeleteNotifierValue>();
|
||||
PublishNotifier<RestoreNotifierValue> restoredNotifier = PublishNotifier<RestoreNotifierValue>();
|
||||
PublishNotifier<UpdateViewNotifiedValue> updatedNotifier = PublishNotifier<UpdateViewNotifiedValue>();
|
||||
PublishNotifier<DeleteViewNotifyValue> deletedNotifier = PublishNotifier<DeleteViewNotifyValue>();
|
||||
PublishNotifier<RestoreViewNotifiedValue> restoredNotifier = PublishNotifier<RestoreViewNotifiedValue>();
|
||||
late FolderNotificationParser _parser;
|
||||
View view;
|
||||
|
||||
|
@ -139,9 +139,10 @@ class _GridBodyState extends State<GridBody> {
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final data = gridInfo.rowAtIndex(index);
|
||||
return RepaintBoundary(child: GridRowWidget(data: data));
|
||||
return GridRowWidget(data: data);
|
||||
},
|
||||
childCount: gridInfo.numberOfRows(),
|
||||
addRepaintBoundaries: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -607,6 +607,47 @@ class Cell extends $pb.GeneratedMessage {
|
||||
void clearContent() => clearField(2);
|
||||
}
|
||||
|
||||
class RepeatedCell extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedCell', createEmptyInstance: create)
|
||||
..pc<Cell>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: Cell.create)
|
||||
..hasRequiredFields = false
|
||||
;
|
||||
|
||||
RepeatedCell._() : super();
|
||||
factory RepeatedCell({
|
||||
$core.Iterable<Cell>? items,
|
||||
}) {
|
||||
final _result = create();
|
||||
if (items != null) {
|
||||
_result.items.addAll(items);
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
factory RepeatedCell.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory RepeatedCell.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
RepeatedCell clone() => RepeatedCell()..mergeFromMessage(this);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
RepeatedCell copyWith(void Function(RepeatedCell) updates) => super.copyWith((message) => updates(message as RepeatedCell)) as RepeatedCell; // ignore: deprecated_member_use
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static RepeatedCell create() => RepeatedCell._();
|
||||
RepeatedCell createEmptyInstance() => create();
|
||||
static $pb.PbList<RepeatedCell> createRepeated() => $pb.PbList<RepeatedCell>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static RepeatedCell getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<RepeatedCell>(create);
|
||||
static RepeatedCell? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.List<Cell> get items => $_getList(0);
|
||||
}
|
||||
|
||||
class CreateGridPayload extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateGridPayload', createEmptyInstance: create)
|
||||
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
|
||||
|
@ -131,6 +131,16 @@ const Cell$json = const {
|
||||
|
||||
/// Descriptor for `Cell`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhgKB2NvbnRlbnQYAiABKAlSB2NvbnRlbnQ=');
|
||||
@$core.Deprecated('Use repeatedCellDescriptor instead')
|
||||
const RepeatedCell$json = const {
|
||||
'1': 'RepeatedCell',
|
||||
'2': const [
|
||||
const {'1': 'items', '3': 1, '4': 3, '5': 11, '6': '.Cell', '10': 'items'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `RepeatedCell`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List repeatedCellDescriptor = $convert.base64Decode('CgxSZXBlYXRlZENlbGwSGwoFaXRlbXMYASADKAsyBS5DZWxsUgVpdGVtcw==');
|
||||
@$core.Deprecated('Use createGridPayloadDescriptor instead')
|
||||
const CreateGridPayload$json = const {
|
||||
'1': 'CreateGridPayload',
|
||||
|
@ -0,0 +1,11 @@
|
||||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: dart_notification.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
|
||||
|
||||
import 'dart:core' as $core;
|
||||
|
||||
export 'dart_notification.pbenum.dart';
|
||||
|
@ -0,0 +1,34 @@
|
||||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: dart_notification.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
|
||||
|
||||
// ignore_for_file: UNDEFINED_SHOWN_NAME
|
||||
import 'dart:core' as $core;
|
||||
import 'package:protobuf/protobuf.dart' as $pb;
|
||||
|
||||
class GridNotification extends $pb.ProtobufEnum {
|
||||
static const GridNotification Unknown = GridNotification._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
|
||||
static const GridNotification GridDidCreateRows = GridNotification._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidCreateRows');
|
||||
static const GridNotification GridDidDeleteRow = GridNotification._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidDeleteRow');
|
||||
static const GridNotification GridDidUpdateRows = GridNotification._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidUpdateRows');
|
||||
static const GridNotification GridDidUpdateCells = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidUpdateCells');
|
||||
static const GridNotification GridDidUpdateFields = GridNotification._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidUpdateFields');
|
||||
|
||||
static const $core.List<GridNotification> values = <GridNotification> [
|
||||
Unknown,
|
||||
GridDidCreateRows,
|
||||
GridDidDeleteRow,
|
||||
GridDidUpdateRows,
|
||||
GridDidUpdateCells,
|
||||
GridDidUpdateFields,
|
||||
];
|
||||
|
||||
static final $core.Map<$core.int, GridNotification> _byValue = $pb.ProtobufEnum.initByValue(values);
|
||||
static GridNotification? valueOf($core.int value) => _byValue[value];
|
||||
|
||||
const GridNotification._($core.int v, $core.String n) : super(v, n);
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: dart_notification.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
|
||||
|
||||
import 'dart:core' as $core;
|
||||
import 'dart:convert' as $convert;
|
||||
import 'dart:typed_data' as $typed_data;
|
||||
@$core.Deprecated('Use gridNotificationDescriptor instead')
|
||||
const GridNotification$json = const {
|
||||
'1': 'GridNotification',
|
||||
'2': const [
|
||||
const {'1': 'Unknown', '2': 0},
|
||||
const {'1': 'GridDidCreateRows', '2': 10},
|
||||
const {'1': 'GridDidDeleteRow', '2': 11},
|
||||
const {'1': 'GridDidUpdateRows', '2': 12},
|
||||
const {'1': 'GridDidUpdateCells', '2': 20},
|
||||
const {'1': 'GridDidUpdateFields', '2': 30},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `GridNotification`. Decode as a `google.protobuf.EnumDescriptorProto`.
|
||||
final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABIVChFHcmlkRGlkQ3JlYXRlUm93cxAKEhQKEEdyaWREaWREZWxldGVSb3cQCxIVChFHcmlkRGlkVXBkYXRlUm93cxAMEhYKEkdyaWREaWRVcGRhdGVDZWxscxAUEhcKE0dyaWREaWRVcGRhdGVGaWVsZHMQHg==');
|
@ -0,0 +1,9 @@
|
||||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: dart_notification.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
|
||||
|
||||
export 'dart_notification.pb.dart';
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Auto-generated, do not edit
|
||||
export './date_description.pb.dart';
|
||||
export './text_description.pb.dart';
|
||||
export './dart_notification.pb.dart';
|
||||
export './checkbox_description.pb.dart';
|
||||
export './selection_description.pb.dart';
|
||||
export './event_map.pb.dart';
|
||||
|
@ -1,3 +1,3 @@
|
||||
|
||||
proto_crates = ["src/event_map.rs", "src/services/cell/description"]
|
||||
proto_crates = ["src/event_map.rs", "src/services/cell/description", "src/dart_notification.rs"]
|
||||
event_files = ["src/event_map.rs"]
|
36
frontend/rust-lib/flowy-grid/src/dart_notification.rs
Normal file
36
frontend/rust-lib/flowy-grid/src/dart_notification.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use dart_notify::DartNotifyBuilder;
|
||||
use flowy_derive::ProtoBuf_Enum;
|
||||
const OBSERVABLE_CATEGORY: &str = "Grid";
|
||||
|
||||
#[derive(ProtoBuf_Enum, Debug)]
|
||||
pub enum GridNotification {
|
||||
Unknown = 0,
|
||||
GridDidCreateRows = 10,
|
||||
GridDidDeleteRow = 11,
|
||||
GridDidUpdateRows = 12,
|
||||
|
||||
GridDidUpdateCells = 20,
|
||||
GridDidUpdateFields = 30,
|
||||
}
|
||||
|
||||
impl std::default::Default for GridNotification {
|
||||
fn default() -> Self {
|
||||
GridNotification::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GridNotification> for i32 {
|
||||
fn from(notification: GridNotification) -> Self {
|
||||
notification as i32
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace")]
|
||||
pub fn send_dart_notification(id: &str, ty: GridNotification) -> DartNotifyBuilder {
|
||||
DartNotifyBuilder::new(id, ty, OBSERVABLE_CATEGORY)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace")]
|
||||
pub fn send_anonymous_dart_notification(ty: GridNotification) -> DartNotifyBuilder {
|
||||
DartNotifyBuilder::new("", ty, OBSERVABLE_CATEGORY)
|
||||
}
|
@ -45,11 +45,11 @@ pub(crate) async fn get_fields_handler(
|
||||
pub(crate) async fn create_row_handler(
|
||||
data: Data<CreateRowPayload>,
|
||||
manager: AppData<Arc<GridManager>>,
|
||||
) -> DataResult<Row, FlowyError> {
|
||||
) -> Result<(), FlowyError> {
|
||||
let payload: CreateRowPayload = data.into_inner();
|
||||
let editor = manager.get_grid_editor(payload.grid_id.as_ref())?;
|
||||
let row = editor.create_row(payload.upper_row_id).await?;
|
||||
data_result(row)
|
||||
let _ = editor.create_row(payload.upper_row_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
|
@ -5,6 +5,7 @@ mod event_handler;
|
||||
pub mod event_map;
|
||||
pub mod manager;
|
||||
|
||||
mod dart_notification;
|
||||
mod protobuf;
|
||||
pub mod services;
|
||||
pub mod util;
|
||||
|
@ -0,0 +1,106 @@
|
||||
// This file is generated by rust-protobuf 2.25.2. Do not edit
|
||||
// @generated
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/702
|
||||
#![allow(unknown_lints)]
|
||||
#![allow(clippy::all)]
|
||||
|
||||
#![allow(unused_attributes)]
|
||||
#![cfg_attr(rustfmt, rustfmt::skip)]
|
||||
|
||||
#![allow(box_pointers)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(trivial_casts)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(unused_results)]
|
||||
//! Generated file from `dart_notification.proto`
|
||||
|
||||
/// Generated files are compatible only with the same version
|
||||
/// of protobuf runtime.
|
||||
// const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_2_25_2;
|
||||
|
||||
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
|
||||
pub enum GridNotification {
|
||||
Unknown = 0,
|
||||
GridDidCreateRows = 10,
|
||||
GridDidDeleteRow = 11,
|
||||
GridDidUpdateRows = 12,
|
||||
GridDidUpdateCells = 20,
|
||||
GridDidUpdateFields = 30,
|
||||
}
|
||||
|
||||
impl ::protobuf::ProtobufEnum for GridNotification {
|
||||
fn value(&self) -> i32 {
|
||||
*self as i32
|
||||
}
|
||||
|
||||
fn from_i32(value: i32) -> ::std::option::Option<GridNotification> {
|
||||
match value {
|
||||
0 => ::std::option::Option::Some(GridNotification::Unknown),
|
||||
10 => ::std::option::Option::Some(GridNotification::GridDidCreateRows),
|
||||
11 => ::std::option::Option::Some(GridNotification::GridDidDeleteRow),
|
||||
12 => ::std::option::Option::Some(GridNotification::GridDidUpdateRows),
|
||||
20 => ::std::option::Option::Some(GridNotification::GridDidUpdateCells),
|
||||
30 => ::std::option::Option::Some(GridNotification::GridDidUpdateFields),
|
||||
_ => ::std::option::Option::None
|
||||
}
|
||||
}
|
||||
|
||||
fn values() -> &'static [Self] {
|
||||
static values: &'static [GridNotification] = &[
|
||||
GridNotification::Unknown,
|
||||
GridNotification::GridDidCreateRows,
|
||||
GridNotification::GridDidDeleteRow,
|
||||
GridNotification::GridDidUpdateRows,
|
||||
GridNotification::GridDidUpdateCells,
|
||||
GridNotification::GridDidUpdateFields,
|
||||
];
|
||||
values
|
||||
}
|
||||
|
||||
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
|
||||
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
||||
descriptor.get(|| {
|
||||
::protobuf::reflect::EnumDescriptor::new_pb_name::<GridNotification>("GridNotification", file_descriptor_proto())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::marker::Copy for GridNotification {
|
||||
}
|
||||
|
||||
impl ::std::default::Default for GridNotification {
|
||||
fn default() -> Self {
|
||||
GridNotification::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for GridNotification {
|
||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||
::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
|
||||
}
|
||||
}
|
||||
|
||||
static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\n\x17dart_notification.proto*\x94\x01\n\x10GridNotification\x12\x0b\n\
|
||||
\x07Unknown\x10\0\x12\x15\n\x11GridDidCreateRows\x10\n\x12\x14\n\x10Grid\
|
||||
DidDeleteRow\x10\x0b\x12\x15\n\x11GridDidUpdateRows\x10\x0c\x12\x16\n\
|
||||
\x12GridDidUpdateCells\x10\x14\x12\x17\n\x13GridDidUpdateFields\x10\x1eb\
|
||||
\x06proto3\
|
||||
";
|
||||
|
||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||
|
||||
fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto {
|
||||
::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
|
||||
}
|
||||
|
||||
pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
|
||||
file_descriptor_proto_lazy.get(|| {
|
||||
parse_descriptor_proto()
|
||||
})
|
||||
}
|
@ -7,6 +7,9 @@ pub use date_description::*;
|
||||
mod text_description;
|
||||
pub use text_description::*;
|
||||
|
||||
mod dart_notification;
|
||||
pub use dart_notification::*;
|
||||
|
||||
mod checkbox_description;
|
||||
pub use checkbox_description::*;
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
syntax = "proto3";
|
||||
|
||||
enum GridNotification {
|
||||
Unknown = 0;
|
||||
GridDidCreateRows = 10;
|
||||
GridDidDeleteRow = 11;
|
||||
GridDidUpdateRows = 12;
|
||||
GridDidUpdateCells = 20;
|
||||
GridDidUpdateFields = 30;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use crate::manager::GridUser;
|
||||
use crate::services::row::make_row_ids_per_block;
|
||||
use crate::services::row::{make_cell, make_row_ids_per_block, make_rows};
|
||||
use bytes::Bytes;
|
||||
|
||||
use dashmap::DashMap;
|
||||
@ -8,7 +8,8 @@ use flowy_collaboration::entities::revision::Revision;
|
||||
use flowy_collaboration::util::make_delta_from_revisions;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::{
|
||||
GridBlock, GridBlockChangeset, RepeatedRowOrder, RowMeta, RowMetaChangeset, RowOrder,
|
||||
Cell, FieldMeta, GridBlock, GridBlockChangeset, RepeatedCell, RepeatedRow, RepeatedRowOrder, RowMeta,
|
||||
RowMetaChangeset, RowOrder,
|
||||
};
|
||||
use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
|
||||
use flowy_sync::{
|
||||
@ -19,6 +20,7 @@ use lib_ot::core::PlainTextAttributes;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
@ -26,17 +28,20 @@ type RowId = String;
|
||||
type BlockId = String;
|
||||
|
||||
pub(crate) struct GridBlockMetaEditorManager {
|
||||
grid_id: String,
|
||||
user: Arc<dyn GridUser>,
|
||||
editor_map: DashMap<String, Arc<ClientGridBlockMetaEditor>>,
|
||||
block_id_by_row_id: DashMap<BlockId, RowId>,
|
||||
}
|
||||
|
||||
impl GridBlockMetaEditorManager {
|
||||
pub(crate) async fn new(user: &Arc<dyn GridUser>, blocks: Vec<GridBlock>) -> FlowyResult<Self> {
|
||||
pub(crate) async fn new(grid_id: &str, user: &Arc<dyn GridUser>, blocks: Vec<GridBlock>) -> FlowyResult<Self> {
|
||||
let editor_map = make_block_meta_editor_map(user, blocks).await?;
|
||||
let user = user.clone();
|
||||
let block_id_by_row_id = DashMap::new();
|
||||
let grid_id = grid_id.to_owned();
|
||||
let manager = Self {
|
||||
grid_id,
|
||||
user,
|
||||
editor_map,
|
||||
block_id_by_row_id,
|
||||
@ -56,25 +61,41 @@ impl GridBlockMetaEditorManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn create_row(&self, row: RowMeta, upper_row_id: Option<String>) -> FlowyResult<i32> {
|
||||
self.block_id_by_row_id.insert(row.id.clone(), row.block_id.clone());
|
||||
let editor = self.get_editor(&row.block_id).await?;
|
||||
editor.create_row(row, upper_row_id).await
|
||||
pub(crate) async fn create_row(
|
||||
&self,
|
||||
field_metas: &[FieldMeta],
|
||||
row_meta: RowMeta,
|
||||
upper_row_id: Option<String>,
|
||||
) -> FlowyResult<i32> {
|
||||
self.block_id_by_row_id
|
||||
.insert(row_meta.id.clone(), row_meta.block_id.clone());
|
||||
let editor = self.get_editor(&row_meta.block_id).await?;
|
||||
|
||||
let rows = make_rows(field_metas, vec![row_meta.clone().into()]);
|
||||
send_dart_notification(&self.grid_id, GridNotification::GridDidCreateRows)
|
||||
.payload(RepeatedRow::from(rows))
|
||||
.send();
|
||||
|
||||
self.notify_did_create_rows(field_metas, vec![row_meta.clone()]);
|
||||
|
||||
editor.create_row(row_meta, upper_row_id).await
|
||||
}
|
||||
|
||||
pub(crate) async fn insert_row(
|
||||
&self,
|
||||
field_metas: &[FieldMeta],
|
||||
rows_by_block_id: HashMap<String, Vec<RowMeta>>,
|
||||
) -> FlowyResult<Vec<GridBlockChangeset>> {
|
||||
let mut changesets = vec![];
|
||||
for (block_id, rows) in rows_by_block_id {
|
||||
for (block_id, row_metas) in rows_by_block_id {
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
let mut row_count = 0;
|
||||
for row in rows {
|
||||
for row in &row_metas {
|
||||
self.block_id_by_row_id.insert(row.id.clone(), row.block_id.clone());
|
||||
row_count = editor.create_row(row, None).await?;
|
||||
row_count = editor.create_row(row.clone(), None).await?;
|
||||
}
|
||||
changesets.push(GridBlockChangeset::from_row_count(&block_id, row_count));
|
||||
self.notify_did_create_rows(field_metas, row_metas);
|
||||
}
|
||||
|
||||
Ok(changesets)
|
||||
@ -104,19 +125,17 @@ impl GridBlockMetaEditorManager {
|
||||
}
|
||||
|
||||
pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
|
||||
match self.block_id_by_row_id.get(&changeset.row_id) {
|
||||
None => {
|
||||
let msg = format!(
|
||||
"Update Row failed. Can't find the corresponding block with row_id: {}",
|
||||
changeset.row_id
|
||||
);
|
||||
Err(FlowyError::internal().context(msg))
|
||||
}
|
||||
Some(block_id) => {
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
editor.update_row(changeset).await
|
||||
}
|
||||
}
|
||||
let editor = self.get_editor_from_row_id(&changeset.row_id).await?;
|
||||
let _ = editor.update_row(changeset.clone()).await?;
|
||||
let _ = self.notify_did_update_row()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_cells(&self, field_metas: &[FieldMeta], changeset: RowMetaChangeset) -> FlowyResult<()> {
|
||||
let editor = self.get_editor_from_row_id(&changeset.row_id).await?;
|
||||
let _ = editor.update_row(changeset.clone()).await?;
|
||||
self.notify_did_update_cells(changeset, field_metas)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_all_rows(&self, grid_blocks: Vec<GridBlock>) -> FlowyResult<Vec<Arc<RowMeta>>> {
|
||||
@ -159,6 +178,68 @@ impl GridBlockMetaEditorManager {
|
||||
}
|
||||
Ok(row_metas)
|
||||
}
|
||||
|
||||
async fn get_editor_from_row_id(&self, row_id: &str) -> FlowyResult<Arc<ClientGridBlockMetaEditor>> {
|
||||
match self.block_id_by_row_id.get(row_id) {
|
||||
None => {
|
||||
let msg = format!(
|
||||
"Update Row failed. Can't find the corresponding block with row_id: {}",
|
||||
row_id
|
||||
);
|
||||
Err(FlowyError::internal().context(msg))
|
||||
}
|
||||
Some(block_id) => {
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
Ok(editor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn notify_did_create_rows(&self, field_metas: &[FieldMeta], row_metas: Vec<RowMeta>) {
|
||||
let rows = make_rows(
|
||||
field_metas,
|
||||
row_metas
|
||||
.into_iter()
|
||||
.map(|row_meta| Arc::new(row_meta))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
send_dart_notification(&self.grid_id, GridNotification::GridDidCreateRows)
|
||||
.payload(RepeatedRow::from(rows))
|
||||
.send();
|
||||
}
|
||||
|
||||
fn notify_did_update_row(&self) -> FlowyResult<()> {
|
||||
// send_dart_notification(&changeset.row_id, GridNotification::GridDidUpdateRows)
|
||||
// .payload(RepeatedRow::from(cells))
|
||||
// .send();
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn notify_did_update_cells(&self, changeset: RowMetaChangeset, field_metas: &[FieldMeta]) -> FlowyResult<()> {
|
||||
let field_meta_map = field_metas
|
||||
.iter()
|
||||
.map(|field_meta| (&field_meta.id, field_meta))
|
||||
.collect::<HashMap<&String, &FieldMeta>>();
|
||||
|
||||
let mut cells = vec![];
|
||||
changeset
|
||||
.cell_by_field_id
|
||||
.into_iter()
|
||||
.for_each(
|
||||
|(field_id, cell_meta)| match make_cell(&field_meta_map, field_id, cell_meta) {
|
||||
None => {}
|
||||
Some((_, cell)) => cells.push(cell),
|
||||
},
|
||||
);
|
||||
|
||||
if !cells.is_empty() {
|
||||
send_dart_notification(&changeset.row_id, GridNotification::GridDidUpdateCells)
|
||||
.payload(RepeatedCell::from(cells))
|
||||
.send();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn make_block_meta_editor_map(
|
||||
|
@ -1,16 +1,17 @@
|
||||
use crate::manager::GridUser;
|
||||
use crate::services::block_meta_editor::GridBlockMetaEditorManager;
|
||||
use bytes::Bytes;
|
||||
use flowy_collaboration::client_grid::{GridChange, GridMetaPad};
|
||||
use flowy_collaboration::client_grid::{GridChangeset, GridMetaPad};
|
||||
use flowy_collaboration::entities::revision::Revision;
|
||||
use flowy_collaboration::util::make_delta_from_revisions;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::entities::{
|
||||
CellMetaChangeset, FieldChangeset, FieldMeta, Grid, GridBlock, GridBlockChangeset, RepeatedFieldOrder,
|
||||
RepeatedRowOrder, Row, RowMeta, RowMetaChangeset,
|
||||
Cell, CellMetaChangeset, Field, FieldChangeset, FieldMeta, Grid, GridBlock, GridBlockChangeset, RepeatedField,
|
||||
RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row, RowMeta, RowMetaChangeset,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||
use crate::services::row::{
|
||||
make_row_by_row_id, make_rows, row_meta_from_context, serialize_cell_data, RowMetaContext, RowMetaContextBuilder,
|
||||
};
|
||||
@ -40,8 +41,9 @@ impl ClientGridEditor {
|
||||
let rev_manager = Arc::new(rev_manager);
|
||||
let grid_meta_pad = Arc::new(RwLock::new(grid_pad));
|
||||
|
||||
let block_meta_manager =
|
||||
Arc::new(GridBlockMetaEditorManager::new(&user, grid_meta_pad.read().await.get_blocks().clone()).await?);
|
||||
let block_meta_manager = Arc::new(
|
||||
GridBlockMetaEditorManager::new(grid_id, &user, grid_meta_pad.read().await.get_blocks().clone()).await?,
|
||||
);
|
||||
|
||||
Ok(Arc::new(Self {
|
||||
grid_id: grid_id.to_owned(),
|
||||
@ -54,6 +56,7 @@ impl ClientGridEditor {
|
||||
|
||||
pub async fn create_field(&self, field_meta: FieldMeta) -> FlowyResult<()> {
|
||||
let _ = self.modify(|grid| Ok(grid.create_field(field_meta)?)).await?;
|
||||
let _ = self.notify_did_update_fields().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -81,7 +84,7 @@ impl ClientGridEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_row(&self, upper_row_id: Option<String>) -> FlowyResult<Row> {
|
||||
pub async fn create_row(&self, upper_row_id: Option<String>) -> FlowyResult<()> {
|
||||
let field_metas = self.grid_meta_pad.read().await.get_field_metas(None)?;
|
||||
let block_id = self.last_block_id().await?;
|
||||
|
||||
@ -92,17 +95,17 @@ impl ClientGridEditor {
|
||||
// insert the row
|
||||
let row_count = self
|
||||
.block_meta_manager
|
||||
.create_row(row_meta.clone(), upper_row_id)
|
||||
.create_row(&field_metas, row_meta, upper_row_id)
|
||||
.await?;
|
||||
let row = make_rows(&field_metas, vec![row_meta.into()]).pop().unwrap();
|
||||
|
||||
// update block row count
|
||||
let changeset = GridBlockChangeset::from_row_count(&block_id, row_count);
|
||||
let _ = self.update_block(changeset).await?;
|
||||
Ok(row)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn insert_rows(&self, contexts: Vec<RowMetaContext>) -> FlowyResult<()> {
|
||||
let field_metas = self.grid_meta_pad.read().await.get_field_metas(None)?;
|
||||
let block_id = self.last_block_id().await?;
|
||||
let mut rows_by_block_id: HashMap<String, Vec<RowMeta>> = HashMap::new();
|
||||
for ctx in contexts {
|
||||
@ -112,7 +115,10 @@ impl ClientGridEditor {
|
||||
.or_insert_with(Vec::new)
|
||||
.push(row_meta);
|
||||
}
|
||||
let changesets = self.block_meta_manager.insert_row(rows_by_block_id).await?;
|
||||
let changesets = self
|
||||
.block_meta_manager
|
||||
.insert_row(&field_metas, rows_by_block_id)
|
||||
.await?;
|
||||
for changeset in changesets {
|
||||
let _ = self.update_block(changeset).await?;
|
||||
}
|
||||
@ -136,8 +142,13 @@ impl ClientGridEditor {
|
||||
}
|
||||
}
|
||||
|
||||
let field_metas = self.get_field_metas(None).await?;
|
||||
let row_changeset: RowMetaChangeset = changeset.into();
|
||||
self.update_row(row_changeset).await
|
||||
let _ = self
|
||||
.block_meta_manager
|
||||
.update_cells(&field_metas, row_changeset)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<Vec<Row>> {
|
||||
@ -205,7 +216,7 @@ impl ClientGridEditor {
|
||||
|
||||
async fn modify<F>(&self, f: F) -> FlowyResult<()>
|
||||
where
|
||||
F: for<'a> FnOnce(&'a mut GridMetaPad) -> FlowyResult<Option<GridChange>>,
|
||||
F: for<'a> FnOnce(&'a mut GridMetaPad) -> FlowyResult<Option<GridChangeset>>,
|
||||
{
|
||||
let mut write_guard = self.grid_meta_pad.write().await;
|
||||
match f(&mut *write_guard)? {
|
||||
@ -217,8 +228,8 @@ impl ClientGridEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn apply_change(&self, change: GridChange) -> FlowyResult<()> {
|
||||
let GridChange { delta, md5 } = change;
|
||||
async fn apply_change(&self, change: GridChangeset) -> FlowyResult<()> {
|
||||
let GridChangeset { delta, md5 } = change;
|
||||
let user_id = self.user.user_id()?;
|
||||
let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
|
||||
let delta_data = delta.to_delta_bytes();
|
||||
@ -243,6 +254,15 @@ impl ClientGridEditor {
|
||||
Some(grid_block) => Ok(grid_block.id.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn notify_did_update_fields(&self) -> FlowyResult<()> {
|
||||
let field_metas = self.get_field_metas(None).await?;
|
||||
let repeated_field: RepeatedField = field_metas.into_iter().map(Field::from).collect::<Vec<_>>().into();
|
||||
send_dart_notification(&self.grid_id, GridNotification::GridDidUpdateFields)
|
||||
.payload(repeated_field)
|
||||
.send();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "flowy_unit_test")]
|
||||
|
@ -48,7 +48,11 @@ pub(crate) fn make_rows(fields: &[FieldMeta], row_metas: Vec<Arc<RowMeta>>) -> V
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn make_cell(field_map: &HashMap<&String, &FieldMeta>, field_id: String, raw_cell: CellMeta) -> Option<(String, Cell)> {
|
||||
pub fn make_cell(
|
||||
field_map: &HashMap<&String, &FieldMeta>,
|
||||
field_id: String,
|
||||
raw_cell: CellMeta,
|
||||
) -> Option<(String, Cell)> {
|
||||
let field_meta = field_map.get(&field_id)?;
|
||||
match deserialize_cell_data(raw_cell.data, field_meta) {
|
||||
Ok(content) => {
|
||||
@ -63,9 +67,9 @@ fn make_cell(field_map: &HashMap<&String, &FieldMeta>, field_id: String, raw_cel
|
||||
}
|
||||
|
||||
pub(crate) fn make_row_by_row_id(fields: &[FieldMeta], row_metas: Vec<Arc<RowMeta>>) -> HashMap<String, Row> {
|
||||
let field_map = fields
|
||||
let field_meta_map = fields
|
||||
.iter()
|
||||
.map(|field| (&field.id, field))
|
||||
.map(|field_meta| (&field_meta.id, field_meta))
|
||||
.collect::<HashMap<&String, &FieldMeta>>();
|
||||
|
||||
let make_row = |row_meta: Arc<RowMeta>| {
|
||||
@ -73,7 +77,7 @@ pub(crate) fn make_row_by_row_id(fields: &[FieldMeta], row_metas: Vec<Arc<RowMet
|
||||
.cell_by_field_id
|
||||
.clone()
|
||||
.into_par_iter()
|
||||
.flat_map(|(field_id, raw_cell)| make_cell(&field_map, field_id, raw_cell))
|
||||
.flat_map(|(field_id, raw_cell)| make_cell(&field_meta_map, field_id, raw_cell))
|
||||
.collect::<HashMap<String, Cell>>();
|
||||
|
||||
let row = Row {
|
||||
|
@ -172,7 +172,7 @@ impl GridEditorTest {
|
||||
assert_eq!(compared_block, block);
|
||||
}
|
||||
EditorScript::CreateEmptyRow => {
|
||||
self.editor.create_row().await.unwrap();
|
||||
self.editor.create_row(None).await.unwrap();
|
||||
self.row_metas = self.editor.get_row_metas(None).await.unwrap();
|
||||
self.grid_blocks = self.editor.get_blocks().await.unwrap();
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ impl GridMetaPad {
|
||||
Self::from_delta(grid_delta)
|
||||
}
|
||||
|
||||
pub fn create_field(&mut self, field_meta: FieldMeta) -> CollaborateResult<Option<GridChange>> {
|
||||
pub fn create_field(&mut self, field_meta: FieldMeta) -> CollaborateResult<Option<GridChangeset>> {
|
||||
self.modify_grid(|grid| {
|
||||
if grid.fields.contains(&field_meta) {
|
||||
tracing::warn!("Duplicate grid field");
|
||||
@ -47,7 +47,7 @@ impl GridMetaPad {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn delete_field(&mut self, field_id: &str) -> CollaborateResult<Option<GridChange>> {
|
||||
pub fn delete_field(&mut self, field_id: &str) -> CollaborateResult<Option<GridChangeset>> {
|
||||
self.modify_grid(|grid| match grid.fields.iter().position(|field| field.id == field_id) {
|
||||
None => Ok(None),
|
||||
Some(index) => {
|
||||
@ -95,7 +95,7 @@ impl GridMetaPad {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_field(&mut self, changeset: FieldChangeset) -> CollaborateResult<Option<GridChange>> {
|
||||
pub fn update_field(&mut self, changeset: FieldChangeset) -> CollaborateResult<Option<GridChangeset>> {
|
||||
let field_id = changeset.field_id.clone();
|
||||
self.modify_field(&field_id, |field| {
|
||||
let mut is_changed = None;
|
||||
@ -138,7 +138,7 @@ impl GridMetaPad {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_block(&mut self, block: GridBlock) -> CollaborateResult<Option<GridChange>> {
|
||||
pub fn create_block(&mut self, block: GridBlock) -> CollaborateResult<Option<GridChangeset>> {
|
||||
self.modify_grid(|grid| {
|
||||
if grid.blocks.iter().any(|b| b.id == block.id) {
|
||||
tracing::warn!("Duplicate grid block");
|
||||
@ -165,7 +165,7 @@ impl GridMetaPad {
|
||||
self.grid_meta.blocks.clone()
|
||||
}
|
||||
|
||||
pub fn update_block(&mut self, changeset: GridBlockChangeset) -> CollaborateResult<Option<GridChange>> {
|
||||
pub fn update_block(&mut self, changeset: GridBlockChangeset) -> CollaborateResult<Option<GridChangeset>> {
|
||||
let block_id = changeset.block_id.clone();
|
||||
self.modify_block(&block_id, |block| {
|
||||
let mut is_changed = None;
|
||||
@ -200,7 +200,7 @@ impl GridMetaPad {
|
||||
&self.grid_meta.fields
|
||||
}
|
||||
|
||||
fn modify_grid<F>(&mut self, f: F) -> CollaborateResult<Option<GridChange>>
|
||||
fn modify_grid<F>(&mut self, f: F) -> CollaborateResult<Option<GridChangeset>>
|
||||
where
|
||||
F: FnOnce(&mut GridMeta) -> CollaborateResult<Option<()>>,
|
||||
{
|
||||
@ -214,14 +214,14 @@ impl GridMetaPad {
|
||||
None => Ok(None),
|
||||
Some(delta) => {
|
||||
self.delta = self.delta.compose(&delta)?;
|
||||
Ok(Some(GridChange { delta, md5: self.md5() }))
|
||||
Ok(Some(GridChangeset { delta, md5: self.md5() }))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modify_block<F>(&mut self, block_id: &str, f: F) -> CollaborateResult<Option<GridChange>>
|
||||
pub fn modify_block<F>(&mut self, block_id: &str, f: F) -> CollaborateResult<Option<GridChangeset>>
|
||||
where
|
||||
F: FnOnce(&mut GridBlock) -> CollaborateResult<Option<()>>,
|
||||
{
|
||||
@ -234,7 +234,7 @@ impl GridMetaPad {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn modify_field<F>(&mut self, field_id: &str, f: F) -> CollaborateResult<Option<GridChange>>
|
||||
pub fn modify_field<F>(&mut self, field_id: &str, f: F) -> CollaborateResult<Option<GridChangeset>>
|
||||
where
|
||||
F: FnOnce(&mut FieldMeta) -> CollaborateResult<Option<()>>,
|
||||
{
|
||||
@ -254,7 +254,7 @@ fn json_from_grid(grid: &Arc<GridMeta>) -> CollaborateResult<String> {
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
pub struct GridChange {
|
||||
pub struct GridChangeset {
|
||||
pub delta: GridMetaDelta,
|
||||
/// md5: the md5 of the grid after applying the change.
|
||||
pub md5: String,
|
||||
|
@ -204,6 +204,31 @@ impl Cell {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct RepeatedCell {
|
||||
#[pb(index = 1)]
|
||||
pub items: Vec<Cell>,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for RepeatedCell {
|
||||
type Target = Vec<Cell>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for RepeatedCell {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.items
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Vec<Cell>> for RepeatedCell {
|
||||
fn from(items: Vec<Cell>) -> Self {
|
||||
Self { items }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct CreateGridPayload {
|
||||
#[pb(index = 1)]
|
||||
|
@ -2115,6 +2115,172 @@ impl ::protobuf::reflect::ProtobufValue for Cell {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default)]
|
||||
pub struct RepeatedCell {
|
||||
// message fields
|
||||
pub items: ::protobuf::RepeatedField<Cell>,
|
||||
// special fields
|
||||
pub unknown_fields: ::protobuf::UnknownFields,
|
||||
pub cached_size: ::protobuf::CachedSize,
|
||||
}
|
||||
|
||||
impl<'a> ::std::default::Default for &'a RepeatedCell {
|
||||
fn default() -> &'a RepeatedCell {
|
||||
<RepeatedCell as ::protobuf::Message>::default_instance()
|
||||
}
|
||||
}
|
||||
|
||||
impl RepeatedCell {
|
||||
pub fn new() -> RepeatedCell {
|
||||
::std::default::Default::default()
|
||||
}
|
||||
|
||||
// repeated .Cell items = 1;
|
||||
|
||||
|
||||
pub fn get_items(&self) -> &[Cell] {
|
||||
&self.items
|
||||
}
|
||||
pub fn clear_items(&mut self) {
|
||||
self.items.clear();
|
||||
}
|
||||
|
||||
// Param is passed by value, moved
|
||||
pub fn set_items(&mut self, v: ::protobuf::RepeatedField<Cell>) {
|
||||
self.items = v;
|
||||
}
|
||||
|
||||
// Mutable pointer to the field.
|
||||
pub fn mut_items(&mut self) -> &mut ::protobuf::RepeatedField<Cell> {
|
||||
&mut self.items
|
||||
}
|
||||
|
||||
// Take field
|
||||
pub fn take_items(&mut self) -> ::protobuf::RepeatedField<Cell> {
|
||||
::std::mem::replace(&mut self.items, ::protobuf::RepeatedField::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Message for RepeatedCell {
|
||||
fn is_initialized(&self) -> bool {
|
||||
for v in &self.items {
|
||||
if !v.is_initialized() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
||||
while !is.eof()? {
|
||||
let (field_number, wire_type) = is.read_tag_unpack()?;
|
||||
match field_number {
|
||||
1 => {
|
||||
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.items)?;
|
||||
},
|
||||
_ => {
|
||||
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
|
||||
},
|
||||
};
|
||||
}
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
// Compute sizes of nested messages
|
||||
#[allow(unused_variables)]
|
||||
fn compute_size(&self) -> u32 {
|
||||
let mut my_size = 0;
|
||||
for value in &self.items {
|
||||
let len = value.compute_size();
|
||||
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
|
||||
};
|
||||
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
|
||||
self.cached_size.set(my_size);
|
||||
my_size
|
||||
}
|
||||
|
||||
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
|
||||
for v in &self.items {
|
||||
os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?;
|
||||
os.write_raw_varint32(v.get_cached_size())?;
|
||||
v.write_to_with_cached_sizes(os)?;
|
||||
};
|
||||
os.write_unknown_fields(self.get_unknown_fields())?;
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
fn get_cached_size(&self) -> u32 {
|
||||
self.cached_size.get()
|
||||
}
|
||||
|
||||
fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
|
||||
&self.unknown_fields
|
||||
}
|
||||
|
||||
fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
|
||||
&mut self.unknown_fields
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn (::std::any::Any) {
|
||||
self as &dyn (::std::any::Any)
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
|
||||
self as &mut dyn (::std::any::Any)
|
||||
}
|
||||
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
|
||||
self
|
||||
}
|
||||
|
||||
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||
Self::descriptor_static()
|
||||
}
|
||||
|
||||
fn new() -> RepeatedCell {
|
||||
RepeatedCell::new()
|
||||
}
|
||||
|
||||
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
|
||||
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
|
||||
descriptor.get(|| {
|
||||
let mut fields = ::std::vec::Vec::new();
|
||||
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<Cell>>(
|
||||
"items",
|
||||
|m: &RepeatedCell| { &m.items },
|
||||
|m: &mut RepeatedCell| { &mut m.items },
|
||||
));
|
||||
::protobuf::reflect::MessageDescriptor::new_pb_name::<RepeatedCell>(
|
||||
"RepeatedCell",
|
||||
fields,
|
||||
file_descriptor_proto()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn default_instance() -> &'static RepeatedCell {
|
||||
static instance: ::protobuf::rt::LazyV2<RepeatedCell> = ::protobuf::rt::LazyV2::INIT;
|
||||
instance.get(RepeatedCell::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::Clear for RepeatedCell {
|
||||
fn clear(&mut self) {
|
||||
self.items.clear();
|
||||
self.unknown_fields.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Debug for RepeatedCell {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
::protobuf::text_format::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::protobuf::reflect::ProtobufValue for RepeatedCell {
|
||||
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
|
||||
::protobuf::reflect::ReflectValueRef::Message(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq,Clone,Default)]
|
||||
pub struct CreateGridPayload {
|
||||
// message fields
|
||||
@ -3129,16 +3295,17 @@ static file_descriptor_proto_data: &'static [u8] = b"\
|
||||
\x02\x20\x01(\x0b2\x05.CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\
|
||||
\x1a\n\x05items\x18\x01\x20\x03(\x0b2\x04.RowR\x05items\";\n\x04Cell\x12\
|
||||
\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07content\
|
||||
\x18\x02\x20\x01(\tR\x07content\"'\n\x11CreateGridPayload\x12\x12\n\x04n\
|
||||
ame\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05value\x18\
|
||||
\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\n\x07grid_id\
|
||||
\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cupper_row_id\x18\x02\x20\x01(\
|
||||
\tH\0R\nupperRowIdB\x15\n\x13one_of_upper_row_id\"d\n\x11QueryFieldPaylo\
|
||||
ad\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_or\
|
||||
ders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\x0bfieldOrders\"\\\n\
|
||||
\x0fQueryRowPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\
|
||||
\x120\n\nrow_orders\x18\x02\x20\x01(\x0b2\x11.RepeatedRowOrderR\trowOrde\
|
||||
rsb\x06proto3\
|
||||
\x18\x02\x20\x01(\tR\x07content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\
|
||||
\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\
|
||||
\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\
|
||||
\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\
|
||||
\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cupper_row_id\x18\
|
||||
\x02\x20\x01(\tH\0R\nupperRowIdB\x15\n\x13one_of_upper_row_id\"d\n\x11Qu\
|
||||
eryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\
|
||||
\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\x0bfiel\
|
||||
dOrders\"\\\n\x0fQueryRowPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\t\
|
||||
R\x06gridId\x120\n\nrow_orders\x18\x02\x20\x01(\x0b2\x11.RepeatedRowOrde\
|
||||
rR\trowOrdersb\x06proto3\
|
||||
";
|
||||
|
||||
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;
|
||||
|
@ -43,6 +43,9 @@ message Cell {
|
||||
string field_id = 1;
|
||||
string content = 2;
|
||||
}
|
||||
message RepeatedCell {
|
||||
repeated Cell items = 1;
|
||||
}
|
||||
message CreateGridPayload {
|
||||
string name = 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user