From 8b7eee46bb32dca090548f5f36baa7d4db0bcf4c Mon Sep 17 00:00:00 2001 From: appflowy <annie@appflowy.io> Date: Sun, 27 Mar 2022 11:14:21 +0800 Subject: [PATCH] chore: duplicate and hide field --- .../grid/field/create_field_bloc.dart | 1 + .../grid/field/edit_field_bloc.dart | 31 +- .../application/grid/field/field_service.dart | 26 +- .../plugins/grid/src/grid_page.dart | 2 +- .../src/widgets/header/edit_field_pannel.dart | 26 +- .../widgets/header/field_operation_list.dart | 31 +- .../grid/src/widgets/header/header.dart | 123 ----- .../grid/src/widgets/header/header_cell.dart | 36 -- .../lib/style_widget/button.dart | 3 +- .../dart_event/flowy-grid/dart_event.dart | 21 +- .../flowy-grid-data-model/grid.pb.dart | 122 +++++ .../flowy-grid-data-model/grid.pbjson.dart | 22 + .../protobuf/flowy-grid/event_map.pbenum.dart | 4 +- .../protobuf/flowy-grid/event_map.pbjson.dart | 5 +- .../rust-lib/flowy-grid/src/event_handler.rs | 17 +- frontend/rust-lib/flowy-grid/src/event_map.rs | 12 +- .../src/protobuf/model/event_map.rs | 15 +- .../src/protobuf/proto/event_map.proto | 3 +- .../flowy-grid/src/services/grid_editor.rs | 11 +- .../src/entities/grid.rs | 31 ++ .../src/protobuf/model/grid.rs | 489 ++++++++++++++++-- .../src/protobuf/proto/grid.proto | 8 + .../src/client_grid/grid_meta_pad.rs | 83 +-- 23 files changed, 835 insertions(+), 287 deletions(-) delete mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart delete mode 100755 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header_cell.dart diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/create_field_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/create_field_bloc.dart index 29f7187c2f..6a5a276214 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/create_field_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/create_field_bloc.dart @@ -62,6 +62,7 @@ class CreateFieldBloc extends Bloc<CreateFieldEvent, CreateFieldState> { emit(state.copyWith( field: Some(editContext.gridField), typeOptionData: editContext.typeOptionData, + fieldName: editContext.gridField.name, )); }, (err) => Log.error(err), diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/edit_field_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/edit_field_bloc.dart index 11dbe765fc..6b92b0d0d5 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/edit_field_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/edit_field_bloc.dart @@ -1,3 +1,4 @@ +import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -18,9 +19,27 @@ class EditFieldBloc extends Bloc<EditFieldEvent, EditFieldState> { updateFieldName: (_UpdateFieldName value) { // }, - hideField: (_HideField value) {}, - deleteField: (_DeleteField value) {}, - duplicateField: (_DuplicateField value) {}, + hideField: (_HideField value) async { + final result = await service.updateField(fieldId: value.fieldId, visibility: false); + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }, + deleteField: (_DeleteField value) async { + final result = await service.deleteField(fieldId: value.fieldId); + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }, + duplicateField: (_DuplicateField value) async { + final result = await service.duplicateField(fieldId: value.fieldId); + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }, saveField: (_SaveField value) {}, ); }, @@ -37,9 +56,9 @@ class EditFieldBloc extends Bloc<EditFieldEvent, EditFieldState> { class EditFieldEvent with _$EditFieldEvent { const factory EditFieldEvent.initial() = _InitialField; const factory EditFieldEvent.updateFieldName(String name) = _UpdateFieldName; - const factory EditFieldEvent.hideField() = _HideField; - const factory EditFieldEvent.duplicateField() = _DuplicateField; - const factory EditFieldEvent.deleteField() = _DeleteField; + const factory EditFieldEvent.hideField(String fieldId) = _HideField; + const factory EditFieldEvent.duplicateField(String fieldId) = _DuplicateField; + const factory EditFieldEvent.deleteField(String fieldId) = _DeleteField; const factory EditFieldEvent.saveField() = _SaveField; } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index 84566da604..6824ce0b1b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -21,7 +21,7 @@ class FieldService { } Future<Either<Unit, FlowyError>> updateField({ - required Field field, + required String fieldId, String? name, FieldType? fieldType, bool? frozen, @@ -29,7 +29,9 @@ class FieldService { double? width, List<int>? typeOptionData, }) { - var payload = FieldChangesetPayload.create()..gridId = gridId; + var payload = FieldChangesetPayload.create() + ..gridId = gridId + ..fieldId = fieldId; if (name != null) { payload.name = name; @@ -74,6 +76,26 @@ class FieldService { return GridEventCreateField(payload).send(); } + + Future<Either<Unit, FlowyError>> deleteField({ + required String fieldId, + }) { + final payload = FieldIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId; + + return GridEventDeleteField(payload).send(); + } + + Future<Either<Unit, FlowyError>> duplicateField({ + required String fieldId, + }) { + final payload = FieldIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId; + + return GridEventDuplicateField(payload).send(); + } } class GridFieldData extends Equatable { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index 5cd23accc6..e1c44c253b 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -13,7 +13,7 @@ import 'layout/layout.dart'; import 'layout/sizes.dart'; import 'widgets/content/grid_row.dart'; import 'widgets/footer/grid_footer.dart'; -import 'widgets/header/header.dart'; +import 'widgets/header/grid_header.dart'; class GridPage extends StatefulWidget { final View view; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/edit_field_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/edit_field_pannel.dart index 47affb67e8..ce542b6760 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/edit_field_pannel.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/edit_field_pannel.dart @@ -2,7 +2,6 @@ import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -38,9 +37,7 @@ class EditFieldPannel extends StatelessWidget { const VSpace(6), const _FieldTypeSwitcher(), const VSpace(6), - FieldOperationList( - onDismiss: () => FlowyOverlay.of(context).remove(identifier()), - ), + _FieldOperationList(fieldData, () => FlowyOverlay.of(context).remove(identifier())), ], ), ), @@ -52,6 +49,27 @@ class EditFieldPannel extends StatelessWidget { } } +class _FieldOperationList extends StatelessWidget { + final GridFieldData fieldData; + final VoidCallback onDismissed; + const _FieldOperationList(this.fieldData, this.onDismissed, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final actions = FieldAction.values + .map( + (action) => FieldActionItem( + fieldId: fieldData.field.id, + action: action, + onTap: onDismissed, + ), + ) + .toList(); + + return FieldOperationList(actions: actions); + } +} + class _FieldTypeSwitcher extends StatelessWidget { const _FieldTypeSwitcher({Key? key}) : super(key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_operation_list.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_operation_list.dart index fb639e5f5b..ddf5eb7660 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_operation_list.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_operation_list.dart @@ -9,17 +9,11 @@ import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class FieldOperationList extends StatelessWidget { - final VoidCallback onDismiss; - const FieldOperationList({required this.onDismiss, Key? key}) : super(key: key); + final List<FieldActionItem> actions; + const FieldOperationList({required this.actions, Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final children = FieldAction.values - .map((action) => FieldActionItem( - action: action, - onTap: onDismiss, - )) - .toList(); return GridView( // https://api.flutter.dev/flutter/widgets/AnimatedList/shrinkWrap.html shrinkWrap: true, @@ -28,15 +22,22 @@ class FieldOperationList extends StatelessWidget { childAspectRatio: 4.0, mainAxisSpacing: 8, ), - children: children, + children: actions, ); } } class FieldActionItem extends StatelessWidget { + final String fieldId; final VoidCallback onTap; final FieldAction action; - const FieldActionItem({required this.action, required this.onTap, Key? key}) : super(key: key); + + const FieldActionItem({ + required this.fieldId, + required this.action, + required this.onTap, + Key? key, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -45,7 +46,7 @@ class FieldActionItem extends StatelessWidget { text: FlowyText.medium(action.title(), fontSize: 12), hoverColor: theme.hover, onTap: () { - action.run(context); + action.run(context, fieldId); onTap(); }, leftIcon: svg(action.iconName(), color: theme.iconColor), @@ -82,16 +83,16 @@ extension _FieldActionExtension on FieldAction { } } - void run(BuildContext context) { + void run(BuildContext context, String fieldId) { switch (this) { case FieldAction.hide: - context.read<EditFieldBloc>().add(const EditFieldEvent.hideField()); + context.read<EditFieldBloc>().add(EditFieldEvent.hideField(fieldId)); break; case FieldAction.duplicate: - context.read<EditFieldBloc>().add(const EditFieldEvent.duplicateField()); + context.read<EditFieldBloc>().add(EditFieldEvent.duplicateField(fieldId)); break; case FieldAction.delete: - context.read<EditFieldBloc>().add(const EditFieldEvent.deleteField()); + context.read<EditFieldBloc>().add(EditFieldEvent.deleteField(fieldId)); break; } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart deleted file mode 100644 index dbebb311b9..0000000000 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart +++ /dev/null @@ -1,123 +0,0 @@ -import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/workspace/application/grid/prelude.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; -import 'package:flowy_infra/image.dart'; -import 'package:flowy_infra/theme.dart'; -import 'package:flowy_infra_ui/style_widget/button.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -import 'create_field_pannel.dart'; -import 'header_cell.dart'; - -class GridHeaderDelegate extends SliverPersistentHeaderDelegate { - final String gridId; - final List<Field> fields; - - GridHeaderDelegate({required this.gridId, required this.fields}); - - @override - Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - return GridHeader(gridId: gridId, fields: fields, key: ObjectKey(fields)); - } - - @override - double get maxExtent => GridSize.headerHeight; - - @override - double get minExtent => GridSize.headerHeight; - - @override - bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { - if (oldDelegate is GridHeaderDelegate) { - return fields != oldDelegate.fields; - } - return false; - } -} - -class GridHeader extends StatelessWidget { - final List<Field> fields; - final String gridId; - const GridHeader({required this.gridId, required this.fields, Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final theme = context.watch<AppTheme>(); - return BlocProvider( - create: (context) { - final bloc = getIt<GridHeaderBloc>(param1: gridId, param2: fields); - bloc.add(const GridHeaderEvent.initial()); - return bloc; - }, - child: BlocBuilder<GridHeaderBloc, GridHeaderState>( - builder: (context, state) { - final cells = state.fields.map( - (field) => HeaderCell( - GridFieldData(gridId: gridId, field: field), - ), - ); - - final row = Row( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const _HeaderLeading(), - ...cells, - _HeaderTrailing(gridId: gridId), - ], - ); - - return Container(color: theme.surface, child: row); - }, - ), - ); - } -} - -class _HeaderLeading extends StatelessWidget { - const _HeaderLeading({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return SizedBox( - width: GridSize.leadingHeaderPadding, - ); - } -} - -class _HeaderTrailing extends StatelessWidget { - final String gridId; - const _HeaderTrailing({required this.gridId, Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final theme = context.watch<AppTheme>(); - final borderSide = BorderSide(color: theme.shader4, width: 0.4); - return Container( - width: GridSize.trailHeaderPadding, - decoration: BoxDecoration( - border: Border(top: borderSide, bottom: borderSide), - ), - padding: GridSize.headerContentInsets, - child: CreateFieldButton(gridId: gridId), - ); - } -} - -class CreateFieldButton extends StatelessWidget { - final String gridId; - const CreateFieldButton({required this.gridId, Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final theme = context.watch<AppTheme>(); - return FlowyButton( - text: const FlowyText.medium('New column', fontSize: 12), - hoverColor: theme.hover, - onTap: () => CreateFieldPannel(gridId: gridId).show(context, gridId), - leftIcon: svg("home/add"), - ); - } -} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header_cell.dart deleted file mode 100755 index 52e7e38d75..0000000000 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header_cell.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; -import 'package:flowy_infra/image.dart'; -import 'package:flowy_infra/theme.dart'; -import 'package:flowy_infra_ui/style_widget/button.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -import 'edit_field_pannel.dart'; - -class HeaderCell extends StatelessWidget { - final GridFieldData fieldData; - const HeaderCell(this.fieldData, {Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final theme = context.watch<AppTheme>(); - final button = FlowyButton( - hoverColor: theme.hover, - onTap: () => EditFieldPannel.show(context, fieldData), - rightIcon: svg("editor/details", color: theme.iconColor), - text: Padding(padding: GridSize.cellContentInsets, child: FlowyText.medium(fieldData.field.name, fontSize: 12)), - ); - - final borderSide = BorderSide(color: theme.shader4, width: 0.4); - final decoration = BoxDecoration(border: Border(top: borderSide, right: borderSide, bottom: borderSide)); - - return Container( - width: fieldData.field.width.toDouble(), - decoration: decoration, - padding: GridSize.headerContentInsets, - child: button, - ); - } -} diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart index 78d65a9941..0bcd05f56e 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart @@ -40,10 +40,9 @@ class FlowyButton extends StatelessWidget { children.add(const HSpace(6)); } - children.add(text); + children.add(Expanded(child: text)); if (rightIcon != null) { - children.add(const Spacer()); children.add(SizedBox.fromSize(size: const Size.square(16), child: rightIcon!)); children.add(const HSpace(6)); } diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart index 0c3d242c37..7f25329284 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart @@ -53,7 +53,7 @@ class GridEventGetFields { } class GridEventUpdateField { - FieldChangeset request; + FieldChangesetPayload request; GridEventUpdateField(this.request); Future<Either<Unit, FlowyError>> send() { @@ -87,7 +87,7 @@ class GridEventCreateField { } class GridEventDeleteField { - FieldOrder request; + FieldIdentifierPayload request; GridEventDeleteField(this.request); Future<Either<Unit, FlowyError>> send() { @@ -103,6 +103,23 @@ class GridEventDeleteField { } } +class GridEventDuplicateField { + FieldIdentifierPayload request; + GridEventDuplicateField(this.request); + + Future<Either<Unit, FlowyError>> send() { + final request = FFIRequest.create() + ..event = GridEvent.DuplicateField.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + class GridEventCreateEditFieldContext { CreateEditFieldContextParams request; GridEventCreateEditFieldContext(this.request); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart index 4ea447d729..bd9afe2243 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart @@ -205,6 +205,128 @@ class Field extends $pb.GeneratedMessage { void clearWidth() => clearField(7); } +class FieldIdentifierPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldIdentifierPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..hasRequiredFields = false + ; + + FieldIdentifierPayload._() : super(); + factory FieldIdentifierPayload({ + $core.String? fieldId, + $core.String? gridId, + }) { + final _result = create(); + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (gridId != null) { + _result.gridId = gridId; + } + return _result; + } + factory FieldIdentifierPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory FieldIdentifierPayload.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') + FieldIdentifierPayload clone() => FieldIdentifierPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + FieldIdentifierPayload copyWith(void Function(FieldIdentifierPayload) updates) => super.copyWith((message) => updates(message as FieldIdentifierPayload)) as FieldIdentifierPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static FieldIdentifierPayload create() => FieldIdentifierPayload._(); + FieldIdentifierPayload createEmptyInstance() => create(); + static $pb.PbList<FieldIdentifierPayload> createRepeated() => $pb.PbList<FieldIdentifierPayload>(); + @$core.pragma('dart2js:noInline') + static FieldIdentifierPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FieldIdentifierPayload>(create); + static FieldIdentifierPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get fieldId => $_getSZ(0); + @$pb.TagNumber(1) + set fieldId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasFieldId() => $_has(0); + @$pb.TagNumber(1) + void clearFieldId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get gridId => $_getSZ(1); + @$pb.TagNumber(2) + set gridId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasGridId() => $_has(1); + @$pb.TagNumber(2) + void clearGridId() => clearField(2); +} + +class FieldIdentifierParams extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldIdentifierParams', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..hasRequiredFields = false + ; + + FieldIdentifierParams._() : super(); + factory FieldIdentifierParams({ + $core.String? fieldId, + $core.String? gridId, + }) { + final _result = create(); + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (gridId != null) { + _result.gridId = gridId; + } + return _result; + } + factory FieldIdentifierParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory FieldIdentifierParams.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') + FieldIdentifierParams clone() => FieldIdentifierParams()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + FieldIdentifierParams copyWith(void Function(FieldIdentifierParams) updates) => super.copyWith((message) => updates(message as FieldIdentifierParams)) as FieldIdentifierParams; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static FieldIdentifierParams create() => FieldIdentifierParams._(); + FieldIdentifierParams createEmptyInstance() => create(); + static $pb.PbList<FieldIdentifierParams> createRepeated() => $pb.PbList<FieldIdentifierParams>(); + @$core.pragma('dart2js:noInline') + static FieldIdentifierParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FieldIdentifierParams>(create); + static FieldIdentifierParams? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get fieldId => $_getSZ(0); + @$pb.TagNumber(1) + set fieldId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasFieldId() => $_has(0); + @$pb.TagNumber(1) + void clearFieldId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get gridId => $_getSZ(1); + @$pb.TagNumber(2) + set gridId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasGridId() => $_has(1); + @$pb.TagNumber(2) + void clearGridId() => clearField(2); +} + class FieldOrder extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldOrder', createEmptyInstance: create) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart index a7dc3255c8..0b900d46f9 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart @@ -36,6 +36,28 @@ const Field$json = const { /// Descriptor for `Field`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List fieldDescriptor = $convert.base64Decode('CgVGaWVsZBIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRkZXNjGAMgASgJUgRkZXNjEikKCmZpZWxkX3R5cGUYBCABKA4yCi5GaWVsZFR5cGVSCWZpZWxkVHlwZRIWCgZmcm96ZW4YBSABKAhSBmZyb3plbhIeCgp2aXNpYmlsaXR5GAYgASgIUgp2aXNpYmlsaXR5EhQKBXdpZHRoGAcgASgFUgV3aWR0aA=='); +@$core.Deprecated('Use fieldIdentifierPayloadDescriptor instead') +const FieldIdentifierPayload$json = const { + '1': 'FieldIdentifierPayload', + '2': const [ + const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'grid_id', '3': 2, '4': 1, '5': 9, '10': 'gridId'}, + ], +}; + +/// Descriptor for `FieldIdentifierPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fieldIdentifierPayloadDescriptor = $convert.base64Decode('ChZGaWVsZElkZW50aWZpZXJQYXlsb2FkEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhcKB2dyaWRfaWQYAiABKAlSBmdyaWRJZA=='); +@$core.Deprecated('Use fieldIdentifierParamsDescriptor instead') +const FieldIdentifierParams$json = const { + '1': 'FieldIdentifierParams', + '2': const [ + const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'grid_id', '3': 2, '4': 1, '5': 9, '10': 'gridId'}, + ], +}; + +/// Descriptor for `FieldIdentifierParams`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fieldIdentifierParamsDescriptor = $convert.base64Decode('ChVGaWVsZElkZW50aWZpZXJQYXJhbXMSGQoIZmllbGRfaWQYASABKAlSB2ZpZWxkSWQSFwoHZ3JpZF9pZBgCIAEoCVIGZ3JpZElk'); @$core.Deprecated('Use fieldOrderDescriptor instead') const FieldOrder$json = const { '1': 'FieldOrder', diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart index 755b1c1ed1..46291923e0 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart @@ -16,7 +16,8 @@ class GridEvent extends $pb.ProtobufEnum { static const GridEvent UpdateField = GridEvent._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateField'); static const GridEvent CreateField = GridEvent._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateField'); static const GridEvent DeleteField = GridEvent._(13, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteField'); - static const GridEvent CreateEditFieldContext = GridEvent._(14, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateEditFieldContext'); + static const GridEvent DuplicateField = GridEvent._(15, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField'); + static const GridEvent CreateEditFieldContext = GridEvent._(16, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateEditFieldContext'); static const GridEvent CreateRow = GridEvent._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateRow'); static const GridEvent GetRow = GridEvent._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetRow'); static const GridEvent UpdateCell = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCell'); @@ -28,6 +29,7 @@ class GridEvent extends $pb.ProtobufEnum { UpdateField, CreateField, DeleteField, + DuplicateField, CreateEditFieldContext, CreateRow, GetRow, diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart index 9441a03bea..278e0b14c3 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart @@ -18,7 +18,8 @@ const GridEvent$json = const { const {'1': 'UpdateField', '2': 11}, const {'1': 'CreateField', '2': 12}, const {'1': 'DeleteField', '2': 13}, - const {'1': 'CreateEditFieldContext', '2': 14}, + const {'1': 'DuplicateField', '2': 15}, + const {'1': 'CreateEditFieldContext', '2': 16}, const {'1': 'CreateRow', '2': 21}, const {'1': 'GetRow', '2': 22}, const {'1': 'UpdateCell', '2': 30}, @@ -26,4 +27,4 @@ const GridEvent$json = const { }; /// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtDcmVhdGVGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SGgoWQ3JlYXRlRWRpdEZpZWxkQ29udGV4dBAOEg0KCUNyZWF0ZVJvdxAVEgoKBkdldFJvdxAWEg4KClVwZGF0ZUNlbGwQHg=='); +final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtDcmVhdGVGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEgoORHVwbGljYXRlRmllbGQQDxIaChZDcmVhdGVFZGl0RmllbGRDb250ZXh0EBASDQoJQ3JlYXRlUm93EBUSCgoGR2V0Um93EBYSDgoKVXBkYXRlQ2VsbBAe'); diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index e16c761cb2..97b91e5557 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -68,12 +68,23 @@ pub(crate) async fn create_field_handler( #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn delete_field_handler( - data: Data<FieldOrder>, + data: Data<FieldIdentifierPayload>, manager: AppData<Arc<GridManager>>, ) -> Result<(), FlowyError> { - let field_order: FieldOrder = data.into_inner(); + let params: FieldIdentifierParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; - let _ = editor.delete_field(&field_order.field_id).await?; + let _ = editor.delete_field(¶ms.field_id).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn duplicate_field_handler( + data: Data<FieldIdentifierPayload>, + manager: AppData<Arc<GridManager>>, +) -> Result<(), FlowyError> { + let params: FieldIdentifierParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let _ = editor.duplicate_field(¶ms.field_id).await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index 9819f2142e..efe5ddc094 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -13,7 +13,8 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module { .event(GridEvent::GetFields, get_fields_handler) .event(GridEvent::UpdateField, update_field_handler) .event(GridEvent::CreateField, create_field_handler) - .event(GridEvent::DeleteField, create_field_handler) + .event(GridEvent::DeleteField, delete_field_handler) + .event(GridEvent::DuplicateField, duplicate_field_handler) .event(GridEvent::CreateEditFieldContext, create_edit_field_context_handler) .event(GridEvent::CreateRow, create_row_handler) .event(GridEvent::GetRow, get_row_handler) @@ -34,17 +35,20 @@ pub enum GridEvent { #[event(input = "QueryFieldPayload", output = "RepeatedField")] GetFields = 10, - #[event(input = "FieldChangeset")] + #[event(input = "FieldChangesetPayload")] UpdateField = 11, #[event(input = "CreateFieldPayload")] CreateField = 12, - #[event(input = "FieldOrder")] + #[event(input = "FieldIdentifierPayload")] DeleteField = 13, + #[event(input = "FieldIdentifierPayload")] + DuplicateField = 15, + #[event(input = "CreateEditFieldContextParams", output = "EditFieldContext")] - CreateEditFieldContext = 14, + CreateEditFieldContext = 16, #[event(input = "CreateRowPayload", output = "Row")] CreateRow = 21, diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs index dfa0f30b74..13ee0705cc 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs @@ -31,7 +31,8 @@ pub enum GridEvent { UpdateField = 11, CreateField = 12, DeleteField = 13, - CreateEditFieldContext = 14, + DuplicateField = 15, + CreateEditFieldContext = 16, CreateRow = 21, GetRow = 22, UpdateCell = 30, @@ -50,7 +51,8 @@ impl ::protobuf::ProtobufEnum for GridEvent { 11 => ::std::option::Option::Some(GridEvent::UpdateField), 12 => ::std::option::Option::Some(GridEvent::CreateField), 13 => ::std::option::Option::Some(GridEvent::DeleteField), - 14 => ::std::option::Option::Some(GridEvent::CreateEditFieldContext), + 15 => ::std::option::Option::Some(GridEvent::DuplicateField), + 16 => ::std::option::Option::Some(GridEvent::CreateEditFieldContext), 21 => ::std::option::Option::Some(GridEvent::CreateRow), 22 => ::std::option::Option::Some(GridEvent::GetRow), 30 => ::std::option::Option::Some(GridEvent::UpdateCell), @@ -66,6 +68,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { GridEvent::UpdateField, GridEvent::CreateField, GridEvent::DeleteField, + GridEvent::DuplicateField, GridEvent::CreateEditFieldContext, GridEvent::CreateRow, GridEvent::GetRow, @@ -98,12 +101,12 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*\xb8\x01\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ + \n\x0fevent_map.proto*\xcc\x01\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ \0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\ \x0bUpdateField\x10\x0b\x12\x0f\n\x0bCreateField\x10\x0c\x12\x0f\n\x0bDe\ - leteField\x10\r\x12\x1a\n\x16CreateEditFieldContext\x10\x0e\x12\r\n\tCre\ - ateRow\x10\x15\x12\n\n\x06GetRow\x10\x16\x12\x0e\n\nUpdateCell\x10\x1eb\ - \x06proto3\ + leteField\x10\r\x12\x12\n\x0eDuplicateField\x10\x0f\x12\x1a\n\x16CreateE\ + ditFieldContext\x10\x10\x12\r\n\tCreateRow\x10\x15\x12\n\n\x06GetRow\x10\ + \x16\x12\x0e\n\nUpdateCell\x10\x1eb\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto index 36e5b81d12..327a1e3aee 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto @@ -7,7 +7,8 @@ enum GridEvent { UpdateField = 11; CreateField = 12; DeleteField = 13; - CreateEditFieldContext = 14; + DuplicateField = 15; + CreateEditFieldContext = 16; CreateRow = 21; GetRow = 22; UpdateCell = 30; diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 022dc3bbfa..7ff089ff9b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -110,6 +110,12 @@ impl ClientGridEditor { Ok(()) } + pub async fn duplicate_field(&self, field_id: &str) -> FlowyResult<()> { + let _ = self.modify(|grid| Ok(grid.duplicate_field(field_id)?)).await?; + let _ = self.notify_did_update_fields().await?; + Ok(()) + } + pub async fn create_block(&self, grid_block: GridBlockMeta) -> FlowyResult<()> { let _ = self.modify(|grid| Ok(grid.create_block(grid_block)?)).await?; Ok(()) @@ -254,8 +260,9 @@ impl ClientGridEditor { } pub async fn get_field_metas(&self, field_orders: Option<RepeatedFieldOrder>) -> FlowyResult<Vec<FieldMeta>> { - let field_meta = self.pad.read().await.get_field_metas(field_orders)?; - Ok(field_meta) + let mut field_metas = self.pad.read().await.get_field_metas(field_orders)?; + field_metas.retain(|field_meta| field_meta.visibility); + Ok(field_metas) } pub async fn get_block_meta_data_vec( diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs index 22d03a5993..dfd5dc397f 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -55,6 +55,37 @@ impl std::convert::From<FieldMeta> for Field { } } +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct FieldIdentifierPayload { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub grid_id: String, +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct FieldIdentifierParams { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub grid_id: String, +} + +impl TryInto<FieldIdentifierParams> for FieldIdentifierPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result<FieldIdentifierParams, Self::Error> { + let grid_id = NotEmptyUuid::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyUuid::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + Ok(FieldIdentifierParams { + grid_id: grid_id.0, + field_id: field_id.0, + }) + } +} + #[derive(Debug, Clone, Default, ProtoBuf)] pub struct FieldOrder { #[pb(index = 1)] diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs index a6afa46d9a..c18043184f 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs @@ -659,6 +659,408 @@ impl ::protobuf::reflect::ProtobufValue for Field { } } +#[derive(PartialEq,Clone,Default)] +pub struct FieldIdentifierPayload { + // message fields + pub field_id: ::std::string::String, + pub grid_id: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a FieldIdentifierPayload { + fn default() -> &'a FieldIdentifierPayload { + <FieldIdentifierPayload as ::protobuf::Message>::default_instance() + } +} + +impl FieldIdentifierPayload { + pub fn new() -> FieldIdentifierPayload { + ::std::default::Default::default() + } + + // string field_id = 1; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // string grid_id = 2; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for FieldIdentifierPayload { + fn is_initialized(&self) -> bool { + 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_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + _ => { + ::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; + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.field_id); + } + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.grid_id); + } + 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<()> { + if !self.field_id.is_empty() { + os.write_string(1, &self.field_id)?; + } + if !self.grid_id.is_empty() { + os.write_string(2, &self.grid_id)?; + } + 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() -> FieldIdentifierPayload { + FieldIdentifierPayload::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_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &FieldIdentifierPayload| { &m.field_id }, + |m: &mut FieldIdentifierPayload| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &FieldIdentifierPayload| { &m.grid_id }, + |m: &mut FieldIdentifierPayload| { &mut m.grid_id }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::<FieldIdentifierPayload>( + "FieldIdentifierPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static FieldIdentifierPayload { + static instance: ::protobuf::rt::LazyV2<FieldIdentifierPayload> = ::protobuf::rt::LazyV2::INIT; + instance.get(FieldIdentifierPayload::new) + } +} + +impl ::protobuf::Clear for FieldIdentifierPayload { + fn clear(&mut self) { + self.field_id.clear(); + self.grid_id.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for FieldIdentifierPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for FieldIdentifierPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct FieldIdentifierParams { + // message fields + pub field_id: ::std::string::String, + pub grid_id: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a FieldIdentifierParams { + fn default() -> &'a FieldIdentifierParams { + <FieldIdentifierParams as ::protobuf::Message>::default_instance() + } +} + +impl FieldIdentifierParams { + pub fn new() -> FieldIdentifierParams { + ::std::default::Default::default() + } + + // string field_id = 1; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // string grid_id = 2; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for FieldIdentifierParams { + fn is_initialized(&self) -> bool { + 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_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + _ => { + ::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; + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.field_id); + } + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.grid_id); + } + 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<()> { + if !self.field_id.is_empty() { + os.write_string(1, &self.field_id)?; + } + if !self.grid_id.is_empty() { + os.write_string(2, &self.grid_id)?; + } + 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() -> FieldIdentifierParams { + FieldIdentifierParams::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_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &FieldIdentifierParams| { &m.field_id }, + |m: &mut FieldIdentifierParams| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &FieldIdentifierParams| { &m.grid_id }, + |m: &mut FieldIdentifierParams| { &mut m.grid_id }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::<FieldIdentifierParams>( + "FieldIdentifierParams", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static FieldIdentifierParams { + static instance: ::protobuf::rt::LazyV2<FieldIdentifierParams> = ::protobuf::rt::LazyV2::INIT; + instance.get(FieldIdentifierParams::new) + } +} + +impl ::protobuf::Clear for FieldIdentifierParams { + fn clear(&mut self) { + self.field_id.clear(); + self.grid_id.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for FieldIdentifierParams { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for FieldIdentifierParams { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + #[derive(PartialEq,Clone,Default)] pub struct FieldOrder { // message fields @@ -4865,48 +5267,51 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12)\n\nfield_type\x18\x04\x20\ \x01(\x0e2\n.FieldTypeR\tfieldType\x12\x16\n\x06frozen\x18\x05\x20\x01(\ \x08R\x06frozen\x12\x1e\n\nvisibility\x18\x06\x20\x01(\x08R\nvisibility\ - \x12\x14\n\x05width\x18\x07\x20\x01(\x05R\x05width\"'\n\nFieldOrder\x12\ - \x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\"b\n\x1cCreateEditFiel\ - dContextParams\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12)\n\ - \nfield_type\x18\x02\x20\x01(\x0e2\n.FieldTypeR\tfieldType\"|\n\x10EditF\ - ieldContext\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ng\ - rid_field\x18\x02\x20\x01(\x0b2\x06.FieldR\tgridField\x12(\n\x10type_opt\ - ion_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\"-\n\rRepeatedField\x12\ - \x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12Repeat\ - edFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\x05it\ - ems\"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05rowId\ - \x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06heigh\ - t\x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\ - \x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\ - \x17.Row.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x03\ - \x20\x01(\x05R\x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03key\ - \x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05\ - .CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\ - \x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05\ - items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"+\n\x0eGridBlockOrder\ - \x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\"E\n\tGridBlock\ - \x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12(\n\nrow_orders\x18\x02\ - \x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\x04Cell\x12\x19\n\x08field_id\ - \x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07content\x18\x02\x20\x01(\tR\ - \x07content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b\ - 2\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\"#\n\x0bGridBlockId\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\x0cstart_row_id\x18\x02\x20\x01(\tH\0R\nstart\ - RowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12CreateFieldPayload\ - \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05field\ - \x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\x12(\n\x10type_option_data\ - \x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\n\x0estart_field_id\x18\ - \x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_field_id\"d\n\ - \x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\ - \x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\ - \x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\ - \x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\ - \x0f.GridBlockOrderR\x0bblockOrders\"\\\n\x0fQueryRowPayload\x12\x17\n\ - \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08block_id\x18\x02\ - \x20\x01(\tR\x07blockId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowId\ - b\x06proto3\ + \x12\x14\n\x05width\x18\x07\x20\x01(\x05R\x05width\"L\n\x16FieldIdentifi\ + erPayload\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\ + \x07grid_id\x18\x02\x20\x01(\tR\x06gridId\"K\n\x15FieldIdentifierParams\ + \x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_\ + id\x18\x02\x20\x01(\tR\x06gridId\"'\n\nFieldOrder\x12\x19\n\x08field_id\ + \x18\x01\x20\x01(\tR\x07fieldId\"b\n\x1cCreateEditFieldContextParams\x12\ + \x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12)\n\nfield_type\x18\ + \x02\x20\x01(\x0e2\n.FieldTypeR\tfieldType\"|\n\x10EditFieldContext\x12\ + \x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngrid_field\x18\ + \x02\x20\x01(\x0b2\x06.FieldR\tgridField\x12(\n\x10type_option_data\x18\ + \x03\x20\x01(\x0cR\x0etypeOptionData\"-\n\rRepeatedField\x12\x1c\n\x05it\ + ems\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12RepeatedFieldOrder\ + \x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\x05items\"T\n\x08\ + RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05rowId\x12\x19\n\x08b\ + lock_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06height\x18\x03\x20\ + \x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\ + \tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\x17.Row.CellB\ + yFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\ + \x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01\ + (\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\ + \x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\ + \x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05items\x18\x01\ + \x20\x03(\x0b2\n.GridBlockR\x05items\"+\n\x0eGridBlockOrder\x12\x19\n\ + \x08block_id\x18\x01\x20\x01(\tR\x07blockId\"E\n\tGridBlock\x12\x0e\n\ + \x02id\x18\x01\x20\x01(\tR\x02id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b\ + 2\t.RowOrderR\trowOrders\";\n\x04Cell\x12\x19\n\x08field_id\x18\x01\x20\ + \x01(\tR\x07fieldId\x12\x18\n\x07content\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(\t\ + R\x04name\"\x1e\n\x06GridId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05va\ + lue\"#\n\x0bGridBlockId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\ + \"f\n\x10CreateRowPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gr\ + idId\x12\"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\ + \x13one_of_start_row_id\"\xb6\x01\n\x12CreateFieldPayload\x12\x17\n\x07g\ + rid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\ + \x0b2\x06.FieldR\x05field\x12(\n\x10type_option_data\x18\x03\x20\x01(\ + \x0cR\x0etypeOptionData\x12&\n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\ + \x0cstartFieldIdB\x17\n\x15one_of_start_field_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\"e\n\ + \x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06g\ + ridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\ + \x0bblockOrders\"\\\n\x0fQueryRowPayload\x12\x17\n\x07grid_id\x18\x01\ + \x20\x01(\tR\x06gridId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07bloc\ + kId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowIdb\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto index ec109f580f..3a74e23026 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto +++ b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto @@ -15,6 +15,14 @@ message Field { bool visibility = 6; int32 width = 7; } +message FieldIdentifierPayload { + string field_id = 1; + string grid_id = 2; +} +message FieldIdentifierParams { + string field_id = 1; + string grid_id = 2; +} message FieldOrder { string field_id = 1; } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index e1712d2584..78c0091b57 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -72,42 +72,17 @@ impl GridMetaPad { }) } - pub fn contain_field(&self, field_id: &str) -> bool { - self.grid_meta.fields.iter().any(|field| field.id == field_id) - } - - pub fn get_field(&self, field_id: &str) -> Option<&FieldMeta> { - self.grid_meta.fields.iter().find(|field| field.id == field_id) - } - - pub fn get_field_orders(&self) -> Vec<FieldOrder> { - self.grid_meta.fields.iter().map(FieldOrder::from).collect() - } - - pub fn get_field_metas(&self, field_orders: Option<RepeatedFieldOrder>) -> CollaborateResult<Vec<FieldMeta>> { - match field_orders { - None => Ok(self.grid_meta.fields.clone()), - Some(field_orders) => { - let field_by_field_id = self - .grid_meta - .fields - .iter() - .map(|field| (&field.id, field)) - .collect::<HashMap<&String, &FieldMeta>>(); - - let fields = field_orders - .iter() - .flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) { - None => { - tracing::error!("Can't find the field with id: {}", field_order.field_id); - None - } - Some(field) => Some((*field).clone()), - }) - .collect::<Vec<FieldMeta>>(); - Ok(fields) + pub fn duplicate_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) => { + let mut duplicate_field_meta = grid.fields[index].clone(); + duplicate_field_meta.id = uuid(); + duplicate_field_meta.name = format!("{} (copy)", duplicate_field_meta.name); + grid.fields.insert(index + 1, duplicate_field_meta); + Ok(Some(())) } - } + }) } pub fn update_field(&mut self, changeset: FieldChangesetParams) -> CollaborateResult<Option<GridChangeset>> { @@ -160,6 +135,44 @@ impl GridMetaPad { }) } + pub fn get_field(&self, field_id: &str) -> Option<&FieldMeta> { + self.grid_meta.fields.iter().find(|field| field.id == field_id) + } + + pub fn contain_field(&self, field_id: &str) -> bool { + self.grid_meta.fields.iter().any(|field| field.id == field_id) + } + + pub fn get_field_orders(&self) -> Vec<FieldOrder> { + self.grid_meta.fields.iter().map(FieldOrder::from).collect() + } + + pub fn get_field_metas(&self, field_orders: Option<RepeatedFieldOrder>) -> CollaborateResult<Vec<FieldMeta>> { + match field_orders { + None => Ok(self.grid_meta.fields.clone()), + Some(field_orders) => { + let field_by_field_id = self + .grid_meta + .fields + .iter() + .map(|field| (&field.id, field)) + .collect::<HashMap<&String, &FieldMeta>>(); + + let fields = field_orders + .iter() + .flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) { + None => { + tracing::error!("Can't find the field with id: {}", field_order.field_id); + None + } + Some(field) => Some((*field).clone()), + }) + .collect::<Vec<FieldMeta>>(); + Ok(fields) + } + } + } + pub fn create_block(&mut self, block: GridBlockMeta) -> CollaborateResult<Option<GridChangeset>> { self.modify_grid(|grid| { if grid.block_metas.iter().any(|b| b.block_id == block.block_id) {