Merge pull request #514 from AppFlowy-IO/refactor_cell_data

Refactor cell data
This commit is contained in:
Nathan.fooo 2022-05-28 15:55:59 +08:00 committed by GitHub
commit 81cf96986e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 435 additions and 527 deletions

View File

@ -16,7 +16,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart';
import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
import 'dart:convert' show utf8;
part 'cell_service.freezed.dart'; part 'cell_service.freezed.dart';
part 'data_loader.dart'; part 'data_loader.dart';
part 'context_builder.dart'; part 'context_builder.dart';

View File

@ -1,6 +1,6 @@
part of 'cell_service.dart'; part of 'cell_service.dart';
typedef GridCellContext = _GridCellContext<Cell, String>; typedef GridCellContext = _GridCellContext<String, String>;
typedef GridSelectOptionCellContext = _GridCellContext<SelectOptionCellData, String>; typedef GridSelectOptionCellContext = _GridCellContext<SelectOptionCellData, String>;
typedef GridDateCellContext = _GridCellContext<DateCellData, DateCalData>; typedef GridDateCellContext = _GridCellContext<DateCellData, DateCalData>;
@ -16,26 +16,33 @@ class GridCellContextBuilder {
_GridCellContext build() { _GridCellContext build() {
switch (_gridCell.field.fieldType) { switch (_gridCell.field.fieldType) {
case FieldType.Checkbox: case FieldType.Checkbox:
final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell,
parser: StringCellDataParser(),
);
return GridCellContext( return GridCellContext(
gridCell: _gridCell, gridCell: _gridCell,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: GridCellDataLoader(gridCell: _gridCell), cellDataLoader: cellDataLoader,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell), cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
); );
case FieldType.DateTime: case FieldType.DateTime:
final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell,
parser: DateCellDataParser(),
);
return GridDateCellContext( return GridDateCellContext(
gridCell: _gridCell, gridCell: _gridCell,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: DateCellDataLoader(gridCell: _gridCell), cellDataLoader: cellDataLoader,
cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell), cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell),
); );
case FieldType.Number: case FieldType.Number:
final cellDataLoader = GridCellDataLoader( final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell, gridCell: _gridCell,
config: const GridCellDataConfig( parser: StringCellDataParser(),
reloadOnCellChanged: true, config: const GridCellDataConfig(reloadOnCellChanged: true, reloadOnFieldChanged: true),
reloadOnFieldChanged: true,
),
); );
return GridCellContext( return GridCellContext(
gridCell: _gridCell, gridCell: _gridCell,
@ -44,18 +51,28 @@ class GridCellContextBuilder {
cellDataPersistence: CellDataPersistence(gridCell: _gridCell), cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
); );
case FieldType.RichText: case FieldType.RichText:
final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell,
parser: StringCellDataParser(),
);
return GridCellContext( return GridCellContext(
gridCell: _gridCell, gridCell: _gridCell,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: GridCellDataLoader(gridCell: _gridCell), cellDataLoader: cellDataLoader,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell), cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
); );
case FieldType.MultiSelect: case FieldType.MultiSelect:
case FieldType.SingleSelect: case FieldType.SingleSelect:
final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell,
parser: SelectOptionCellDataParser(),
config: const GridCellDataConfig(reloadOnFieldChanged: true),
);
return GridSelectOptionCellContext( return GridSelectOptionCellContext(
gridCell: _gridCell, gridCell: _gridCell,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: SelectOptionCellDataLoader(gridCell: _gridCell), cellDataLoader: cellDataLoader,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell), cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
); );
default: default:
@ -131,10 +148,7 @@ class _GridCellContext<T, D> extends Equatable {
} }
onCellChangedFn() { onCellChangedFn() {
final value = _cellDataNotifier.value; onCellChanged(_cellDataNotifier.value as T);
if (value is T) {
onCellChanged(value);
}
if (cellDataLoader.config.reloadOnCellChanged) { if (cellDataLoader.config.reloadOnCellChanged) {
_loadData(); _loadData();
@ -149,9 +163,9 @@ class _GridCellContext<T, D> extends Equatable {
_cellDataNotifier.removeListener(fn); _cellDataNotifier.removeListener(fn);
} }
T? getCellData() { T? getCellData({bool loadIfNoCache = true}) {
final data = cellCache.get(_cacheKey); final data = cellCache.get(_cacheKey);
if (data == null) { if (data == null && loadIfNoCache) {
_loadData(); _loadData();
} }
return data; return data;

View File

@ -4,8 +4,8 @@ abstract class IGridCellDataConfig {
// The cell data will reload if it receives the field's change notification. // The cell data will reload if it receives the field's change notification.
bool get reloadOnFieldChanged; bool get reloadOnFieldChanged;
// The cell data will reload if it receives the cell's change notification. // When the reloadOnCellChanged is true, it will load the cell data after user input.
// For example, the number cell should be reloaded after user input the number. // For example: The number cell reload the cell data that carries the format
// user input: 12 // user input: 12
// cell display: $12 // cell display: $12
bool get reloadOnCellChanged; bool get reloadOnCellChanged;
@ -30,60 +30,45 @@ abstract class IGridCellDataLoader<T> {
IGridCellDataConfig get config; IGridCellDataConfig get config;
} }
class GridCellDataLoader extends IGridCellDataLoader<Cell> { abstract class ICellDataParser<T> {
T? parserData(List<int> data);
}
class GridCellDataLoader<T> extends IGridCellDataLoader<T> {
final CellService service = CellService(); final CellService service = CellService();
final GridCell gridCell; final GridCell gridCell;
final ICellDataParser<T> parser;
@override @override
final IGridCellDataConfig config; final IGridCellDataConfig config;
GridCellDataLoader({ GridCellDataLoader({
required this.gridCell, required this.gridCell,
required this.parser,
this.config = const GridCellDataConfig(), this.config = const GridCellDataConfig(),
}); });
@override @override
Future<Cell?> loadData() { Future<T?> loadData() {
final fut = service.getCell( final fut = service.getCell(
gridId: gridCell.gridId, gridId: gridCell.gridId,
fieldId: gridCell.field.id, fieldId: gridCell.field.id,
rowId: gridCell.rowId, rowId: gridCell.rowId,
); );
return fut.then((result) { return fut.then(
return result.fold((data) => data, (err) { (result) => result.fold((Cell cell) {
try {
return parser.parserData(cell.data);
} catch (e, s) {
Log.error('$parser parser cellData failed, $e');
Log.error('Stack trace \n $s');
return null;
}
}, (err) {
Log.error(err); Log.error(err);
return null; return null;
}); }),
});
}
}
class DateCellDataLoader extends IGridCellDataLoader<DateCellData> {
final GridCell gridCell;
final IGridCellDataConfig _config;
DateCellDataLoader({
required this.gridCell,
}) : _config = const GridCellDataConfig(reloadOnFieldChanged: true);
@override
IGridCellDataConfig get config => _config;
@override
Future<DateCellData?> loadData() {
final payload = CellIdentifierPayload.create()
..gridId = gridCell.gridId
..fieldId = gridCell.field.id
..rowId = gridCell.rowId;
return GridEventGetDateCellData(payload).send().then((result) {
return result.fold(
(data) => data,
(err) {
Log.error(err);
return null;
},
); );
});
} }
} }
@ -109,3 +94,30 @@ class SelectOptionCellDataLoader extends IGridCellDataLoader<SelectOptionCellDat
@override @override
IGridCellDataConfig get config => const GridCellDataConfig(reloadOnFieldChanged: true); IGridCellDataConfig get config => const GridCellDataConfig(reloadOnFieldChanged: true);
} }
class StringCellDataParser implements ICellDataParser<String> {
@override
String? parserData(List<int> data) {
return utf8.decode(data);
}
}
class DateCellDataParser implements ICellDataParser<DateCellData> {
@override
DateCellData? parserData(List<int> data) {
if (data.isEmpty) {
return null;
}
return DateCellData.fromBuffer(data);
}
}
class SelectOptionCellDataParser implements ICellDataParser<SelectOptionCellData> {
@override
SelectOptionCellData? parserData(List<int> data) {
if (data.isEmpty) {
return null;
}
return SelectOptionCellData.fromBuffer(data);
}
}

View File

@ -1,4 +1,3 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell;
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async'; import 'dart:async';
@ -16,15 +15,15 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
}) : super(CheckboxCellState.initial(cellContext)) { }) : super(CheckboxCellState.initial(cellContext)) {
on<CheckboxCellEvent>( on<CheckboxCellEvent>(
(event, emit) async { (event, emit) async {
await event.map( await event.when(
initial: (_Initial value) { initial: () {
_startListening(); _startListening();
}, },
select: (_Selected value) async { select: () async {
_updateCellData(); _updateCellData();
}, },
didReceiveCellUpdate: (_DidReceiveCellUpdate value) { didReceiveCellUpdate: (cellData) {
emit(state.copyWith(isSelected: _isSelected(value.cell))); emit(state.copyWith(isSelected: _isSelected(cellData)));
}, },
); );
}, },
@ -43,9 +42,9 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
} }
void _startListening() { void _startListening() {
_onCellChangedFn = cellContext.startListening(onCellChanged: ((cell) { _onCellChangedFn = cellContext.startListening(onCellChanged: ((cellData) {
if (!isClosed) { if (!isClosed) {
add(CheckboxCellEvent.didReceiveCellUpdate(cell)); add(CheckboxCellEvent.didReceiveCellUpdate(cellData));
} }
})); }));
} }
@ -59,7 +58,7 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
class CheckboxCellEvent with _$CheckboxCellEvent { class CheckboxCellEvent with _$CheckboxCellEvent {
const factory CheckboxCellEvent.initial() = _Initial; const factory CheckboxCellEvent.initial() = _Initial;
const factory CheckboxCellEvent.select() = _Selected; const factory CheckboxCellEvent.select() = _Selected;
const factory CheckboxCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; const factory CheckboxCellEvent.didReceiveCellUpdate(String cellData) = _DidReceiveCellUpdate;
} }
@freezed @freezed
@ -73,7 +72,6 @@ class CheckboxCellState with _$CheckboxCellState {
} }
} }
bool _isSelected(Cell? cell) { bool _isSelected(String? cellData) {
final content = cell?.content ?? ""; return cellData == "Yes";
return content == "Yes";
} }

View File

@ -1,4 +1,3 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async'; import 'dart:async';
@ -20,7 +19,7 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
_startListening(); _startListening();
}, },
didReceiveCellUpdate: (_DidReceiveCellUpdate value) { didReceiveCellUpdate: (_DidReceiveCellUpdate value) {
emit(state.copyWith(content: value.cell.content)); emit(state.copyWith(content: value.cellContent));
}, },
updateCell: (_UpdateCell value) async { updateCell: (_UpdateCell value) async {
await _updateCellValue(value, emit); await _updateCellValue(value, emit);
@ -46,9 +45,9 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
void _startListening() { void _startListening() {
_onCellChangedFn = cellContext.startListening( _onCellChangedFn = cellContext.startListening(
onCellChanged: ((cell) { onCellChanged: ((cellContent) {
if (!isClosed) { if (!isClosed) {
add(NumberCellEvent.didReceiveCellUpdate(cell)); add(NumberCellEvent.didReceiveCellUpdate(cellContent));
} }
}), }),
); );
@ -59,7 +58,7 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
class NumberCellEvent with _$NumberCellEvent { class NumberCellEvent with _$NumberCellEvent {
const factory NumberCellEvent.initial() = _Initial; const factory NumberCellEvent.initial() = _Initial;
const factory NumberCellEvent.updateCell(String text) = _UpdateCell; const factory NumberCellEvent.updateCell(String text) = _UpdateCell;
const factory NumberCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; const factory NumberCellEvent.didReceiveCellUpdate(String cellContent) = _DidReceiveCellUpdate;
} }
@freezed @freezed
@ -69,7 +68,7 @@ class NumberCellState with _$NumberCellState {
}) = _NumberCellState; }) = _NumberCellState;
factory NumberCellState.initial(GridCellContext context) { factory NumberCellState.initial(GridCellContext context) {
final cell = context.getCellData(); final cellContent = context.getCellData() ?? "";
return NumberCellState(content: cell?.content ?? ""); return NumberCellState(content: cellContent);
} }
} }

View File

@ -21,7 +21,6 @@ class SelectOptionCellBloc extends Bloc<SelectOptionCellEvent, SelectOptionCellS
}, },
didReceiveOptions: (_DidReceiveOptions value) { didReceiveOptions: (_DidReceiveOptions value) {
emit(state.copyWith( emit(state.copyWith(
options: value.options,
selectedOptions: value.selectedOptions, selectedOptions: value.selectedOptions,
)); ));
}, },
@ -45,7 +44,6 @@ class SelectOptionCellBloc extends Bloc<SelectOptionCellEvent, SelectOptionCellS
onCellChanged: ((selectOptionContext) { onCellChanged: ((selectOptionContext) {
if (!isClosed) { if (!isClosed) {
add(SelectOptionCellEvent.didReceiveOptions( add(SelectOptionCellEvent.didReceiveOptions(
selectOptionContext.options,
selectOptionContext.selectOptions, selectOptionContext.selectOptions,
)); ));
} }
@ -58,7 +56,6 @@ class SelectOptionCellBloc extends Bloc<SelectOptionCellEvent, SelectOptionCellS
class SelectOptionCellEvent with _$SelectOptionCellEvent { class SelectOptionCellEvent with _$SelectOptionCellEvent {
const factory SelectOptionCellEvent.initial() = _InitialCell; const factory SelectOptionCellEvent.initial() = _InitialCell;
const factory SelectOptionCellEvent.didReceiveOptions( const factory SelectOptionCellEvent.didReceiveOptions(
List<SelectOption> options,
List<SelectOption> selectedOptions, List<SelectOption> selectedOptions,
) = _DidReceiveOptions; ) = _DidReceiveOptions;
} }
@ -66,7 +63,6 @@ class SelectOptionCellEvent with _$SelectOptionCellEvent {
@freezed @freezed
class SelectOptionCellState with _$SelectOptionCellState { class SelectOptionCellState with _$SelectOptionCellState {
const factory SelectOptionCellState({ const factory SelectOptionCellState({
required List<SelectOption> options,
required List<SelectOption> selectedOptions, required List<SelectOption> selectedOptions,
}) = _SelectOptionCellState; }) = _SelectOptionCellState;
@ -74,7 +70,6 @@ class SelectOptionCellState with _$SelectOptionCellState {
final data = context.getCellData(); final data = context.getCellData();
return SelectOptionCellState( return SelectOptionCellState(
options: data?.options ?? [],
selectedOptions: data?.selectOptions ?? [], selectedOptions: data?.selectOptions ?? [],
); );
} }

View File

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
@ -13,17 +14,21 @@ part 'select_option_editor_bloc.freezed.dart';
class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> { class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> {
final SelectOptionService _selectOptionService; final SelectOptionService _selectOptionService;
final GridSelectOptionCellContext cellContext; final GridSelectOptionCellContext cellContext;
late final GridFieldsListener _fieldListener;
void Function()? _onCellChangedFn; void Function()? _onCellChangedFn;
Timer? _delayOperation;
SelectOptionCellEditorBloc({ SelectOptionCellEditorBloc({
required this.cellContext, required this.cellContext,
}) : _selectOptionService = SelectOptionService(gridCell: cellContext.gridCell), }) : _selectOptionService = SelectOptionService(gridCell: cellContext.gridCell),
_fieldListener = GridFieldsListener(gridId: cellContext.gridId),
super(SelectOptionEditorState.initial(cellContext)) { super(SelectOptionEditorState.initial(cellContext)) {
on<SelectOptionEditorEvent>( on<SelectOptionEditorEvent>(
(event, emit) async { (event, emit) async {
await event.map( await event.map(
initial: (_Initial value) async { initial: (_Initial value) async {
_startListening(); _startListening();
_loadOptions();
}, },
didReceiveOptions: (_DidReceiveOptions value) { didReceiveOptions: (_DidReceiveOptions value) {
final result = _makeOptions(state.filter, value.options); final result = _makeOptions(state.filter, value.options);
@ -63,6 +68,8 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
cellContext.removeListener(_onCellChangedFn!); cellContext.removeListener(_onCellChangedFn!);
_onCellChangedFn = null; _onCellChangedFn = null;
} }
_delayOperation?.cancel();
await _fieldListener.stop();
cellContext.dispose(); cellContext.dispose();
return super.close(); return super.close();
} }
@ -106,6 +113,24 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
)); ));
} }
void _loadOptions() {
_delayOperation?.cancel();
_delayOperation = Timer(const Duration(milliseconds: 10), () {
_selectOptionService.getOpitonContext().then((result) {
if (isClosed) {
return;
}
return result.fold(
(data) => add(SelectOptionEditorEvent.didReceiveOptions(data.options, data.selectOptions)),
(err) {
Log.error(err);
return null;
},
);
});
});
}
_MakeOptionResult _makeOptions(Option<String> filter, List<SelectOption> allOptions) { _MakeOptionResult _makeOptions(Option<String> filter, List<SelectOption> allOptions) {
final List<SelectOption> options = List.from(allOptions); final List<SelectOption> options = List.from(allOptions);
Option<String> createOption = filter; Option<String> createOption = filter;
@ -135,13 +160,21 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
_onCellChangedFn = cellContext.startListening( _onCellChangedFn = cellContext.startListening(
onCellChanged: ((selectOptionContext) { onCellChanged: ((selectOptionContext) {
if (!isClosed) { if (!isClosed) {
add(SelectOptionEditorEvent.didReceiveOptions( _loadOptions();
selectOptionContext.options,
selectOptionContext.selectOptions,
));
} }
}), }),
); );
_fieldListener.start(onFieldsChanged: (result) {
result.fold(
(changeset) {
if (changeset.updatedFields.isNotEmpty) {
_loadOptions();
}
},
(err) => Log.error(err),
);
});
} }
} }
@ -168,7 +201,7 @@ class SelectOptionEditorState with _$SelectOptionEditorState {
}) = _SelectOptionEditorState; }) = _SelectOptionEditorState;
factory SelectOptionEditorState.initial(GridSelectOptionCellContext context) { factory SelectOptionEditorState.initial(GridSelectOptionCellContext context) {
final data = context.getCellData(); final data = context.getCellData(loadIfNoCache: false);
return SelectOptionEditorState( return SelectOptionEditorState(
options: data?.options ?? [], options: data?.options ?? [],
allOptions: data?.options ?? [], allOptions: data?.options ?? [],

View File

@ -1,4 +1,3 @@
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell;
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async'; import 'dart:async';
@ -14,21 +13,16 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
}) : super(TextCellState.initial(cellContext)) { }) : super(TextCellState.initial(cellContext)) {
on<TextCellEvent>( on<TextCellEvent>(
(event, emit) async { (event, emit) async {
await event.map( await event.when(
initial: (_InitialCell value) async { initial: () async {
_startListening(); _startListening();
}, },
updateText: (_UpdateText value) { updateText: (text) {
cellContext.saveCellData(value.text); cellContext.saveCellData(text);
emit(state.copyWith(content: value.text)); emit(state.copyWith(content: text));
}, },
didReceiveCellData: (_DidReceiveCellData value) { didReceiveCellUpdate: (content) {
emit(state.copyWith(content: value.cellData.cell?.content ?? "")); emit(state.copyWith(content: content));
},
didReceiveCellUpdate: (_DidReceiveCellUpdate value) {
emit(state.copyWith(
content: value.cell.content,
));
}, },
); );
}, },
@ -47,9 +41,9 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
void _startListening() { void _startListening() {
_onCellChangedFn = cellContext.startListening( _onCellChangedFn = cellContext.startListening(
onCellChanged: ((cell) { onCellChanged: ((cellContent) {
if (!isClosed) { if (!isClosed) {
add(TextCellEvent.didReceiveCellUpdate(cell)); add(TextCellEvent.didReceiveCellUpdate(cellContent));
} }
}), }),
); );
@ -59,8 +53,7 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
@freezed @freezed
class TextCellEvent with _$TextCellEvent { class TextCellEvent with _$TextCellEvent {
const factory TextCellEvent.initial() = _InitialCell; const factory TextCellEvent.initial() = _InitialCell;
const factory TextCellEvent.didReceiveCellData(GridCell cellData) = _DidReceiveCellData; const factory TextCellEvent.didReceiveCellUpdate(String cellContent) = _DidReceiveCellUpdate;
const factory TextCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate;
const factory TextCellEvent.updateText(String text) = _UpdateText; const factory TextCellEvent.updateText(String text) = _UpdateText;
} }
@ -71,6 +64,6 @@ class TextCellState with _$TextCellState {
}) = _TextCellState; }) = _TextCellState;
factory TextCellState.initial(GridCellContext context) => TextCellState( factory TextCellState.initial(GridCellContext context) => TextCellState(
content: context.getCellData()?.content ?? "", content: context.getCellData() ?? "",
); );
} }

View File

@ -392,20 +392,3 @@ class GridEventUpdateDateCell {
} }
} }
class GridEventGetDateCellData {
CellIdentifierPayload request;
GridEventGetDateCellData(this.request);
Future<Either<DateCellData, FlowyError>> send() {
final request = FFIRequest.create()
..event = GridEvent.GetDateCellData.toString()
..payload = requestToBytes(this.request);
return Dispatch.asyncRequest(request)
.then((bytesResult) => bytesResult.fold(
(okBytes) => left(DateCellData.fromBuffer(okBytes)),
(errBytes) => right(FlowyError.fromBuffer(errBytes)),
));
}
}

View File

@ -1366,24 +1366,19 @@ class GridBlock extends $pb.GeneratedMessage {
class Cell extends $pb.GeneratedMessage { class Cell extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Cell', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Cell', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content') ..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
Cell._() : super(); Cell._() : super();
factory Cell({ factory Cell({
$core.String? fieldId, $core.String? fieldId,
$core.String? content, $core.List<$core.int>? data,
$core.String? data,
}) { }) {
final _result = create(); final _result = create();
if (fieldId != null) { if (fieldId != null) {
_result.fieldId = fieldId; _result.fieldId = fieldId;
} }
if (content != null) {
_result.content = content;
}
if (data != null) { if (data != null) {
_result.data = data; _result.data = data;
} }
@ -1420,22 +1415,13 @@ class Cell extends $pb.GeneratedMessage {
void clearFieldId() => clearField(1); void clearFieldId() => clearField(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.String get content => $_getSZ(1); $core.List<$core.int> get data => $_getN(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
set content($core.String v) { $_setString(1, v); } set data($core.List<$core.int> v) { $_setBytes(1, v); }
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.bool hasContent() => $_has(1); $core.bool hasData() => $_has(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
void clearContent() => clearField(2); void clearData() => clearField(2);
@$pb.TagNumber(3)
$core.String get data => $_getSZ(2);
@$pb.TagNumber(3)
set data($core.String v) { $_setString(2, v); }
@$pb.TagNumber(3)
$core.bool hasData() => $_has(2);
@$pb.TagNumber(3)
void clearData() => clearField(3);
} }
class RepeatedCell extends $pb.GeneratedMessage { class RepeatedCell extends $pb.GeneratedMessage {

View File

@ -289,13 +289,12 @@ const Cell$json = const {
'1': 'Cell', '1': 'Cell',
'2': const [ '2': const [
const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'}, const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'},
const {'1': 'content', '3': 2, '4': 1, '5': 9, '10': 'content'}, const {'1': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'},
const {'1': 'data', '3': 3, '4': 1, '5': 9, '10': 'data'},
], ],
}; };
/// Descriptor for `Cell`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `Cell`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhgKB2NvbnRlbnQYAiABKAlSB2NvbnRlbnQSEgoEZGF0YRgDIAEoCVIEZGF0YQ=='); final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhIKBGRhdGEYAiABKAxSBGRhdGE=');
@$core.Deprecated('Use repeatedCellDescriptor instead') @$core.Deprecated('Use repeatedCellDescriptor instead')
const RepeatedCell$json = const { const RepeatedCell$json = const {
'1': 'RepeatedCell', '1': 'RepeatedCell',

View File

@ -33,7 +33,6 @@ class GridEvent extends $pb.ProtobufEnum {
static const GridEvent UpdateCell = GridEvent._(71, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCell'); static const GridEvent UpdateCell = GridEvent._(71, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCell');
static const GridEvent UpdateSelectOptionCell = GridEvent._(72, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOptionCell'); static const GridEvent UpdateSelectOptionCell = GridEvent._(72, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOptionCell');
static const GridEvent UpdateDateCell = GridEvent._(80, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateDateCell'); static const GridEvent UpdateDateCell = GridEvent._(80, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateDateCell');
static const GridEvent GetDateCellData = GridEvent._(90, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetDateCellData');
static const $core.List<GridEvent> values = <GridEvent> [ static const $core.List<GridEvent> values = <GridEvent> [
GetGridData, GetGridData,
@ -59,7 +58,6 @@ class GridEvent extends $pb.ProtobufEnum {
UpdateCell, UpdateCell,
UpdateSelectOptionCell, UpdateSelectOptionCell,
UpdateDateCell, UpdateDateCell,
GetDateCellData,
]; ];
static final $core.Map<$core.int, GridEvent> _byValue = $pb.ProtobufEnum.initByValue(values); static final $core.Map<$core.int, GridEvent> _byValue = $pb.ProtobufEnum.initByValue(values);

View File

@ -35,9 +35,8 @@ const GridEvent$json = const {
const {'1': 'UpdateCell', '2': 71}, const {'1': 'UpdateCell', '2': 71},
const {'1': 'UpdateSelectOptionCell', '2': 72}, const {'1': 'UpdateSelectOptionCell', '2': 72},
const {'1': 'UpdateDateCell', '2': 80}, const {'1': 'UpdateDateCell', '2': 80},
const {'1': 'GetDateCellData', '2': 90},
], ],
}; };
/// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. /// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIZChVVcGRhdGVGaWVsZFR5cGVPcHRpb24QDBIPCgtJbnNlcnRGaWVsZBANEg8KC0RlbGV0ZUZpZWxkEA4SEQoNU3dpdGNoVG9GaWVsZBAUEhIKDkR1cGxpY2F0ZUZpZWxkEBUSDAoITW92ZUl0ZW0QFhIWChJHZXRGaWVsZFR5cGVPcHRpb24QFxIZChVDcmVhdGVGaWVsZFR5cGVPcHRpb24QGBITCg9OZXdTZWxlY3RPcHRpb24QHhIbChdHZXRTZWxlY3RPcHRpb25DZWxsRGF0YRAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlU2VsZWN0T3B0aW9uQ2VsbBBIEhIKDlVwZGF0ZURhdGVDZWxsEFASEwoPR2V0RGF0ZUNlbGxEYXRhEFo='); final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIZChVVcGRhdGVGaWVsZFR5cGVPcHRpb24QDBIPCgtJbnNlcnRGaWVsZBANEg8KC0RlbGV0ZUZpZWxkEA4SEQoNU3dpdGNoVG9GaWVsZBAUEhIKDkR1cGxpY2F0ZUZpZWxkEBUSDAoITW92ZUl0ZW0QFhIWChJHZXRGaWVsZFR5cGVPcHRpb24QFxIZChVDcmVhdGVGaWVsZFR5cGVPcHRpb24QGBITCg9OZXdTZWxlY3RPcHRpb24QHhIbChdHZXRTZWxlY3RPcHRpb25DZWxsRGF0YRAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlU2VsZWN0T3B0aW9uQ2VsbBBIEhIKDlVwZGF0ZURhdGVDZWxsEFA=');

View File

@ -263,27 +263,6 @@ pub(crate) async fn update_cell_handler(
Ok(()) Ok(())
} }
#[tracing::instrument(level = "trace", skip(data, manager), err)]
pub(crate) async fn get_date_cell_data_handler(
data: Data<CellIdentifierPayload>,
manager: AppData<Arc<GridManager>>,
) -> DataResult<DateCellData, FlowyError> {
let params: CellIdentifier = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
match editor.get_field_meta(&params.field_id).await {
None => {
tracing::error!("Can't find the corresponding field with id: {}", params.field_id);
data_result(DateCellData::default())
}
Some(field_meta) => {
let cell_meta = editor.get_cell_meta(&params.row_id, &params.field_id).await?;
let type_option = DateTypeOption::from(&field_meta);
let date_cell_data = type_option.make_date_cell_data(&cell_meta)?;
data_result(date_cell_data)
}
}
}
#[tracing::instrument(level = "trace", skip_all, err)] #[tracing::instrument(level = "trace", skip_all, err)]
pub(crate) async fn new_select_option_handler( pub(crate) async fn new_select_option_handler(
data: Data<CreateSelectOptionPayload>, data: Data<CreateSelectOptionPayload>,

View File

@ -29,7 +29,6 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
// Cell // Cell
.event(GridEvent::GetCell, get_cell_handler) .event(GridEvent::GetCell, get_cell_handler)
.event(GridEvent::UpdateCell, update_cell_handler) .event(GridEvent::UpdateCell, update_cell_handler)
.event(GridEvent::GetDateCellData, get_date_cell_data_handler)
// SelectOption // SelectOption
.event(GridEvent::NewSelectOption, new_select_option_handler) .event(GridEvent::NewSelectOption, new_select_option_handler)
.event(GridEvent::UpdateSelectOption, update_select_option_handler) .event(GridEvent::UpdateSelectOption, update_select_option_handler)
@ -112,7 +111,4 @@ pub enum GridEvent {
#[event(input = "DateChangesetPayload")] #[event(input = "DateChangesetPayload")]
UpdateDateCell = 80, UpdateDateCell = 80,
#[event(input = "CellIdentifierPayload", output = "DateCellData")]
GetDateCellData = 90,
} }

View File

@ -48,7 +48,6 @@ pub enum GridEvent {
UpdateCell = 71, UpdateCell = 71,
UpdateSelectOptionCell = 72, UpdateSelectOptionCell = 72,
UpdateDateCell = 80, UpdateDateCell = 80,
GetDateCellData = 90,
} }
impl ::protobuf::ProtobufEnum for GridEvent { impl ::protobuf::ProtobufEnum for GridEvent {
@ -81,7 +80,6 @@ impl ::protobuf::ProtobufEnum for GridEvent {
71 => ::std::option::Option::Some(GridEvent::UpdateCell), 71 => ::std::option::Option::Some(GridEvent::UpdateCell),
72 => ::std::option::Option::Some(GridEvent::UpdateSelectOptionCell), 72 => ::std::option::Option::Some(GridEvent::UpdateSelectOptionCell),
80 => ::std::option::Option::Some(GridEvent::UpdateDateCell), 80 => ::std::option::Option::Some(GridEvent::UpdateDateCell),
90 => ::std::option::Option::Some(GridEvent::GetDateCellData),
_ => ::std::option::Option::None _ => ::std::option::Option::None
} }
} }
@ -111,7 +109,6 @@ impl ::protobuf::ProtobufEnum for GridEvent {
GridEvent::UpdateCell, GridEvent::UpdateCell,
GridEvent::UpdateSelectOptionCell, GridEvent::UpdateSelectOptionCell,
GridEvent::UpdateDateCell, GridEvent::UpdateDateCell,
GridEvent::GetDateCellData,
]; ];
values values
} }
@ -140,7 +137,7 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent {
} }
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0fevent_map.proto*\xdc\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ \n\x0fevent_map.proto*\xc7\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\
\0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\ \0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\
\x0bUpdateField\x10\x0b\x12\x19\n\x15UpdateFieldTypeOption\x10\x0c\x12\ \x0bUpdateField\x10\x0b\x12\x19\n\x15UpdateFieldTypeOption\x10\x0c\x12\
\x0f\n\x0bInsertField\x10\r\x12\x0f\n\x0bDeleteField\x10\x0e\x12\x11\n\r\ \x0f\n\x0bInsertField\x10\r\x12\x0f\n\x0bDeleteField\x10\x0e\x12\x11\n\r\
@ -151,7 +148,7 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\x10\x20\x12\r\n\tCreateRow\x102\x12\n\n\x06GetRow\x103\x12\r\n\tDeleteR\ \x10\x20\x12\r\n\tCreateRow\x102\x12\n\n\x06GetRow\x103\x12\r\n\tDeleteR\
ow\x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\ ow\x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\
\n\nUpdateCell\x10G\x12\x1a\n\x16UpdateSelectOptionCell\x10H\x12\x12\n\ \n\nUpdateCell\x10G\x12\x1a\n\x16UpdateSelectOptionCell\x10H\x12\x12\n\
\x0eUpdateDateCell\x10P\x12\x13\n\x0fGetDateCellData\x10Zb\x06proto3\ \x0eUpdateDateCell\x10Pb\x06proto3\
"; ";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -24,5 +24,4 @@ enum GridEvent {
UpdateCell = 71; UpdateCell = 71;
UpdateSelectOptionCell = 72; UpdateSelectOptionCell = 72;
UpdateDateCell = 80; UpdateDateCell = 80;
GetDateCellData = 90;
} }

View File

@ -58,7 +58,7 @@ impl CellDataOperation<String, String> for CheckboxTypeOption {
let encoded_data = encoded_data.into(); let encoded_data = encoded_data.into();
if encoded_data == YES || encoded_data == NO { if encoded_data == YES || encoded_data == NO {
return Ok(DecodedCellData::from_content(encoded_data)); return Ok(DecodedCellData::new(encoded_data));
} }
Ok(DecodedCellData::default()) Ok(DecodedCellData::default())
@ -104,37 +104,37 @@ mod tests {
let field_meta = FieldBuilder::from_field_type(&FieldType::Checkbox).build(); let field_meta = FieldBuilder::from_field_type(&FieldType::Checkbox).build();
let data = apply_cell_data_changeset("true", None, &field_meta).unwrap(); let data = apply_cell_data_changeset("true", None, &field_meta).unwrap();
assert_eq!( assert_eq!(
decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).content, decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).to_string(),
YES YES
); );
let data = apply_cell_data_changeset("1", None, &field_meta).unwrap(); let data = apply_cell_data_changeset("1", None, &field_meta).unwrap();
assert_eq!( assert_eq!(
decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).content, decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).to_string(),
YES YES
); );
let data = apply_cell_data_changeset("yes", None, &field_meta).unwrap(); let data = apply_cell_data_changeset("yes", None, &field_meta).unwrap();
assert_eq!( assert_eq!(
decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).content, decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).to_string(),
YES YES
); );
let data = apply_cell_data_changeset("false", None, &field_meta).unwrap(); let data = apply_cell_data_changeset("false", None, &field_meta).unwrap();
assert_eq!( assert_eq!(
decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).content, decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).to_string(),
NO NO
); );
let data = apply_cell_data_changeset("no", None, &field_meta).unwrap(); let data = apply_cell_data_changeset("no", None, &field_meta).unwrap();
assert_eq!( assert_eq!(
decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).content, decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).to_string(),
NO NO
); );
let data = apply_cell_data_changeset("12", None, &field_meta).unwrap(); let data = apply_cell_data_changeset("12", None, &field_meta).unwrap();
assert_eq!( assert_eq!(
decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).content, decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).to_string(),
NO NO
); );
} }

View File

@ -1,9 +1,7 @@
use crate::entities::{CellIdentifier, CellIdentifierPayload}; use crate::entities::{CellIdentifier, CellIdentifierPayload};
use crate::impl_type_option; use crate::impl_type_option;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{ use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, EncodedCellData};
CellContentChangeset, CellDataOperation, DecodedCellData, EncodedCellData, TypeOptionCellData,
};
use bytes::Bytes; use bytes::Bytes;
use chrono::format::strftime::StrftimeItems; use chrono::format::strftime::StrftimeItems;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
@ -79,32 +77,12 @@ impl DateTypeOption {
} }
} }
pub fn make_date_cell_data(&self, cell_meta: &Option<CellMeta>) -> FlowyResult<DateCellData> { fn date_desc_from_timestamp(&self, serde_cell_data: &DateCellDataSerde) -> String {
if cell_meta.is_none() {
return Ok(DateCellData::default());
}
let json = &cell_meta.as_ref().unwrap().data;
let result = TypeOptionCellData::from_str(json);
if result.is_err() {
return Ok(DateCellData::default());
}
let serde_cell_data = DateCellDataSerde::from_str(&result.unwrap().data)?;
let date = self.decode_cell_data_from_timestamp(&serde_cell_data).content;
let time = serde_cell_data.time.unwrap_or_else(|| "".to_owned());
let timestamp = serde_cell_data.timestamp;
Ok(DateCellData { date, time, timestamp })
}
fn decode_cell_data_from_timestamp(&self, serde_cell_data: &DateCellDataSerde) -> DecodedCellData {
if serde_cell_data.timestamp == 0 { if serde_cell_data.timestamp == 0 {
return DecodedCellData::default(); return "".to_owned();
} }
let cell_content = self.today_desc_from_timestamp(serde_cell_data.timestamp, &serde_cell_data.time); self.today_desc_from_timestamp(serde_cell_data.timestamp, &serde_cell_data.time)
DecodedCellData::new(serde_cell_data.timestamp.to_string(), cell_content)
} }
fn timestamp_from_utc_with_time( fn timestamp_from_utc_with_time(
@ -156,7 +134,11 @@ impl CellDataOperation<EncodedCellData<DateCellDataSerde>, DateCellDataSerde> fo
} }
let encoded_data = encoded_data.into().try_into_inner()?; let encoded_data = encoded_data.into().try_into_inner()?;
Ok(self.decode_cell_data_from_timestamp(&encoded_data)) let date = self.date_desc_from_timestamp(&encoded_data);
let time = encoded_data.time.unwrap_or_else(|| "".to_owned());
let timestamp = encoded_data.timestamp;
DecodedCellData::try_from_bytes(DateCellData { date, time, timestamp })
} }
fn apply_changeset<C>(&self, changeset: C, _cell_meta: Option<CellMeta>) -> Result<DateCellDataSerde, FlowyError> fn apply_changeset<C>(&self, changeset: C, _cell_meta: Option<CellMeta>) -> Result<DateCellDataSerde, FlowyError>
@ -417,20 +399,27 @@ impl std::convert::From<DateCellContentChangeset> for CellContentChangeset {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::services::field::FieldBuilder; use crate::services::field::FieldBuilder;
use crate::services::field::{DateCellContentChangeset, DateCellDataSerde, DateFormat, DateTypeOption, TimeFormat}; use crate::services::field::{
use crate::services::row::{ DateCellContentChangeset, DateCellData, DateCellDataSerde, DateFormat, DateTypeOption, TimeFormat,
apply_cell_data_changeset, decode_cell_data_from_type_option_cell_data, CellDataOperation, EncodedCellData,
}; };
use crate::services::row::{CellDataOperation, EncodedCellData};
use flowy_grid_data_model::entities::{FieldMeta, FieldType}; use flowy_grid_data_model::entities::{FieldMeta, FieldType};
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
#[test] #[test]
fn date_description_invalid_input_test() { fn date_description_invalid_input_test() {
let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); let type_option = DateTypeOption::default();
let data = apply_cell_data_changeset("1e", None, &field_meta).unwrap(); let field_type = FieldType::DateTime;
assert_eq!( let field_meta = FieldBuilder::from_field_type(&field_type).build();
decode_cell_data_from_type_option_cell_data(data, &field_meta, &field_meta.field_type).content, assert_changeset_result(
"".to_owned() &type_option,
DateCellContentChangeset {
date: Some("1e".to_string()),
time: Some("23:00".to_owned()),
},
&field_type,
&field_meta,
"",
); );
} }
@ -442,40 +431,16 @@ mod tests {
type_option.date_format = date_format; type_option.date_format = date_format;
match date_format { match date_format {
DateFormat::Friendly => { DateFormat::Friendly => {
assert_eq!( assert_decode_timestamp(1647251762, &type_option, &field_meta, "Mar 14,2022");
"Mar 14,2022".to_owned(),
type_option
.decode_cell_data(data(1647251762), &FieldType::DateTime, &field_meta)
.unwrap()
.content
);
} }
DateFormat::US => { DateFormat::US => {
assert_eq!( assert_decode_timestamp(1647251762, &type_option, &field_meta, "2022/03/14");
"2022/03/14".to_owned(),
type_option
.decode_cell_data(data(1647251762), &FieldType::DateTime, &field_meta)
.unwrap()
.content
);
} }
DateFormat::ISO => { DateFormat::ISO => {
assert_eq!( assert_decode_timestamp(1647251762, &type_option, &field_meta, "2022-03-14");
"2022-03-14".to_owned(),
type_option
.decode_cell_data(data(1647251762), &FieldType::DateTime, &field_meta)
.unwrap()
.content
);
} }
DateFormat::Local => { DateFormat::Local => {
assert_eq!( assert_decode_timestamp(1647251762, &type_option, &field_meta, "2022/03/14");
"2022/03/14".to_owned(),
type_option
.decode_cell_data(data(1647251762), &FieldType::DateTime, &field_meta)
.unwrap()
.content
);
} }
} }
} }
@ -483,43 +448,6 @@ mod tests {
#[test] #[test]
fn date_description_time_format_test() { fn date_description_time_format_test() {
let mut type_option = DateTypeOption::default();
let field_meta = FieldBuilder::from_field_type(&FieldType::DateTime).build();
for time_format in TimeFormat::iter() {
type_option.time_format = time_format;
match time_format {
TimeFormat::TwentyFourHour => {
assert_eq!(
"Mar 14,2022".to_owned(),
type_option.today_desc_from_timestamp(1647251762, &None)
);
assert_eq!(
"Mar 14,2022".to_owned(),
type_option
.decode_cell_data(data(1647251762), &FieldType::DateTime, &field_meta)
.unwrap()
.content
);
}
TimeFormat::TwelveHour => {
assert_eq!(
"Mar 14,2022".to_owned(),
type_option.today_desc_from_timestamp(1647251762, &None)
);
assert_eq!(
"Mar 14,2022".to_owned(),
type_option
.decode_cell_data(data(1647251762), &FieldType::DateTime, &field_meta)
.unwrap()
.content
);
}
}
}
}
#[test]
fn date_description_time_format_test2() {
let mut type_option = DateTypeOption::default(); let mut type_option = DateTypeOption::default();
let field_type = FieldType::DateTime; let field_type = FieldType::DateTime;
let field_meta = FieldBuilder::from_field_type(&field_type).build(); let field_meta = FieldBuilder::from_field_type(&field_type).build();
@ -529,7 +457,7 @@ mod tests {
type_option.include_time = true; type_option.include_time = true;
match time_format { match time_format {
TimeFormat::TwentyFourHour => { TimeFormat::TwentyFourHour => {
assert_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellContentChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
@ -539,7 +467,7 @@ mod tests {
&field_meta, &field_meta,
"May 27,2022 00:00", "May 27,2022 00:00",
); );
assert_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellContentChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
@ -551,7 +479,7 @@ mod tests {
); );
} }
TimeFormat::TwelveHour => { TimeFormat::TwelveHour => {
assert_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellContentChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
@ -562,7 +490,7 @@ mod tests {
"May 27,2022 12:00 AM", "May 27,2022 12:00 AM",
); );
assert_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellContentChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
@ -573,7 +501,7 @@ mod tests {
"May 27,2022", "May 27,2022",
); );
assert_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellContentChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
@ -595,7 +523,7 @@ mod tests {
let field_meta = FieldBuilder::from_field_type(&field_type).build(); let field_meta = FieldBuilder::from_field_type(&field_type).build();
let date_timestamp = "1653609600".to_owned(); let date_timestamp = "1653609600".to_owned();
assert_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellContentChangeset {
date: Some(date_timestamp.clone()), date: Some(date_timestamp.clone()),
@ -607,7 +535,7 @@ mod tests {
); );
type_option.include_time = true; type_option.include_time = true;
assert_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellContentChangeset {
date: Some(date_timestamp.clone()), date: Some(date_timestamp.clone()),
@ -618,7 +546,7 @@ mod tests {
"May 27,2022 00:00", "May 27,2022 00:00",
); );
assert_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellContentChangeset {
date: Some(date_timestamp.clone()), date: Some(date_timestamp.clone()),
@ -630,7 +558,7 @@ mod tests {
); );
type_option.time_format = TimeFormat::TwelveHour; type_option.time_format = TimeFormat::TwelveHour;
assert_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellContentChangeset {
date: Some(date_timestamp), date: Some(date_timestamp),
@ -670,22 +598,39 @@ mod tests {
type_option.apply_changeset("he", None).unwrap(); type_option.apply_changeset("he", None).unwrap();
} }
fn data(s: i64) -> String { fn assert_changeset_result(
serde_json::to_string(&DateCellDataSerde::from_timestamp(s, None)).unwrap()
}
fn assert_result(
type_option: &DateTypeOption, type_option: &DateTypeOption,
changeset: DateCellContentChangeset, changeset: DateCellContentChangeset,
field_type: &FieldType, _field_type: &FieldType,
field_meta: &FieldMeta, field_meta: &FieldMeta,
expected: &str, expected: &str,
) { ) {
let encoded_data = EncodedCellData(Some(type_option.apply_changeset(changeset, None).unwrap())); let encoded_data = EncodedCellData(Some(type_option.apply_changeset(changeset, None).unwrap()));
let content = type_option assert_eq!(
.decode_cell_data(encoded_data, field_type, field_meta) expected.to_owned(),
decode_cell_data(encoded_data, type_option, field_meta)
);
}
fn assert_decode_timestamp(timestamp: i64, type_option: &DateTypeOption, field_meta: &FieldMeta, expected: &str) {
let serde_json = DateCellDataSerde { timestamp, time: None }.to_string();
assert_eq!(
expected.to_owned(),
decode_cell_data(serde_json, type_option, field_meta)
);
}
fn decode_cell_data<T: Into<EncodedCellData<DateCellDataSerde>>>(
encoded_data: T,
type_option: &DateTypeOption,
field_meta: &FieldMeta,
) -> String {
type_option
.decode_cell_data(encoded_data, &FieldType::DateTime, &field_meta)
.unwrap() .unwrap()
.content; .parse::<DateCellData>()
assert_eq!(expected.to_owned(), content); .unwrap()
.date
} }
} }

View File

@ -94,22 +94,22 @@ impl CellDataOperation<String, String> for NumberTypeOption {
match self.format { match self.format {
NumberFormat::Number => { NumberFormat::Number => {
if let Ok(v) = cell_data.parse::<f64>() { if let Ok(v) = cell_data.parse::<f64>() {
return Ok(DecodedCellData::from_content(v.to_string())); return Ok(DecodedCellData::new(v.to_string()));
} }
if let Ok(v) = cell_data.parse::<i64>() { if let Ok(v) = cell_data.parse::<i64>() {
return Ok(DecodedCellData::from_content(v.to_string())); return Ok(DecodedCellData::new(v.to_string()));
} }
Ok(DecodedCellData::default()) Ok(DecodedCellData::default())
} }
NumberFormat::Percent => { NumberFormat::Percent => {
let content = cell_data.parse::<f64>().map_or(String::new(), |v| v.to_string()); let content = cell_data.parse::<f64>().map_or(String::new(), |v| v.to_string());
Ok(DecodedCellData::from_content(content)) Ok(DecodedCellData::new(content))
} }
_ => { _ => {
let content = self.money_from_str(&cell_data); let content = self.money_from_str(&cell_data);
Ok(DecodedCellData::from_content(content)) Ok(DecodedCellData::new(content))
} }
} }
} }
@ -738,7 +738,7 @@ mod tests {
type_option type_option
.decode_cell_data(data(cell_data), field_type, field_meta) .decode_cell_data(data(cell_data), field_type, field_meta)
.unwrap() .unwrap()
.content, .to_string(),
expected_str.to_owned() expected_str.to_owned()
); );
} }

View File

@ -109,18 +109,20 @@ impl CellDataOperation<String, String> for SingleSelectTypeOption {
return Ok(DecodedCellData::default()); return Ok(DecodedCellData::default());
} }
let cell_data = encoded_data.into(); let encoded_data = encoded_data.into();
if let Some(option_id) = select_option_ids(cell_data).first() { let mut cell_data = SelectOptionCellData {
let data = match self.options.iter().find(|option| &option.id == option_id) { options: self.options.clone(),
None => DecodedCellData::default(), select_options: vec![],
Some(option) => DecodedCellData::from_content(option.name.clone()),
}; };
Ok(data) if let Some(option_id) = select_option_ids(encoded_data).first() {
} else { if let Some(option) = self.options.iter().find(|option| &option.id == option_id) {
Ok(DecodedCellData::default()) cell_data.select_options.push(option.clone());
} }
} }
DecodedCellData::try_from_bytes(cell_data)
}
fn apply_changeset<C>(&self, changeset: C, _cell_meta: Option<CellMeta>) -> Result<String, FlowyError> fn apply_changeset<C>(&self, changeset: C, _cell_meta: Option<CellMeta>) -> Result<String, FlowyError>
where where
C: Into<CellContentChangeset>, C: Into<CellContentChangeset>,
@ -204,17 +206,21 @@ impl CellDataOperation<String, String> for MultiSelectTypeOption {
if !decoded_field_type.is_select_option() { if !decoded_field_type.is_select_option() {
return Ok(DecodedCellData::default()); return Ok(DecodedCellData::default());
} }
let cell_data = encoded_data.into();
let option_ids = select_option_ids(cell_data);
let content = self
.options
.iter()
.filter(|option| option_ids.contains(&option.id))
.map(|option| option.name.clone())
.collect::<Vec<String>>()
.join(SELECTION_IDS_SEPARATOR);
Ok(DecodedCellData::from_content(content)) tracing::info!("😁{}", self.options.len());
let encoded_data = encoded_data.into();
let select_options = select_option_ids(encoded_data)
.into_iter()
.flat_map(|option_id| self.options.iter().find(|option| option.id == option_id).cloned())
.collect::<Vec<SelectOption>>();
let cell_data = SelectOptionCellData {
options: self.options.clone(),
select_options,
};
DecodedCellData::try_from_bytes(cell_data)
} }
fn apply_changeset<T>(&self, changeset: T, cell_meta: Option<CellMeta>) -> Result<String, FlowyError> fn apply_changeset<T>(&self, changeset: T, cell_meta: Option<CellMeta>) -> Result<String, FlowyError>
@ -280,7 +286,7 @@ fn select_option_ids(data: String) -> Vec<String> {
.collect::<Vec<String>>() .collect::<Vec<String>>()
} }
#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)]
pub struct SelectOption { pub struct SelectOption {
#[pb(index = 1)] #[pb(index = 1)]
pub id: String, pub id: String,
@ -446,7 +452,7 @@ pub struct SelectOptionCellData {
pub select_options: Vec<SelectOption>, pub select_options: Vec<SelectOption>,
} }
#[derive(ProtoBuf_Enum, Serialize, Deserialize, Debug, Clone)] #[derive(ProtoBuf_Enum, PartialEq, Eq, Serialize, Deserialize, Debug, Clone)]
#[repr(u8)] #[repr(u8)]
pub enum SelectOptionColor { pub enum SelectOptionColor {
Purple = 0, Purple = 0,
@ -502,9 +508,10 @@ mod tests {
use crate::services::field::FieldBuilder; use crate::services::field::FieldBuilder;
use crate::services::field::{ use crate::services::field::{
MultiSelectTypeOption, MultiSelectTypeOptionBuilder, SelectOption, SelectOptionCellContentChangeset, MultiSelectTypeOption, MultiSelectTypeOptionBuilder, SelectOption, SelectOptionCellContentChangeset,
SingleSelectTypeOption, SingleSelectTypeOptionBuilder, SELECTION_IDS_SEPARATOR, SelectOptionCellData, SingleSelectTypeOption, SingleSelectTypeOptionBuilder, SELECTION_IDS_SEPARATOR,
}; };
use crate::services::row::CellDataOperation; use crate::services::row::CellDataOperation;
use flowy_grid_data_model::entities::FieldMeta;
#[test] #[test]
fn single_select_test() { fn single_select_test() {
@ -526,47 +533,24 @@ mod tests {
let option_ids = vec![google_option.id.clone(), facebook_option.id].join(SELECTION_IDS_SEPARATOR); let option_ids = vec![google_option.id.clone(), facebook_option.id].join(SELECTION_IDS_SEPARATOR);
let data = SelectOptionCellContentChangeset::from_insert(&option_ids).to_str(); let data = SelectOptionCellContentChangeset::from_insert(&option_ids).to_str();
let cell_data = type_option.apply_changeset(data, None).unwrap(); let cell_data = type_option.apply_changeset(data, None).unwrap();
assert_eq!( assert_single_select_options(cell_data, &type_option, &field_meta, vec![google_option.clone()]);
type_option
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta)
.unwrap()
.content,
google_option.name,
);
let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str(); let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str();
let cell_data = type_option.apply_changeset(data, None).unwrap(); let cell_data = type_option.apply_changeset(data, None).unwrap();
assert_eq!( assert_single_select_options(cell_data, &type_option, &field_meta, vec![google_option.clone()]);
type_option
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta)
.unwrap()
.content,
google_option.name,
);
// Invalid option id // Invalid option id
let cell_data = type_option let cell_data = type_option
.apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None) .apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None)
.unwrap(); .unwrap();
assert_eq!( assert_single_select_options(cell_data, &type_option, &field_meta, vec![]);
type_option
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta)
.unwrap()
.content,
"",
);
// Invalid option id // Invalid option id
let cell_data = type_option let cell_data = type_option
.apply_changeset(SelectOptionCellContentChangeset::from_insert("123").to_str(), None) .apply_changeset(SelectOptionCellContentChangeset::from_insert("123").to_str(), None)
.unwrap(); .unwrap();
assert_eq!(
type_option assert_single_select_options(cell_data, &type_option, &field_meta, vec![]);
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta)
.unwrap()
.content,
"",
);
// Invalid changeset // Invalid changeset
assert!(type_option.apply_changeset("123", None).is_err()); assert!(type_option.apply_changeset("123", None).is_err());
@ -592,49 +576,64 @@ mod tests {
let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR);
let data = SelectOptionCellContentChangeset::from_insert(&option_ids).to_str(); let data = SelectOptionCellContentChangeset::from_insert(&option_ids).to_str();
let cell_data = type_option.apply_changeset(data, None).unwrap(); let cell_data = type_option.apply_changeset(data, None).unwrap();
assert_eq!( assert_multi_select_options(
type_option cell_data,
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta) &type_option,
.unwrap() &field_meta,
.content, vec![google_option.clone(), facebook_option.clone()],
vec![google_option.name.clone(), facebook_option.name].join(SELECTION_IDS_SEPARATOR),
); );
let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str(); let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str();
let cell_data = type_option.apply_changeset(data, None).unwrap(); let cell_data = type_option.apply_changeset(data, None).unwrap();
assert_eq!( assert_multi_select_options(cell_data, &type_option, &field_meta, vec![google_option.clone()]);
type_option
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta)
.unwrap()
.content,
google_option.name,
);
// Invalid option id // Invalid option id
let cell_data = type_option let cell_data = type_option
.apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None) .apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None)
.unwrap(); .unwrap();
assert_eq!( assert_multi_select_options(cell_data, &type_option, &field_meta, vec![]);
type_option
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta)
.unwrap()
.content,
"",
);
// Invalid option id // Invalid option id
let cell_data = type_option let cell_data = type_option
.apply_changeset(SelectOptionCellContentChangeset::from_insert("123,456").to_str(), None) .apply_changeset(SelectOptionCellContentChangeset::from_insert("123,456").to_str(), None)
.unwrap(); .unwrap();
assert_eq!( assert_multi_select_options(cell_data, &type_option, &field_meta, vec![]);
type_option
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta)
.unwrap()
.content,
"",
);
// Invalid changeset // Invalid changeset
assert!(type_option.apply_changeset("123", None).is_err()); assert!(type_option.apply_changeset("123", None).is_err());
} }
fn assert_multi_select_options(
cell_data: String,
type_option: &MultiSelectTypeOption,
field_meta: &FieldMeta,
expected: Vec<SelectOption>,
) {
assert_eq!(
expected,
type_option
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta)
.unwrap()
.parse::<SelectOptionCellData>()
.unwrap()
.select_options,
);
}
fn assert_single_select_options(
cell_data: String,
type_option: &SingleSelectTypeOption,
field_meta: &FieldMeta,
expected: Vec<SelectOption>,
) {
assert_eq!(
expected,
type_option
.decode_cell_data(cell_data, &field_meta.field_type, &field_meta)
.unwrap()
.parse::<SelectOptionCellData>()
.unwrap()
.select_options,
);
}
} }

View File

@ -49,7 +49,7 @@ impl CellDataOperation<String, String> for RichTextTypeOption {
decode_cell_data(encoded_data, decoded_field_type, decoded_field_type, field_meta) decode_cell_data(encoded_data, decoded_field_type, decoded_field_type, field_meta)
} else { } else {
let cell_data = encoded_data.into(); let cell_data = encoded_data.into();
Ok(DecodedCellData::from_content(cell_data)) Ok(DecodedCellData::new(cell_data))
} }
} }
@ -85,22 +85,26 @@ mod tests {
type_option type_option
.decode_cell_data(json, &field_type, &date_time_field_meta) .decode_cell_data(json, &field_type, &date_time_field_meta)
.unwrap() .unwrap()
.content, .parse::<DateCellData>()
.unwrap()
.date,
"Mar 14,2022".to_owned() "Mar 14,2022".to_owned()
); );
// Single select // Single select
let done_option = SelectOption::new("Done"); let done_option = SelectOption::new("Done");
let done_option_id = done_option.id.clone(); let done_option_id = done_option.id.clone();
let single_select = SingleSelectTypeOptionBuilder::default().option(done_option); let single_select = SingleSelectTypeOptionBuilder::default().option(done_option.clone());
let single_select_field_meta = FieldBuilder::new(single_select).build(); let single_select_field_meta = FieldBuilder::new(single_select).build();
assert_eq!( assert_eq!(
type_option type_option
.decode_cell_data(done_option_id, &FieldType::SingleSelect, &single_select_field_meta) .decode_cell_data(done_option_id, &FieldType::SingleSelect, &single_select_field_meta)
.unwrap() .unwrap()
.content, .parse::<SelectOptionCellData>()
"Done".to_owned() .unwrap()
.select_options,
vec![done_option],
); );
// Multiple select // Multiple select
@ -109,8 +113,8 @@ mod tests {
let ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); let ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR);
let cell_data_changeset = SelectOptionCellContentChangeset::from_insert(&ids).to_str(); let cell_data_changeset = SelectOptionCellContentChangeset::from_insert(&ids).to_str();
let multi_select = MultiSelectTypeOptionBuilder::default() let multi_select = MultiSelectTypeOptionBuilder::default()
.option(google_option) .option(google_option.clone())
.option(facebook_option); .option(facebook_option.clone());
let multi_select_field_meta = FieldBuilder::new(multi_select).build(); let multi_select_field_meta = FieldBuilder::new(multi_select).build();
let multi_type_option = MultiSelectTypeOption::from(&multi_select_field_meta); let multi_type_option = MultiSelectTypeOption::from(&multi_select_field_meta);
let cell_data = multi_type_option.apply_changeset(cell_data_changeset, None).unwrap(); let cell_data = multi_type_option.apply_changeset(cell_data_changeset, None).unwrap();
@ -118,8 +122,10 @@ mod tests {
type_option type_option
.decode_cell_data(cell_data, &FieldType::MultiSelect, &multi_select_field_meta) .decode_cell_data(cell_data, &FieldType::MultiSelect, &multi_select_field_meta)
.unwrap() .unwrap()
.content, .parse::<SelectOptionCellData>()
"Google,Facebook".to_owned() .unwrap()
.select_options,
vec![google_option, facebook_option]
); );
//Number //Number
@ -129,7 +135,7 @@ mod tests {
type_option type_option
.decode_cell_data("18443".to_owned(), &FieldType::Number, &number_field_meta) .decode_cell_data("18443".to_owned(), &FieldType::Number, &number_field_meta)
.unwrap() .unwrap()
.content, .to_string(),
"$18,443".to_owned() "$18,443".to_owned()
); );
} }

View File

@ -1,5 +1,6 @@
use crate::services::field::*; use crate::services::field::*;
use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use bytes::Bytes;
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{CellMeta, FieldMeta, FieldType}; use flowy_grid_data_model::entities::{CellMeta, FieldMeta, FieldType};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Formatter; use std::fmt::Formatter;
@ -145,8 +146,15 @@ pub fn decode_cell_data_from_type_option_cell_data<T: TryInto<TypeOptionCellData
) -> DecodedCellData { ) -> DecodedCellData {
if let Ok(type_option_cell_data) = data.try_into() { if let Ok(type_option_cell_data) = data.try_into() {
let (encoded_data, s_field_type) = type_option_cell_data.split(); let (encoded_data, s_field_type) = type_option_cell_data.split();
decode_cell_data(encoded_data, &s_field_type, field_type, field_meta).unwrap_or_default() match decode_cell_data(encoded_data, &s_field_type, field_type, field_meta) {
Ok(cell_data) => cell_data,
Err(e) => {
tracing::error!("Decode cell data failed, {:?}", e);
DecodedCellData::default()
}
}
} else { } else {
tracing::error!("Decode type option data failed");
DecodedCellData::default() DecodedCellData::default()
} }
} }
@ -158,6 +166,7 @@ pub fn decode_cell_data<T: Into<String>>(
field_meta: &FieldMeta, field_meta: &FieldMeta,
) -> FlowyResult<DecodedCellData> { ) -> FlowyResult<DecodedCellData> {
let encoded_data = encoded_data.into(); let encoded_data = encoded_data.into();
tracing::info!("😁{:?}", field_meta.type_options);
let get_cell_data = || { let get_cell_data = || {
let data = match t_field_type { let data = match t_field_type {
FieldType::RichText => field_meta FieldType::RichText => field_meta
@ -183,13 +192,7 @@ pub fn decode_cell_data<T: Into<String>>(
}; };
match get_cell_data() { match get_cell_data() {
Some(Ok(data)) => { Some(Ok(data)) => Ok(data),
tracing::Span::current().record(
"content",
&format!("{:?}: {}", field_meta.field_type, data.content).as_str(),
);
Ok(data)
}
Some(Err(err)) => { Some(Err(err)) => {
tracing::error!("{:?}", err); tracing::error!("{:?}", err);
Ok(DecodedCellData::default()) Ok(DecodedCellData::default())
@ -226,23 +229,40 @@ where
#[derive(Default)] #[derive(Default)]
pub struct DecodedCellData { pub struct DecodedCellData {
raw: String, pub data: Vec<u8>,
pub content: String,
} }
impl DecodedCellData { impl DecodedCellData {
pub fn from_content(content: String) -> Self { pub fn new<T: AsRef<[u8]>>(data: T) -> Self {
Self { Self {
raw: content.clone(), data: data.as_ref().to_vec(),
content,
} }
} }
pub fn new(raw: String, content: String) -> Self { pub fn try_from_bytes<T: TryInto<Bytes>>(bytes: T) -> FlowyResult<Self>
Self { raw, content } where
<T as TryInto<Bytes>>::Error: std::fmt::Debug,
{
let bytes = bytes.try_into().map_err(internal_error)?;
Ok(Self { data: bytes.to_vec() })
} }
pub fn split(self) -> (String, String) { pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult<T>
(self.raw, self.content) where
<T as TryFrom<&'a [u8]>>::Error: std::fmt::Debug,
{
T::try_from(self.data.as_ref()).map_err(internal_error)
}
}
impl ToString for DecodedCellData {
fn to_string(&self) -> String {
match String::from_utf8(self.data.clone()) {
Ok(s) => s,
Err(e) => {
tracing::error!("DecodedCellData to string failed: {:?}", e);
"".to_string()
}
}
} }
} }

View File

@ -31,17 +31,15 @@ pub fn make_cell_by_field_id(
cell_meta: CellMeta, cell_meta: CellMeta,
) -> Option<(String, Cell)> { ) -> Option<(String, Cell)> {
let field_meta = field_map.get(&field_id)?; let field_meta = field_map.get(&field_id)?;
let (raw, content) = let data = decode_cell_data_from_type_option_cell_data(cell_meta.data, field_meta, &field_meta.field_type).data;
decode_cell_data_from_type_option_cell_data(cell_meta.data, field_meta, &field_meta.field_type).split(); let cell = Cell::new(&field_id, data);
let cell = Cell::new(&field_id, content, raw);
Some((field_id, cell)) Some((field_id, cell))
} }
pub fn make_cell(field_id: &str, field_meta: &FieldMeta, row_meta: &RowMeta) -> Option<Cell> { pub fn make_cell(field_id: &str, field_meta: &FieldMeta, row_meta: &RowMeta) -> Option<Cell> {
let cell_meta = row_meta.cells.get(field_id)?.clone(); let cell_meta = row_meta.cells.get(field_id)?.clone();
let (raw, content) = let data = decode_cell_data_from_type_option_cell_data(cell_meta.data, field_meta, &field_meta.field_type).data;
decode_cell_data_from_type_option_cell_data(cell_meta.data, field_meta, &field_meta.field_type).split(); Some(Cell::new(field_id, data))
Some(Cell::new(field_id, content, raw))
} }
pub(crate) fn make_row_orders_from_row_metas(row_metas: &[Arc<RowMeta>]) -> Vec<RowOrder> { pub(crate) fn make_row_orders_from_row_metas(row_metas: &[Arc<RowMeta>]) -> Vec<RowOrder> {

View File

@ -2,7 +2,7 @@ use crate::grid::script::EditorScript::*;
use crate::grid::script::*; use crate::grid::script::*;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use flowy_grid::services::field::{ use flowy_grid::services::field::{
DateCellContentChangeset, MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset, DateCellContentChangeset, DateCellData, MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset,
SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
}; };
use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowMetaBuilder}; use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowMetaBuilder};
@ -292,8 +292,9 @@ async fn grid_row_add_date_cell_test() {
let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone(); let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
assert_eq!( assert_eq!(
decode_cell_data_from_type_option_cell_data(cell_data.data.clone(), &date_field, &date_field.field_type) decode_cell_data_from_type_option_cell_data(cell_data.data.clone(), &date_field, &date_field.field_type)
.split() .parse::<DateCellData>()
.1, .unwrap()
.date,
"2022/03/16", "2022/03/16",
); );
let scripts = vec![CreateRow { context }]; let scripts = vec![CreateRow { context }];

View File

@ -30,6 +30,14 @@ pub fn make_de_token_steam(ctxt: &Ctxt, ast: &ASTContainer) -> Option<TokenStrea
} }
} }
impl std::convert::TryFrom<&[u8]> for #struct_ident {
type Error = ::protobuf::ProtobufError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let pb: crate::protobuf::#pb_ty = ::protobuf::Message::parse_from_bytes(bytes)?;
#struct_ident::try_from(pb)
}
}
impl std::convert::TryFrom<crate::protobuf::#pb_ty> for #struct_ident { impl std::convert::TryFrom<crate::protobuf::#pb_ty> for #struct_ident {
type Error = ::protobuf::ProtobufError; type Error = ::protobuf::ProtobufError;
fn try_from(mut pb: crate::protobuf::#pb_ty) -> Result<Self, Self::Error> { fn try_from(mut pb: crate::protobuf::#pb_ty) -> Result<Self, Self::Error> {

View File

@ -484,17 +484,13 @@ pub struct Cell {
pub field_id: String, pub field_id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub content: String, pub data: Vec<u8>,
#[pb(index = 3)]
pub data: String,
} }
impl Cell { impl Cell {
pub fn new(field_id: &str, content: String, data: String) -> Self { pub fn new(field_id: &str, data: Vec<u8>) -> Self {
Self { Self {
field_id: field_id.to_owned(), field_id: field_id.to_owned(),
content,
data, data,
} }
} }
@ -502,8 +498,7 @@ impl Cell {
pub fn empty(field_id: &str) -> Self { pub fn empty(field_id: &str) -> Self {
Self { Self {
field_id: field_id.to_owned(), field_id: field_id.to_owned(),
content: "".to_string(), data: vec![],
data: "".to_string(),
} }
} }
} }

View File

@ -4743,8 +4743,7 @@ impl ::protobuf::reflect::ProtobufValue for GridBlock {
pub struct Cell { pub struct Cell {
// message fields // message fields
pub field_id: ::std::string::String, pub field_id: ::std::string::String,
pub content: ::std::string::String, pub data: ::std::vec::Vec<u8>,
pub data: ::std::string::String,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
@ -4787,36 +4786,10 @@ impl Cell {
::std::mem::replace(&mut self.field_id, ::std::string::String::new()) ::std::mem::replace(&mut self.field_id, ::std::string::String::new())
} }
// string content = 2; // bytes data = 2;
pub fn get_content(&self) -> &str { pub fn get_data(&self) -> &[u8] {
&self.content
}
pub fn clear_content(&mut self) {
self.content.clear();
}
// Param is passed by value, moved
pub fn set_content(&mut self, v: ::std::string::String) {
self.content = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_content(&mut self) -> &mut ::std::string::String {
&mut self.content
}
// Take field
pub fn take_content(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.content, ::std::string::String::new())
}
// string data = 3;
pub fn get_data(&self) -> &str {
&self.data &self.data
} }
pub fn clear_data(&mut self) { pub fn clear_data(&mut self) {
@ -4824,19 +4797,19 @@ impl Cell {
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_data(&mut self, v: ::std::string::String) { pub fn set_data(&mut self, v: ::std::vec::Vec<u8>) {
self.data = v; self.data = v;
} }
// Mutable pointer to the field. // Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first. // If field is not initialized, it is initialized with default value first.
pub fn mut_data(&mut self) -> &mut ::std::string::String { pub fn mut_data(&mut self) -> &mut ::std::vec::Vec<u8> {
&mut self.data &mut self.data
} }
// Take field // Take field
pub fn take_data(&mut self) -> ::std::string::String { pub fn take_data(&mut self) -> ::std::vec::Vec<u8> {
::std::mem::replace(&mut self.data, ::std::string::String::new()) ::std::mem::replace(&mut self.data, ::std::vec::Vec::new())
} }
} }
@ -4853,10 +4826,7 @@ impl ::protobuf::Message for Cell {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?;
}, },
2 => { 2 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.content)?; ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?;
},
3 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
}, },
_ => { _ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -4873,11 +4843,8 @@ impl ::protobuf::Message for Cell {
if !self.field_id.is_empty() { if !self.field_id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.field_id); my_size += ::protobuf::rt::string_size(1, &self.field_id);
} }
if !self.content.is_empty() {
my_size += ::protobuf::rt::string_size(2, &self.content);
}
if !self.data.is_empty() { if !self.data.is_empty() {
my_size += ::protobuf::rt::string_size(3, &self.data); my_size += ::protobuf::rt::bytes_size(2, &self.data);
} }
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size); self.cached_size.set(my_size);
@ -4888,11 +4855,8 @@ impl ::protobuf::Message for Cell {
if !self.field_id.is_empty() { if !self.field_id.is_empty() {
os.write_string(1, &self.field_id)?; os.write_string(1, &self.field_id)?;
} }
if !self.content.is_empty() {
os.write_string(2, &self.content)?;
}
if !self.data.is_empty() { if !self.data.is_empty() {
os.write_string(3, &self.data)?; os.write_bytes(2, &self.data)?;
} }
os.write_unknown_fields(self.get_unknown_fields())?; os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(()) ::std::result::Result::Ok(())
@ -4937,12 +4901,7 @@ impl ::protobuf::Message for Cell {
|m: &Cell| { &m.field_id }, |m: &Cell| { &m.field_id },
|m: &mut Cell| { &mut m.field_id }, |m: &mut Cell| { &mut m.field_id },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
"content",
|m: &Cell| { &m.content },
|m: &mut Cell| { &mut m.content },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"data", "data",
|m: &Cell| { &m.data }, |m: &Cell| { &m.data },
|m: &mut Cell| { &mut m.data }, |m: &mut Cell| { &mut m.data },
@ -4964,7 +4923,6 @@ impl ::protobuf::Message for Cell {
impl ::protobuf::Clear for Cell { impl ::protobuf::Clear for Cell {
fn clear(&mut self) { fn clear(&mut self) {
self.field_id.clear(); self.field_id.clear();
self.content.clear();
self.data.clear(); self.data.clear();
self.unknown_fields.clear(); self.unknown_fields.clear();
} }
@ -8340,50 +8298,49 @@ static file_descriptor_proto_data: &'static [u8] = b"\
derR\x0bdeletedRows\x123\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\x10.Upd\ derR\x0bdeletedRows\x123\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\x10.Upd\
atedRowOrderR\x0bupdatedRows\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\ atedRowOrderR\x0bupdatedRows\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\
\x01(\tR\x02id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trow\ \x01(\tR\x02id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trow\
Orders\"O\n\x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\ Orders\"5\n\x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\
\x12\x18\n\x07content\x18\x02\x20\x01(\tR\x07content\x12\x12\n\x04data\ \x12\x12\n\x04data\x18\x02\x20\x01(\x0cR\x04data\"+\n\x0cRepeatedCell\
\x18\x03\x20\x01(\tR\x04data\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\ \x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11Cre\
\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\ ateGridPayload\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06\
\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05va\ GridId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlock\
lue\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\x12\x14\n\x05value\ Id\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayl\
\x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\n\x07grid\ oad\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_\
_id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_row_id\x18\x02\x20\ row_id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\
\x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12Ins\ \"\xb6\x01\n\x12InsertFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\
ertFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\ \tR\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.FieldR\x05fie\
\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\x12(\n\x10type\ ld\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\
_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\n\x0estart_fie\ \x12&\n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\
ld_id\x18\x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_fiel\ \x15one_of_start_field_id\"|\n\x1cUpdateFieldTypeOptionPayload\x12\x17\n\
d_id\"|\n\x1cUpdateFieldTypeOptionPayload\x12\x17\n\x07grid_id\x18\x01\ \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\
\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fiel\ \x20\x01(\tR\x07fieldId\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\
dId\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\"\ \x0etypeOptionData\"d\n\x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\
d\n\x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gri\ \x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\
dId\x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\ \x13.RepeatedFieldOrderR\x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\
\x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\ \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orde\
\x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\ rs\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\
\x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\x15FieldChangesetPayload\ \x15FieldChangesetPayload\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07f\
\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_\ ieldId\x12\x17\n\x07grid_id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04n\
id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\x18\x03\x20\x01(\tH\0\ ame\x18\x03\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\
R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfie\ \x01R\x04desc\x12+\n\nfield_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\
ld_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\n\x06\ \tfieldType\x12\x18\n\x06frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\
frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\x18\ \x20\n\nvisibility\x18\x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05w\
\x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x08\x20\x01(\ idth\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10type_option_data\x18\
\x05H\x05R\x05width\x12*\n\x10type_option_data\x18\t\x20\x01(\x0cH\x06R\ \t\x20\x01(\x0cH\x06R\x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_\
\x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\x11one\ of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_\
_of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\x0e\n\ of_visibilityB\x0e\n\x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\
\x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\x9c\x01\n\x0fMoveIt\ \x9c\x01\n\x0fMoveItemPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
emPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x17\n\ \x06gridId\x12\x17\n\x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\
\x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\nfrom_index\x18\x03\ \nfrom_index\x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\
\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\x04\x20\x01(\x05R\ \x04\x20\x01(\x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.Mo\
\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.MoveItemTypeR\x02ty\ veItemTypeR\x02ty\"\xb3\x01\n\rCellChangeset\x12\x17\n\x07grid_id\x18\
\"\xb3\x01\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06\ \x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05ro\
gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08fie\ wId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07fieldId\x126\n\x16cell_\
ld_id\x18\x03\x20\x01(\tR\x07fieldId\x126\n\x16cell_content_changeset\ content_changeset\x18\x04\x20\x01(\tH\0R\x14cellContentChangesetB\x1f\n\
\x18\x04\x20\x01(\tH\0R\x14cellContentChangesetB\x1f\n\x1done_of_cell_co\ \x1done_of_cell_content_changeset**\n\x0cMoveItemType\x12\r\n\tMoveField\
ntent_changeset**\n\x0cMoveItemType\x12\r\n\tMoveField\x10\0\x12\x0b\n\ \x10\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08RichText\
\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\0\x12\n\n\ \x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\
\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0cSingleSele\ \x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08C\
ct\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\ heckbox\x10\x05b\x06proto3\
\x05b\x06proto3\
"; ";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -95,8 +95,7 @@ message GridBlock {
} }
message Cell { message Cell {
string field_id = 1; string field_id = 1;
string content = 2; bytes data = 2;
string data = 3;
} }
message RepeatedCell { message RepeatedCell {
repeated Cell items = 1; repeated Cell items = 1;