From eeba6884ce309479e3a49c6d73f4512ee7c3b636 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 20 Apr 2022 16:32:12 +0800 Subject: [PATCH] chore: config row detail page --- .../app_flowy/assets/images/grid/expander.svg | 6 + .../application/grid/row/row_detail_bloc.dart | 73 +++++++ .../application/grid/row/row_service.dart | 44 ++-- .../plugins/grid/src/grid_page.dart | 6 +- .../grid/src/widgets/cell/cell_container.dart | 60 +++++- .../header/field_cell_action_sheet.dart | 44 ++-- .../grid/src/widgets/row/grid_row.dart | 150 +++++++++---- .../grid/src/widgets/row/row_detail.dart | 48 +++++ .../src/widgets/toolbar/grid_property.dart | 2 +- .../flowy-grid-data-model/grid.pb.dart | 14 ++ .../flowy-grid-data-model/grid.pbjson.dart | 3 +- .../src/services/field/field_builder.rs | 8 +- .../flowy-grid/src/services/grid_editor.rs | 5 +- frontend/rust-lib/flowy-grid/src/util.rs | 1 + .../rust-lib/flowy-grid/tests/grid/script.rs | 2 + .../src/entities/grid.rs | 4 + .../src/entities/meta.rs | 13 +- .../src/protobuf/model/grid.rs | 202 +++++++++++------- .../src/protobuf/proto/grid.proto | 1 + .../src/client_grid/grid_builder.rs | 4 +- 20 files changed, 506 insertions(+), 184 deletions(-) create mode 100644 frontend/app_flowy/assets/images/grid/expander.svg create mode 100644 frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart create mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart diff --git a/frontend/app_flowy/assets/images/grid/expander.svg b/frontend/app_flowy/assets/images/grid/expander.svg new file mode 100644 index 0000000000..179bdb1a9e --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/expander.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart new file mode 100644 index 0000000000..e93f0be89b --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart @@ -0,0 +1,73 @@ +import 'dart:collection'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; +import 'row_service.dart'; +import 'package:dartz/dartz.dart'; + +part 'row_detail_bloc.freezed.dart'; + +class RowDetailBloc extends Bloc { + final GridRow rowData; + final GridRowCache _rowCache; + void Function()? _rowListenFn; + + RowDetailBloc({ + required this.rowData, + required GridRowCache rowCache, + }) : _rowCache = rowCache, + super(RowDetailState.initial()) { + on( + (event, emit) async { + await event.map( + initial: (_Initial value) async { + await _startListening(); + }, + didReceiveCellDatas: (_DidReceiveCellDatas value) {}, + ); + }, + ); + } + + @override + Future close() async { + if (_rowListenFn != null) { + _rowCache.removeRowListener(_rowListenFn!); + } + return super.close(); + } + + Future _startListening() async { + _rowListenFn = _rowCache.addRowListener( + rowId: rowData.rowId, + onUpdated: (cellDatas) => add(RowDetailEvent.didReceiveCellDatas(cellDatas)), + listenWhen: () => !isClosed, + ); + } + + Future _loadRow(Emitter emit) async { + final data = _rowCache.loadCellData(rowData.rowId); + data.foldRight(null, (cellDatas, _) { + if (!isClosed) { + add(RowDetailEvent.didReceiveCellDatas(cellDatas)); + } + }); + } +} + +@freezed +class RowDetailEvent with _$RowDetailEvent { + const factory RowDetailEvent.initial() = _Initial; + const factory RowDetailEvent.didReceiveCellDatas(CellDataMap cellData) = _DidReceiveCellDatas; +} + +@freezed +class RowDetailState with _$RowDetailState { + const factory RowDetailState({ + required Option cellDataMap, + }) = _RowDetailState; + + factory RowDetailState.initial() => RowDetailState( + cellDataMap: none(), + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart index 63129f4015..f524e03d0c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart @@ -42,9 +42,9 @@ class GridRowCache { result.fold( (changesets) { for (final changeset in changesets) { - _deleteRows(changeset.deletedRows); - _insertRows(changeset.insertedRows); - _updateRows(changeset.updatedRows); + _rowNotifier.deleteRows(changeset.deletedRows); + _rowNotifier.insertRows(changeset.insertedRows); + _rowNotifier.updateRows(changeset.updatedRows); } }, (err) => Log.error(err), @@ -63,13 +63,15 @@ class GridRowCache { bool Function()? listenWhen, }) { _rowNotifier.addListener(() { + if (onChanged == null) { + return; + } + if (listenWhen != null && listenWhen() == false) { return; } - if (onChanged != null) { - onChanged(clonedRows, _rowNotifier._changeReason); - } + onChanged(clonedRows, _rowNotifier._changeReason); }); } @@ -136,18 +138,6 @@ class GridRowCache { final rowOrders = blocks.expand((block) => block.rowOrders).toList(); _rowNotifier.reset(rowOrders); } - - void _deleteRows(List deletedRows) { - _rowNotifier.deleteRows(deletedRows); - } - - void _insertRows(List createdRows) { - _rowNotifier.insertRows(createdRows); - } - - void _updateRows(List rowOrders) { - _rowNotifier.updateRows(rowOrders); - } } class RowsNotifier extends ChangeNotifier { @@ -173,7 +163,7 @@ class RowsNotifier extends ChangeNotifier { final List newRows = []; final DeletedIndexs deletedIndex = []; - final Map deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder}; + final Map deletedRowMap = {for (var e in deletedRows) e.rowId: e}; _rows.asMap().forEach((index, row) { if (deletedRowMap[row.rowId] == null) { @@ -192,12 +182,14 @@ class RowsNotifier extends ChangeNotifier { } InsertedIndexs insertIndexs = []; - final List newRows = _rows; + final List newRows = clonedRows; for (final createdRow in createdRows) { - final rowOrder = createdRow.rowOrder; - final insertIndex = InsertedIndex(index: createdRow.index, rowId: rowOrder.rowId); + final insertIndex = InsertedIndex( + index: createdRow.index, + rowId: createdRow.rowOrder.rowId, + ); insertIndexs.add(insertIndex); - newRows.insert(createdRow.index, (rowBuilder(rowOrder))); + newRows.insert(createdRow.index, (rowBuilder(createdRow.rowOrder))); } _update(newRows, GridRowChangeReason.insert(insertIndexs)); } @@ -208,15 +200,15 @@ class RowsNotifier extends ChangeNotifier { } final UpdatedIndexs updatedIndexs = UpdatedIndexs(); - final List newRows = _rows; + final List newRows = clonedRows; for (final rowOrder in updatedRows) { final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId); if (index != -1) { - newRows.removeAt(index); // Remove the old row data, the data will be filled if the loadRow method gets called. _rowDataMap.remove(rowOrder.rowId); - newRows.insert(index, rowBuilder(rowOrder)); + newRows.removeAt(index); + newRows.insert(index, rowBuilder(rowOrder)); updatedIndexs[rowOrder.rowId] = UpdatedIndex(index: index, rowId: rowOrder.rowId); } } 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 12b9f8963f..b3d35977b8 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 @@ -231,10 +231,8 @@ class _GridRowsState extends State<_GridRows> { return SizeTransition( sizeFactor: animation, child: GridRowWidget( - blocBuilder: () => RowBloc( - rowData: rowData, - rowCache: rowCache, - ), + rowData: rowData, + rowCache: rowCache, key: ValueKey(rowData.rowId), ), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart index e49928f7ac..243edae3a9 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart @@ -6,6 +6,7 @@ import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.d class CellStateNotifier extends ChangeNotifier { bool _isFocus = false; + bool _onEnter = false; set isFocus(bool value) { if (_isFocus != value) { @@ -14,38 +15,56 @@ class CellStateNotifier extends ChangeNotifier { } } + set onEnter(bool value) { + if (_onEnter != value) { + _onEnter = value; + notifyListeners(); + } + } + bool get isFocus => _isFocus; + + bool get onEnter => _onEnter; } class CellContainer extends StatelessWidget { final Widget child; + final Widget? expander; final double width; const CellContainer({ Key? key, required this.child, required this.width, + this.expander, }) : super(key: key); @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (_) => CellStateNotifier(), - child: Consumer( - builder: (context, state, _) { + child: Selector( + selector: (context, notifier) => notifier.isFocus, + builder: (context, isFocus, _) { + Widget container = Center(child: child); + + if (expander != null) { + container = _CellEnterRegion(child: container, expander: expander!); + } + return Container( constraints: BoxConstraints(maxWidth: width), - decoration: _makeBoxDecoration(context, state), + decoration: _makeBoxDecoration(context, isFocus), padding: GridSize.cellContentInsets, - child: Center(child: child), + child: container, ); }, ), ); } - BoxDecoration _makeBoxDecoration(BuildContext context, CellStateNotifier state) { + BoxDecoration _makeBoxDecoration(BuildContext context, bool isFocus) { final theme = context.watch(); - if (state.isFocus) { + if (isFocus) { final borderSide = BorderSide(color: theme.main1, width: 1.0); return BoxDecoration(border: Border.fromBorderSide(borderSide)); } else { @@ -55,6 +74,35 @@ class CellContainer extends StatelessWidget { } } +class _CellEnterRegion extends StatelessWidget { + final Widget expander; + final Widget child; + const _CellEnterRegion({required this.expander, required this.child, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Selector( + selector: (context, notifier) => notifier.onEnter, + builder: (context, onEnter, _) { + List children = [child]; + if (onEnter) { + children.add(expander); + } + + return MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (p) => Provider.of(context, listen: false).onEnter = true, + onExit: (p) => Provider.of(context, listen: false).onEnter = false, + child: Stack( + alignment: AlignmentDirectional.centerEnd, + children: children, + ), + ); + }, + ); + } +} + abstract class GridCellWidget extends StatefulWidget { const GridCellWidget({Key? key}) : super(key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart index 2dc1e2976b..3e7f0c9271 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart @@ -90,16 +90,6 @@ class _FieldOperationList extends StatelessWidget { @override Widget build(BuildContext context) { - final actions = FieldAction.values - .map( - (action) => FieldActionCell( - fieldId: fieldData.field.id, - action: action, - onTap: onDismissed, - ), - ) - .toList(); - return GridView( // https://api.flutter.dev/flutter/widgets/AnimatedList/shrinkWrap.html shrinkWrap: true, @@ -108,20 +98,44 @@ class _FieldOperationList extends StatelessWidget { childAspectRatio: 4.0, mainAxisSpacing: 8, ), - children: actions, + children: buildCells(), ); } + + List buildCells() { + return FieldAction.values.map( + (action) { + bool enable = true; + switch (action) { + case FieldAction.delete: + enable = !fieldData.field.isPrimary; + break; + default: + break; + } + + return FieldActionCell( + fieldId: fieldData.field.id, + action: action, + onTap: onDismissed, + enable: enable, + ); + }, + ).toList(); + } } class FieldActionCell extends StatelessWidget { final String fieldId; final VoidCallback onTap; final FieldAction action; + final bool enable; const FieldActionCell({ required this.fieldId, required this.action, required this.onTap, + required this.enable, Key? key, }) : super(key: key); @@ -129,11 +143,13 @@ class FieldActionCell extends StatelessWidget { Widget build(BuildContext context) { final theme = context.watch(); return FlowyButton( - text: FlowyText.medium(action.title(), fontSize: 12), + text: FlowyText.medium(action.title(), fontSize: 12, color: enable ? null : theme.shader4), hoverColor: theme.hover, onTap: () { - action.run(context); - onTap(); + if (enable) { + action.run(context); + onTap(); + } }, leftIcon: svgWidget(action.iconName(), color: theme.iconColor), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart index 316b5ec9c0..5c08bab8c8 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart @@ -8,12 +8,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:provider/provider.dart'; import 'row_action_sheet.dart'; +import 'package:dartz/dartz.dart' show Option; + +import 'row_detail.dart'; class GridRowWidget extends StatefulWidget { - final RowBloc Function() blocBuilder; + final GridRow rowData; + final GridRowCache rowCache; const GridRowWidget({ - required this.blocBuilder, + required this.rowData, + required this.rowCache, Key? key, }) : super(key: key); @@ -23,13 +28,14 @@ class GridRowWidget extends StatefulWidget { class _GridRowWidgetState extends State { late RowBloc _rowBloc; - late _RegionStateNotifier _rowStateNotifier; @override void initState() { - _rowBloc = widget.blocBuilder(); + _rowBloc = RowBloc( + rowData: widget.rowData, + rowCache: widget.rowCache, + ); _rowBloc.add(const RowEvent.initial()); - _rowStateNotifier = _RegionStateNotifier(); super.initState(); } @@ -37,29 +43,24 @@ class _GridRowWidgetState extends State { Widget build(BuildContext context) { return BlocProvider.value( value: _rowBloc, - child: ChangeNotifierProvider.value( - value: _rowStateNotifier, - child: MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (p) => _rowStateNotifier.onEnter = true, - onExit: (p) => _rowStateNotifier.onEnter = false, - child: BlocBuilder( - buildWhen: (p, c) => p.rowData.height != c.rowData.height, - builder: (context, state) { - return SizedBox( - height: 42, - child: Row( - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: const [ - _RowLeading(), - _RowCells(), - _RowTrailing(), - ], - ), - ); - }, - ), + child: _RowEnterRegion( + child: BlocBuilder( + buildWhen: (p, c) => p.rowData.height != c.rowData.height, + builder: (context, state) { + final children = [ + const _RowLeading(), + _RowCells(onExpand: () => onExpandCell(context)), + const _RowTrailing(), + ]; + + final child = Row( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: children, + ); + + return SizedBox(height: 42, child: child); + }, ), ), ); @@ -68,9 +69,13 @@ class _GridRowWidgetState extends State { @override Future dispose() async { _rowBloc.close(); - _rowStateNotifier.dispose(); super.dispose(); } + + void onExpandCell(BuildContext context) { + final page = RowDetailPage(rowData: widget.rowData, rowCache: widget.rowCache); + page.show(context); + } } class _RowLeading extends StatelessWidget { @@ -142,32 +147,41 @@ class _DeleteRowButton extends StatelessWidget { } class _RowCells extends StatelessWidget { - const _RowCells({Key? key}) : super(key: key); + final VoidCallback onExpand; + const _RowCells({required this.onExpand, Key? key}) : super(key: key); @override Widget build(BuildContext context) { return BlocBuilder( buildWhen: (previous, current) => previous.cellDataMap != current.cellDataMap, builder: (context, state) { - final List children = state.cellDataMap.fold(() => [], _toCells); return Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, - children: children, + children: _makeCells(state.cellDataMap), ); }, ); } - List _toCells(CellDataMap dataMap) { - return dataMap.values.map( - (cellData) { - return CellContainer( - width: cellData.field.width.toDouble(), - child: buildGridCell(cellData), - ); - }, - ).toList(); + List _makeCells(Option data) { + return data.fold( + () => [], + (cellDataMap) => cellDataMap.values.map( + (cellData) { + Widget? expander; + if (cellData.field.isPrimary) { + expander = _CellExpander(onExpand: onExpand); + } + + return CellContainer( + width: cellData.field.width.toDouble(), + child: buildGridCell(cellData), + expander: expander, + ); + }, + ).toList(), + ); } } @@ -183,3 +197,57 @@ class _RegionStateNotifier extends ChangeNotifier { bool get onEnter => _onEnter; } + +class _CellExpander extends StatelessWidget { + final VoidCallback onExpand; + const _CellExpander({required this.onExpand, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return FlowyIconButton( + width: 20, + onPressed: onExpand, + iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2), + icon: svgWidget("grid/expander", color: theme.main1), + ); + } +} + +class _RowEnterRegion extends StatefulWidget { + final Widget child; + const _RowEnterRegion({required this.child, Key? key}) : super(key: key); + + @override + State<_RowEnterRegion> createState() => _RowEnterRegionState(); +} + +class _RowEnterRegionState extends State<_RowEnterRegion> { + late _RegionStateNotifier _rowStateNotifier; + + @override + void initState() { + _rowStateNotifier = _RegionStateNotifier(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return ChangeNotifierProvider.value( + value: _rowStateNotifier, + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (p) => _rowStateNotifier.onEnter = true, + onExit: (p) => _rowStateNotifier.onEnter = false, + child: widget.child, + ), + ); + ; + } + + @override + Future dispose() async { + _rowStateNotifier.dispose(); + super.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart new file mode 100644 index 0000000000..e41a4b484b --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -0,0 +1,48 @@ +import 'package:app_flowy/workspace/application/grid/row/row_detail_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:window_size/window_size.dart'; + +class RowDetailPage extends StatelessWidget with FlowyOverlayDelegate { + final GridRow rowData; + final GridRowCache rowCache; + + const RowDetailPage({ + required this.rowData, + required this.rowCache, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => RowDetailBloc(rowData: rowData, rowCache: rowCache), + child: Container(), + ); + } + + void show(BuildContext context) async { + FlowyOverlay.of(context).remove(identifier()); + + const size = Size(460, 400); + final window = await getWindowInfo(); + FlowyOverlay.of(context).insertWithRect( + widget: OverlayContainer( + child: this, + constraints: BoxConstraints.tight(const Size(460, 400)), + ), + identifier: identifier(), + anchorPosition: Offset(-size.width / 2.0, -size.height / 2.0), + anchorSize: window.frame.size, + anchorDirection: AnchorDirection.center, + style: FlowyOverlayStyle(blur: false), + delegate: this, + ); + } + + static String identifier() { + return (RowDetailPage).toString(); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index bc108f78d7..aa8f88ab5d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -67,7 +67,7 @@ class GridPropertyList extends StatelessWidget with FlowyOverlayDelegate { } String identifier() { - return toString(); + return (GridPropertyList).toString(); } @override 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 8c01e7c1bc..e64431b1f9 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 @@ -85,6 +85,7 @@ class Field extends $pb.GeneratedMessage { ..aOB(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'frozen') ..aOB(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'visibility') ..a<$core.int>(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'width', $pb.PbFieldType.O3) + ..aOB(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isPrimary') ..hasRequiredFields = false ; @@ -97,6 +98,7 @@ class Field extends $pb.GeneratedMessage { $core.bool? frozen, $core.bool? visibility, $core.int? width, + $core.bool? isPrimary, }) { final _result = create(); if (id != null) { @@ -120,6 +122,9 @@ class Field extends $pb.GeneratedMessage { if (width != null) { _result.width = width; } + if (isPrimary != null) { + _result.isPrimary = isPrimary; + } return _result; } factory Field.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -205,6 +210,15 @@ class Field extends $pb.GeneratedMessage { $core.bool hasWidth() => $_has(6); @$pb.TagNumber(7) void clearWidth() => clearField(7); + + @$pb.TagNumber(8) + $core.bool get isPrimary => $_getBF(7); + @$pb.TagNumber(8) + set isPrimary($core.bool v) { $_setBool(7, v); } + @$pb.TagNumber(8) + $core.bool hasIsPrimary() => $_has(7); + @$pb.TagNumber(8) + void clearIsPrimary() => clearField(8); } class FieldOrder extends $pb.GeneratedMessage { 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 624e31c392..722a8ebcd6 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 @@ -57,11 +57,12 @@ const Field$json = const { const {'1': 'frozen', '3': 5, '4': 1, '5': 8, '10': 'frozen'}, const {'1': 'visibility', '3': 6, '4': 1, '5': 8, '10': 'visibility'}, const {'1': 'width', '3': 7, '4': 1, '5': 5, '10': 'width'}, + const {'1': 'is_primary', '3': 8, '4': 1, '5': 8, '10': 'isPrimary'}, ], }; /// Descriptor for `Field`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List fieldDescriptor = $convert.base64Decode('CgVGaWVsZBIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRkZXNjGAMgASgJUgRkZXNjEikKCmZpZWxkX3R5cGUYBCABKA4yCi5GaWVsZFR5cGVSCWZpZWxkVHlwZRIWCgZmcm96ZW4YBSABKAhSBmZyb3plbhIeCgp2aXNpYmlsaXR5GAYgASgIUgp2aXNpYmlsaXR5EhQKBXdpZHRoGAcgASgFUgV3aWR0aA=='); +final $typed_data.Uint8List fieldDescriptor = $convert.base64Decode('CgVGaWVsZBIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRkZXNjGAMgASgJUgRkZXNjEikKCmZpZWxkX3R5cGUYBCABKA4yCi5GaWVsZFR5cGVSCWZpZWxkVHlwZRIWCgZmcm96ZW4YBSABKAhSBmZyb3plbhIeCgp2aXNpYmlsaXR5GAYgASgIUgp2aXNpYmlsaXR5EhQKBXdpZHRoGAcgASgFUgV3aWR0aBIdCgppc19wcmltYXJ5GAggASgIUglpc1ByaW1hcnk='); @$core.Deprecated('Use fieldOrderDescriptor instead') const FieldOrder$json = const { '1': 'FieldOrder', diff --git a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs index d20e29282e..5eaabb0294 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs @@ -13,7 +13,7 @@ pub type BoxTypeOptionBuilder = Box; impl FieldBuilder { pub fn new>(type_option_builder: T) -> Self { let type_option_builder = type_option_builder.into(); - let field_meta = FieldMeta::new("", "", type_option_builder.field_type()); + let field_meta = FieldMeta::new("", "", type_option_builder.field_type(), false); Self { field_meta, type_option_builder, @@ -35,6 +35,7 @@ impl FieldBuilder { visibility: field.visibility, width: field.width, type_options: IndexMap::default(), + is_primary: field.is_primary, }; Self { field_meta, @@ -52,6 +53,11 @@ impl FieldBuilder { self } + pub fn primary(mut self, is_primary: bool) -> Self { + self.field_meta.is_primary = is_primary; + self + } + pub fn visibility(mut self, visibility: bool) -> Self { self.field_meta.visibility = visibility; self 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 724ec65e8f..2834222778 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -1,10 +1,9 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::manager::GridUser; use crate::services::block_meta_manager::GridBlockMetaEditorManager; -use crate::services::entities::{CellIdentifier, CreateSelectOptionParams}; +use crate::services::entities::CellIdentifier; use crate::services::field::{ - default_type_option_builder_from_type, select_option_operation, type_option_builder_from_bytes, FieldBuilder, - SelectOption, + default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder, SelectOption, }; use crate::services::persistence::block_index::BlockIndexPersistence; use crate::services::row::*; diff --git a/frontend/rust-lib/flowy-grid/src/util.rs b/frontend/rust-lib/flowy-grid/src/util.rs index 11c5f5a106..f70d685c2d 100644 --- a/frontend/rust-lib/flowy-grid/src/util.rs +++ b/frontend/rust-lib/flowy-grid/src/util.rs @@ -7,6 +7,7 @@ pub fn make_default_grid() -> BuildGridContext { let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) .name("Name") .visibility(true) + .primary(true) .build(); // single select diff --git a/frontend/rust-lib/flowy-grid/tests/grid/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/script.rs index 40ab75f780..611ee937e2 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/script.rs @@ -271,6 +271,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldMeta) { frozen: field_meta.frozen, visibility: field_meta.visibility, width: field_meta.width, + is_primary: false, }; let params = InsertFieldParams { @@ -303,6 +304,7 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldMet frozen: field_meta.frozen, visibility: field_meta.visibility, width: field_meta.width, + is_primary: false, }; let params = InsertFieldParams { 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 94f46919c1..d246fd490b 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -42,6 +42,9 @@ pub struct Field { #[pb(index = 7)] pub width: i32, + + #[pb(index = 8)] + pub is_primary: bool, } impl std::convert::From for Field { @@ -54,6 +57,7 @@ impl std::convert::From for Field { frozen: field_meta.frozen, visibility: field_meta.visibility, width: field_meta.width, + is_primary: field_meta.is_primary, } } } diff --git a/shared-lib/flowy-grid-data-model/src/entities/meta.rs b/shared-lib/flowy-grid-data-model/src/entities/meta.rs index a457ec1eb5..d5570a58e5 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/meta.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/meta.rs @@ -98,13 +98,21 @@ pub struct FieldMeta { // #[pb(index = 8)] /// type_options contains key/value pairs /// key: id of the FieldType - /// value: type option data string + /// value: type option data that can be parsed into specified TypeOptionStruct. + /// For example, CheckboxTypeOption, MultiSelectTypeOption etc. #[serde(with = "indexmap::serde_seq")] pub type_options: IndexMap, + + #[serde(default = "default_is_primary")] + pub is_primary: bool, +} + +fn default_is_primary() -> bool { + false } impl FieldMeta { - pub fn new(name: &str, desc: &str, field_type: FieldType) -> Self { + pub fn new(name: &str, desc: &str, field_type: FieldType, is_primary: bool) -> Self { let width = field_type.default_cell_width(); Self { id: gen_field_id(), @@ -115,6 +123,7 @@ impl FieldMeta { visibility: true, width, type_options: Default::default(), + is_primary, } } 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 d988ae90c2..754fc11386 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 @@ -290,6 +290,7 @@ pub struct Field { pub frozen: bool, pub visibility: bool, pub width: i32, + pub is_primary: bool, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -443,6 +444,21 @@ impl Field { pub fn set_width(&mut self, v: i32) { self.width = v; } + + // bool is_primary = 8; + + + pub fn get_is_primary(&self) -> bool { + self.is_primary + } + pub fn clear_is_primary(&mut self) { + self.is_primary = false; + } + + // Param is passed by value, moved + pub fn set_is_primary(&mut self, v: bool) { + self.is_primary = v; + } } impl ::protobuf::Message for Field { @@ -487,6 +503,13 @@ impl ::protobuf::Message for Field { let tmp = is.read_int32()?; self.width = tmp; }, + 8 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_bool()?; + self.is_primary = tmp; + }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, @@ -520,6 +543,9 @@ impl ::protobuf::Message for Field { if self.width != 0 { my_size += ::protobuf::rt::value_size(7, self.width, ::protobuf::wire_format::WireTypeVarint); } + if self.is_primary != false { + my_size += 2; + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size @@ -547,6 +573,9 @@ impl ::protobuf::Message for Field { if self.width != 0 { os.write_int32(7, self.width)?; } + if self.is_primary != false { + os.write_bool(8, self.is_primary)?; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -620,6 +649,11 @@ impl ::protobuf::Message for Field { |m: &Field| { &m.width }, |m: &mut Field| { &mut m.width }, )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>( + "is_primary", + |m: &Field| { &m.is_primary }, + |m: &mut Field| { &mut m.is_primary }, + )); ::protobuf::reflect::MessageDescriptor::new_pb_name::( "Field", fields, @@ -643,6 +677,7 @@ impl ::protobuf::Clear for Field { self.frozen = false; self.visibility = false; self.width = 0; + self.is_primary = false; self.unknown_fields.clear(); } } @@ -7770,93 +7805,94 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \n\ngrid.proto\"z\n\x04Grid\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\ \x12.\n\x0cfield_orders\x18\x02\x20\x03(\x0b2\x0b.FieldOrderR\x0bfieldOr\ ders\x122\n\x0cblock_orders\x18\x03\x20\x03(\x0b2\x0f.GridBlockOrderR\ - \x0bblockOrders\"\xb8\x01\n\x05Field\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\ + \x0bblockOrders\"\xd7\x01\n\x05Field\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\ \x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\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\x06froze\ n\x12\x1e\n\nvisibility\x18\x06\x20\x01(\x08R\nvisibility\x12\x14\n\x05w\ - idth\x18\x07\x20\x01(\x05R\x05width\"'\n\nFieldOrder\x12\x19\n\x08field_\ - id\x18\x01\x20\x01(\tR\x07fieldId\"\xc6\x01\n\x12GridFieldChangeset\x12\ - \x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x124\n\x0finserted_field\ - s\x18\x02\x20\x03(\x0b2\x0b.IndexFieldR\x0einsertedFields\x122\n\x0edele\ - ted_fields\x18\x03\x20\x03(\x0b2\x0b.FieldOrderR\rdeletedFields\x12-\n\ - \x0eupdated_fields\x18\x04\x20\x03(\x0b2\x06.FieldR\rupdatedFields\"@\n\ - \nIndexField\x12\x1c\n\x05field\x18\x01\x20\x01(\x0b2\x06.FieldR\x05fiel\ - d\x12\x14\n\x05index\x18\x02\x20\x01(\x05R\x05index\"\x90\x01\n\x1aGetEd\ - itFieldContextPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\ - \x12\x1b\n\x08field_id\x18\x02\x20\x01(\tH\0R\x07fieldId\x12)\n\nfield_t\ - ype\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fone_of_field\ - _id\"q\n\x10EditFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\ - \x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12)\n\n\ - field_type\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldType\"|\n\x10EditFie\ - ldContext\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngri\ - d_field\x18\x02\x20\x01(\x0b2\x06.FieldR\tgridField\x12(\n\x10type_optio\ - n_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\"U\n\x0eGridBlockOrder\ - \x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\ - \x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"_\n\rIndexRowOrder\x12&\n\ - \trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x05i\ - ndex\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"\xbf\x01\ - \n\x11GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blo\ - ckId\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0ci\ - nsertedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0b\ - deletedRows\x12,\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0b\ - updatedRows\"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\"\x8f\x01\n\x14CellNotificati\ - onData\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08f\ - ield_id\x18\x02\x20\x01(\tR\x07fieldId\x12\x15\n\x06row_id\x18\x03\x20\ - \x01(\tR\x05rowId\x12\x1a\n\x07content\x18\x04\x20\x01(\tH\0R\x07content\ - B\x10\n\x0eone_of_content\"+\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\x05va\ - lue\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\nstartRowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12Ins\ - ertFieldPayload\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_fie\ - ld_id\x18\x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_fiel\ - d_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.RepeatedFiel\ - dOrderR\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\"\xa8\x03\n\x15FieldChangesetPa\ - yload\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07\ - grid_id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\x18\x03\x20\x01(\ - \tH\0R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\ - \nfield_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\ - \n\x06frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\ - \x18\x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x08\x20\ - \x01(\x05H\x05R\x05width\x12*\n\x10type_option_data\x18\t\x20\x01(\x0cH\ - \x06R\x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\ - \x11one_of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\ - \x0e\n\x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\x9c\x01\n\x0f\ - MoveItemPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\ - \x17\n\x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\nfrom_index\ - \x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\x04\x20\x01(\ - \x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.MoveItemTypeR\ - \x02ty\"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\ - \x06gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\ - \x08field_id\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\x18\x04\ - \x20\x01(\tH\0R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\x12\r\n\ - \tMoveField\x10\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\ - \x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\ - \x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\ - \x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\ + idth\x18\x07\x20\x01(\x05R\x05width\x12\x1d\n\nis_primary\x18\x08\x20\ + \x01(\x08R\tisPrimary\"'\n\nFieldOrder\x12\x19\n\x08field_id\x18\x01\x20\ + \x01(\tR\x07fieldId\"\xc6\x01\n\x12GridFieldChangeset\x12\x17\n\x07grid_\ + id\x18\x01\x20\x01(\tR\x06gridId\x124\n\x0finserted_fields\x18\x02\x20\ + \x03(\x0b2\x0b.IndexFieldR\x0einsertedFields\x122\n\x0edeleted_fields\ + \x18\x03\x20\x03(\x0b2\x0b.FieldOrderR\rdeletedFields\x12-\n\x0eupdated_\ + fields\x18\x04\x20\x03(\x0b2\x06.FieldR\rupdatedFields\"@\n\nIndexField\ + \x12\x1c\n\x05field\x18\x01\x20\x01(\x0b2\x06.FieldR\x05field\x12\x14\n\ + \x05index\x18\x02\x20\x01(\x05R\x05index\"\x90\x01\n\x1aGetEditFieldCont\ + extPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1b\n\ + \x08field_id\x18\x02\x20\x01(\tH\0R\x07fieldId\x12)\n\nfield_type\x18\ + \x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fone_of_field_id\"q\ + \n\x10EditFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridI\ + d\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12)\n\nfield_typ\ + e\x18\x03\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\ + \x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12RepeatedFiel\ + dOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\x05items\"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\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.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.Cel\ + lR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\x20\ + \x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05item\ + s\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockOrder\x12\ + \x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\x18\ + \x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"_\n\rIndexRowOrder\x12&\n\tro\ + w_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x05index\ + \x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"\xbf\x01\n\ + \x11GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07block\ + Id\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cins\ + ertedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bde\ + letedRows\x12,\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0bup\ + datedRows\"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\x07conte\ + nt\x18\x02\x20\x01(\tR\x07content\"\x8f\x01\n\x14CellNotificationData\ + \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_i\ + d\x18\x02\x20\x01(\tR\x07fieldId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\ + \x05rowId\x12\x1a\n\x07content\x18\x04\x20\x01(\tH\0R\x07contentB\x10\n\ + \x0eone_of_content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\x20\ + \x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\n\x04nam\ + e\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\0\ + R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12InsertFieldPa\ + yload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05fi\ + eld\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\"\xa8\x03\n\x15FieldChangesetPayload\ + \x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_\ + id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\x18\x03\x20\x01(\tH\0\ + R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfie\ + ld_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\n\x06\ + frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\x18\ + \x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x08\x20\x01(\ + \x05H\x05R\x05width\x12*\n\x10type_option_data\x18\t\x20\x01(\x0cH\x06R\ + \x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\x11one\ + _of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\x0e\n\ + \x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\x9c\x01\n\x0fMoveIt\ + emPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x17\n\ + \x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\nfrom_index\x18\x03\ + \x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\x04\x20\x01(\x05R\ + \x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.MoveItemTypeR\x02ty\ + \"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06grid\ + Id\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_i\ + d\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\x18\x04\x20\x01(\tH\0\ + R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\x12\r\n\tMoveField\x10\ + \0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\ + \0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0c\ + SingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Check\ + box\x10\x05b\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 45a1af0518..2d6dbecfe4 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 @@ -13,6 +13,7 @@ message Field { bool frozen = 5; bool visibility = 6; int32 width = 7; + bool is_primary = 8; } message FieldOrder { string field_id = 1; diff --git a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs index 7a1e140140..fb800a9626 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs @@ -47,8 +47,8 @@ mod tests { fn create_default_grid_test() { let grid_id = "1".to_owned(); let build_context = GridBuilder::default() - .add_field(FieldMeta::new("Name", "", FieldType::RichText)) - .add_field(FieldMeta::new("Tags", "", FieldType::SingleSelect)) + .add_field(FieldMeta::new("Name", "", FieldType::RichText, true)) + .add_field(FieldMeta::new("Tags", "", FieldType::SingleSelect, false)) .add_empty_row() .add_empty_row() .add_empty_row()