mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: Merge branch 'main' into feat_grid_url
# Conflicts: # frontend/rust-lib/flowy-grid/src/event_handler.rs # shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs
This commit is contained in:
commit
9844c02cbc
@ -7,6 +7,7 @@ extend = [
|
|||||||
{ path = "scripts/makefile/docker.toml" },
|
{ path = "scripts/makefile/docker.toml" },
|
||||||
{ path = "scripts/makefile/env.toml" },
|
{ path = "scripts/makefile/env.toml" },
|
||||||
{ path = "scripts/makefile/flutter.toml" },
|
{ path = "scripts/makefile/flutter.toml" },
|
||||||
|
{ path = "scripts/makefile/tool.toml" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[config]
|
[config]
|
||||||
|
@ -15,7 +15,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';
|
||||||
|
@ -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>;
|
||||||
typedef GridURLCellContext = _GridCellContext<Cell, String>;
|
typedef GridURLCellContext = _GridCellContext<Cell, String>;
|
||||||
@ -17,26 +17,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,
|
||||||
@ -45,26 +52,40 @@ 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),
|
||||||
);
|
);
|
||||||
|
|
||||||
case FieldType.URL:
|
case FieldType.URL:
|
||||||
|
final cellDataLoader = GridCellDataLoader(
|
||||||
|
gridCell: _gridCell,
|
||||||
|
parser: URLCellDataParser(),
|
||||||
|
);
|
||||||
return GridURLCellContext(
|
return GridURLCellContext(
|
||||||
gridCell: _gridCell,
|
gridCell: _gridCell,
|
||||||
cellCache: _cellCache,
|
cellCache: _cellCache,
|
||||||
cellDataLoader: GridCellDataLoader(gridCell: _gridCell),
|
cellDataLoader: cellDataLoader,
|
||||||
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -141,10 +162,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();
|
||||||
@ -159,9 +177,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;
|
||||||
|
@ -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) {
|
||||||
Log.error(err);
|
try {
|
||||||
|
return parser.parserData(cell.data);
|
||||||
|
} catch (e, s) {
|
||||||
|
Log.error('$parser parser cellData failed, $e');
|
||||||
|
Log.error('Stack trace \n $s');
|
||||||
return null;
|
return null;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}, (err) {
|
||||||
|
|
||||||
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);
|
Log.error(err);
|
||||||
return null;
|
return null;
|
||||||
},
|
}),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,3 +94,40 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class URLCellDataParser implements ICellDataParser<Cell> {
|
||||||
|
@override
|
||||||
|
Cell? parserData(List<int> data) {
|
||||||
|
if (data.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Cell.fromBuffer(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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";
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 ?? [],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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 ?? [],
|
||||||
|
@ -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() ?? "",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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)),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -290,13 +290,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',
|
||||||
|
@ -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);
|
||||||
|
@ -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=');
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
errors::FlowyResult,
|
errors::FlowyResult,
|
||||||
event_map::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser},
|
event_map::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser},
|
||||||
services::{
|
services::{
|
||||||
folder_editor::ClientFolderEditor, persistence::FolderPersistence, set_current_workspace, AppController,
|
folder_editor::FolderEditor, persistence::FolderPersistence, set_current_workspace, AppController,
|
||||||
TrashController, ViewController, WorkspaceController,
|
TrashController, ViewController, WorkspaceController,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -61,7 +61,7 @@ pub struct FolderManager {
|
|||||||
pub(crate) view_controller: Arc<ViewController>,
|
pub(crate) view_controller: Arc<ViewController>,
|
||||||
pub(crate) trash_controller: Arc<TrashController>,
|
pub(crate) trash_controller: Arc<TrashController>,
|
||||||
web_socket: Arc<dyn RevisionWebSocket>,
|
web_socket: Arc<dyn RevisionWebSocket>,
|
||||||
folder_editor: Arc<TokioRwLock<Option<Arc<ClientFolderEditor>>>>,
|
folder_editor: Arc<TokioRwLock<Option<Arc<FolderEditor>>>>,
|
||||||
data_processors: ViewDataProcessorMap,
|
data_processors: ViewDataProcessorMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,8 +166,7 @@ impl FolderManager {
|
|||||||
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache));
|
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache));
|
||||||
let rev_manager = RevisionManager::new(user_id, folder_id.as_ref(), rev_persistence);
|
let rev_manager = RevisionManager::new(user_id, folder_id.as_ref(), rev_persistence);
|
||||||
|
|
||||||
let folder_editor =
|
let folder_editor = FolderEditor::new(user_id, &folder_id, token, rev_manager, self.web_socket.clone()).await?;
|
||||||
ClientFolderEditor::new(user_id, &folder_id, token, rev_manager, self.web_socket.clone()).await?;
|
|
||||||
*self.folder_editor.write().await = Some(Arc::new(folder_editor));
|
*self.folder_editor.write().await = Some(Arc::new(folder_editor));
|
||||||
|
|
||||||
let _ = self.app_controller.initialize()?;
|
let _ = self.app_controller.initialize()?;
|
||||||
@ -228,7 +227,7 @@ impl DefaultFolderBuilder {
|
|||||||
|
|
||||||
#[cfg(feature = "flowy_unit_test")]
|
#[cfg(feature = "flowy_unit_test")]
|
||||||
impl FolderManager {
|
impl FolderManager {
|
||||||
pub async fn folder_editor(&self) -> Arc<ClientFolderEditor> {
|
pub async fn folder_editor(&self) -> Arc<FolderEditor> {
|
||||||
self.folder_editor.read().await.clone().unwrap()
|
self.folder_editor.read().await.clone().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ pub(crate) async fn update_app_handler(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, app_controller, view_controller))]
|
#[tracing::instrument(level = "trace", skip(data, app_controller, view_controller))]
|
||||||
pub(crate) async fn read_app_handler(
|
pub(crate) async fn read_app_handler(
|
||||||
data: Data<AppId>,
|
data: Data<AppId>,
|
||||||
app_controller: AppData<Arc<AppController>>,
|
app_controller: AppData<Arc<AppController>>,
|
||||||
|
@ -17,7 +17,7 @@ use lib_ot::core::PlainTextAttributes;
|
|||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub struct ClientFolderEditor {
|
pub struct FolderEditor {
|
||||||
user_id: String,
|
user_id: String,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) folder_id: FolderId,
|
pub(crate) folder_id: FolderId,
|
||||||
@ -27,7 +27,7 @@ pub struct ClientFolderEditor {
|
|||||||
ws_manager: Arc<flowy_revision::RevisionWebSocketManager>,
|
ws_manager: Arc<flowy_revision::RevisionWebSocketManager>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientFolderEditor {
|
impl FolderEditor {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
user_id: &str,
|
user_id: &str,
|
||||||
@ -129,7 +129,7 @@ impl RevisionCloudService for FolderRevisionCloudService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "flowy_unit_test")]
|
#[cfg(feature = "flowy_unit_test")]
|
||||||
impl ClientFolderEditor {
|
impl FolderEditor {
|
||||||
pub fn rev_manager(&self) -> Arc<RevisionManager> {
|
pub fn rev_manager(&self) -> Arc<RevisionManager> {
|
||||||
self.rev_manager.clone()
|
self.rev_manager.clone()
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ mod version_2;
|
|||||||
use crate::{
|
use crate::{
|
||||||
event_map::WorkspaceDatabase,
|
event_map::WorkspaceDatabase,
|
||||||
manager::FolderId,
|
manager::FolderId,
|
||||||
services::{folder_editor::ClientFolderEditor, persistence::migration::FolderMigration},
|
services::{folder_editor::FolderEditor, persistence::migration::FolderMigration},
|
||||||
};
|
};
|
||||||
use flowy_database::ConnectionPool;
|
use flowy_database::ConnectionPool;
|
||||||
use flowy_error::{FlowyError, FlowyResult};
|
use flowy_error::{FlowyError, FlowyResult};
|
||||||
@ -50,14 +50,11 @@ pub trait FolderPersistenceTransaction {
|
|||||||
|
|
||||||
pub struct FolderPersistence {
|
pub struct FolderPersistence {
|
||||||
database: Arc<dyn WorkspaceDatabase>,
|
database: Arc<dyn WorkspaceDatabase>,
|
||||||
folder_editor: Arc<RwLock<Option<Arc<ClientFolderEditor>>>>,
|
folder_editor: Arc<RwLock<Option<Arc<FolderEditor>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FolderPersistence {
|
impl FolderPersistence {
|
||||||
pub fn new(
|
pub fn new(database: Arc<dyn WorkspaceDatabase>, folder_editor: Arc<RwLock<Option<Arc<FolderEditor>>>>) -> Self {
|
||||||
database: Arc<dyn WorkspaceDatabase>,
|
|
||||||
folder_editor: Arc<RwLock<Option<Arc<ClientFolderEditor>>>>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
database,
|
database,
|
||||||
folder_editor,
|
folder_editor,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::services::{
|
use crate::services::{
|
||||||
folder_editor::ClientFolderEditor,
|
folder_editor::FolderEditor,
|
||||||
persistence::{AppChangeset, FolderPersistenceTransaction, ViewChangeset, WorkspaceChangeset},
|
persistence::{AppChangeset, FolderPersistenceTransaction, ViewChangeset, WorkspaceChangeset},
|
||||||
};
|
};
|
||||||
use flowy_error::{FlowyError, FlowyResult};
|
use flowy_error::{FlowyError, FlowyResult};
|
||||||
@ -11,7 +11,7 @@ use flowy_folder_data_model::entities::{
|
|||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
impl FolderPersistenceTransaction for ClientFolderEditor {
|
impl FolderPersistenceTransaction for FolderEditor {
|
||||||
fn create_workspace(&self, _user_id: &str, workspace: Workspace) -> FlowyResult<()> {
|
fn create_workspace(&self, _user_id: &str, workspace: Workspace) -> FlowyResult<()> {
|
||||||
if let Some(change) = self.folder.write().create_workspace(workspace)? {
|
if let Some(change) = self.folder.write().create_workspace(workspace)? {
|
||||||
let _ = self.apply_change(change)?;
|
let _ = self.apply_change(change)?;
|
||||||
|
@ -129,7 +129,7 @@ impl ViewController {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self), err)]
|
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||||
pub(crate) fn set_latest_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
pub(crate) fn set_latest_view(&self, view_id: &str) -> Result<(), FlowyError> {
|
||||||
KV::set_str(LATEST_VIEW_ID, view_id.to_owned());
|
KV::set_str(LATEST_VIEW_ID, view_id.to_owned());
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -193,7 +193,7 @@ impl ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// belong_to_id will be the app_id or view_id.
|
// belong_to_id will be the app_id or view_id.
|
||||||
#[tracing::instrument(level = "debug", skip(self), err)]
|
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||||
pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, FlowyError> {
|
pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, FlowyError> {
|
||||||
self.persistence
|
self.persistence
|
||||||
.begin_transaction(|transaction| {
|
.begin_transaction(|transaction| {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use flowy_folder::event_map::FolderEvent::*;
|
use flowy_folder::event_map::FolderEvent::*;
|
||||||
use flowy_folder::{errors::ErrorCode, services::folder_editor::ClientFolderEditor};
|
use flowy_folder::{errors::ErrorCode, services::folder_editor::FolderEditor};
|
||||||
use flowy_folder_data_model::entities::view::{RepeatedViewId, ViewId};
|
use flowy_folder_data_model::entities::view::{RepeatedViewId, ViewId};
|
||||||
use flowy_folder_data_model::entities::workspace::WorkspaceId;
|
use flowy_folder_data_model::entities::workspace::WorkspaceId;
|
||||||
use flowy_folder_data_model::entities::{
|
use flowy_folder_data_model::entities::{
|
||||||
@ -125,7 +125,7 @@ impl FolderTest {
|
|||||||
|
|
||||||
pub async fn run_script(&mut self, script: FolderScript) {
|
pub async fn run_script(&mut self, script: FolderScript) {
|
||||||
let sdk = &self.sdk;
|
let sdk = &self.sdk;
|
||||||
let folder_editor: Arc<ClientFolderEditor> = sdk.folder_manager.folder_editor().await;
|
let folder_editor: Arc<FolderEditor> = sdk.folder_manager.folder_editor().await;
|
||||||
let rev_manager = folder_editor.rev_manager();
|
let rev_manager = folder_editor.rev_manager();
|
||||||
let cache = rev_manager.revision_cache().await;
|
let cache = rev_manager.revision_cache().await;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use flowy_grid_data_model::entities::*;
|
|||||||
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
|
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn get_grid_data_handler(
|
pub(crate) async fn get_grid_data_handler(
|
||||||
data: Data<GridId>,
|
data: Data<GridId>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -34,7 +34,7 @@ pub(crate) async fn get_grid_blocks_handler(
|
|||||||
data_result(repeated_grid_block)
|
data_result(repeated_grid_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn get_fields_handler(
|
pub(crate) async fn get_fields_handler(
|
||||||
data: Data<QueryFieldPayload>,
|
data: Data<QueryFieldPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -47,7 +47,7 @@ pub(crate) async fn get_fields_handler(
|
|||||||
data_result(repeated_field)
|
data_result(repeated_field)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn update_field_handler(
|
pub(crate) async fn update_field_handler(
|
||||||
data: Data<FieldChangesetPayload>,
|
data: Data<FieldChangesetPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -58,7 +58,7 @@ pub(crate) async fn update_field_handler(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn insert_field_handler(
|
pub(crate) async fn insert_field_handler(
|
||||||
data: Data<InsertFieldPayload>,
|
data: Data<InsertFieldPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -69,7 +69,7 @@ pub(crate) async fn insert_field_handler(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn update_field_type_option_handler(
|
pub(crate) async fn update_field_type_option_handler(
|
||||||
data: Data<UpdateFieldTypeOptionPayload>,
|
data: Data<UpdateFieldTypeOptionPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -82,7 +82,7 @@ pub(crate) async fn update_field_type_option_handler(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn delete_field_handler(
|
pub(crate) async fn delete_field_handler(
|
||||||
data: Data<FieldIdentifierPayload>,
|
data: Data<FieldIdentifierPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -93,7 +93,7 @@ pub(crate) async fn delete_field_handler(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn switch_to_field_handler(
|
pub(crate) async fn switch_to_field_handler(
|
||||||
data: Data<EditFieldPayload>,
|
data: Data<EditFieldPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -120,7 +120,7 @@ pub(crate) async fn switch_to_field_handler(
|
|||||||
data_result(data)
|
data_result(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn duplicate_field_handler(
|
pub(crate) async fn duplicate_field_handler(
|
||||||
data: Data<FieldIdentifierPayload>,
|
data: Data<FieldIdentifierPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -132,7 +132,7 @@ pub(crate) async fn duplicate_field_handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the FieldTypeOptionData if the Field exists otherwise return record not found error.
|
/// Return the FieldTypeOptionData if the Field exists otherwise return record not found error.
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn get_field_type_option_data_handler(
|
pub(crate) async fn get_field_type_option_data_handler(
|
||||||
data: Data<EditFieldPayload>,
|
data: Data<EditFieldPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -154,7 +154,7 @@ pub(crate) async fn get_field_type_option_data_handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create FieldMeta and save it. Return the FieldTypeOptionData.
|
/// Create FieldMeta and save it. Return the FieldTypeOptionData.
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn create_field_type_option_data_handler(
|
pub(crate) async fn create_field_type_option_data_handler(
|
||||||
data: Data<EditFieldPayload>,
|
data: Data<EditFieldPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -171,7 +171,7 @@ pub(crate) async fn create_field_type_option_data_handler(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn move_item_handler(
|
pub(crate) async fn move_item_handler(
|
||||||
data: Data<MoveItemPayload>,
|
data: Data<MoveItemPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -252,7 +252,7 @@ pub(crate) async fn get_cell_handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||||
pub(crate) async fn update_cell_handler(
|
pub(crate) async fn update_cell_handler(
|
||||||
data: Data<CellChangeset>,
|
data: Data<CellChangeset>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -263,28 +263,7 @@ pub(crate) async fn update_cell_handler(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip_all, 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(¶ms.grid_id)?;
|
|
||||||
match editor.get_field_meta(¶ms.field_id).await {
|
|
||||||
None => {
|
|
||||||
tracing::error!("Can't find the date field with id: {}", params.field_id);
|
|
||||||
data_result(DateCellData::default())
|
|
||||||
}
|
|
||||||
Some(field_meta) => {
|
|
||||||
let cell_meta = editor.get_cell_meta(¶ms.row_id, ¶ms.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 = "debug", 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>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -301,7 +280,7 @@ pub(crate) async fn new_select_option_handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||||
pub(crate) async fn update_select_option_handler(
|
pub(crate) async fn update_select_option_handler(
|
||||||
data: Data<SelectOptionChangesetPayload>,
|
data: Data<SelectOptionChangesetPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -341,7 +320,7 @@ pub(crate) async fn update_select_option_handler(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||||
pub(crate) async fn get_select_option_handler(
|
pub(crate) async fn get_select_option_handler(
|
||||||
data: Data<CellIdentifierPayload>,
|
data: Data<CellIdentifierPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -362,7 +341,7 @@ pub(crate) async fn get_select_option_handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||||
pub(crate) async fn update_select_option_cell_handler(
|
pub(crate) async fn update_select_option_cell_handler(
|
||||||
data: Data<SelectOptionCellChangesetPayload>,
|
data: Data<SelectOptionCellChangesetPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
@ -373,7 +352,7 @@ pub(crate) async fn update_select_option_cell_handler(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||||
pub(crate) async fn update_date_cell_handler(
|
pub(crate) async fn update_date_cell_handler(
|
||||||
data: Data<DateChangesetPayload>,
|
data: Data<DateChangesetPayload>,
|
||||||
manager: AppData<Arc<GridManager>>,
|
manager: AppData<Arc<GridManager>>,
|
||||||
|
@ -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,
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::services::grid_editor::ClientGridEditor;
|
use crate::services::grid_editor::GridMetaEditor;
|
||||||
use crate::services::persistence::block_index::BlockIndexPersistence;
|
use crate::services::persistence::block_index::BlockIndexCache;
|
||||||
use crate::services::persistence::kv::GridKVPersistence;
|
use crate::services::persistence::kv::GridKVPersistence;
|
||||||
use crate::services::persistence::GridDatabase;
|
use crate::services::persistence::GridDatabase;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
@ -20,9 +20,9 @@ pub trait GridUser: Send + Sync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct GridManager {
|
pub struct GridManager {
|
||||||
editor_map: Arc<GridEditorMap>,
|
editor_map: Arc<DashMap<String, Arc<GridMetaEditor>>>,
|
||||||
grid_user: Arc<dyn GridUser>,
|
grid_user: Arc<dyn GridUser>,
|
||||||
block_index_persistence: Arc<BlockIndexPersistence>,
|
block_index_cache: Arc<BlockIndexCache>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
kv_persistence: Arc<GridKVPersistence>,
|
kv_persistence: Arc<GridKVPersistence>,
|
||||||
}
|
}
|
||||||
@ -33,14 +33,14 @@ impl GridManager {
|
|||||||
_rev_web_socket: Arc<dyn RevisionWebSocket>,
|
_rev_web_socket: Arc<dyn RevisionWebSocket>,
|
||||||
database: Arc<dyn GridDatabase>,
|
database: Arc<dyn GridDatabase>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let grid_editors = Arc::new(GridEditorMap::new());
|
let grid_editors = Arc::new(DashMap::new());
|
||||||
let kv_persistence = Arc::new(GridKVPersistence::new(database.clone()));
|
let kv_persistence = Arc::new(GridKVPersistence::new(database.clone()));
|
||||||
let block_index_persistence = Arc::new(BlockIndexPersistence::new(database));
|
let block_index_persistence = Arc::new(BlockIndexCache::new(database));
|
||||||
Self {
|
Self {
|
||||||
editor_map: grid_editors,
|
editor_map: grid_editors,
|
||||||
grid_user,
|
grid_user,
|
||||||
kv_persistence,
|
kv_persistence,
|
||||||
block_index_persistence,
|
block_index_cache: block_index_persistence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ impl GridManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip_all, fields(grid_id), err)]
|
#[tracing::instrument(level = "debug", skip_all, fields(grid_id), err)]
|
||||||
pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<Arc<ClientGridEditor>> {
|
pub async fn open_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<Arc<GridMetaEditor>> {
|
||||||
let grid_id = grid_id.as_ref();
|
let grid_id = grid_id.as_ref();
|
||||||
tracing::Span::current().record("grid_id", &grid_id);
|
tracing::Span::current().record("grid_id", &grid_id);
|
||||||
self.get_or_create_grid_editor(grid_id).await
|
self.get_or_create_grid_editor(grid_id).await
|
||||||
@ -90,23 +90,27 @@ impl GridManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// #[tracing::instrument(level = "debug", skip(self), err)]
|
// #[tracing::instrument(level = "debug", skip(self), err)]
|
||||||
pub fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<ClientGridEditor>> {
|
pub fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<GridMetaEditor>> {
|
||||||
match self.editor_map.get(grid_id) {
|
match self.editor_map.get(grid_id) {
|
||||||
None => Err(FlowyError::internal().context("Should call open_grid function first")),
|
None => Err(FlowyError::internal().context("Should call open_grid function first")),
|
||||||
Some(editor) => Ok(editor),
|
Some(editor) => Ok(editor.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_or_create_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<ClientGridEditor>> {
|
async fn get_or_create_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<GridMetaEditor>> {
|
||||||
match self.editor_map.get(grid_id) {
|
match self.editor_map.get(grid_id) {
|
||||||
None => {
|
None => {
|
||||||
tracing::trace!("Create grid editor with id: {}", grid_id);
|
tracing::trace!("Create grid editor with id: {}", grid_id);
|
||||||
let db_pool = self.grid_user.db_pool()?;
|
let db_pool = self.grid_user.db_pool()?;
|
||||||
let editor = self.make_grid_editor(grid_id, db_pool).await?;
|
let editor = self.make_grid_editor(grid_id, db_pool).await?;
|
||||||
self.editor_map.insert(grid_id, &editor);
|
|
||||||
|
if self.editor_map.contains_key(grid_id) {
|
||||||
|
tracing::warn!("Grid:{} already exists in cache", grid_id);
|
||||||
|
}
|
||||||
|
self.editor_map.insert(grid_id.to_string(), editor.clone());
|
||||||
Ok(editor)
|
Ok(editor)
|
||||||
}
|
}
|
||||||
Some(editor) => Ok(editor),
|
Some(editor) => Ok(editor.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,11 +119,10 @@ impl GridManager {
|
|||||||
&self,
|
&self,
|
||||||
grid_id: &str,
|
grid_id: &str,
|
||||||
pool: Arc<ConnectionPool>,
|
pool: Arc<ConnectionPool>,
|
||||||
) -> Result<Arc<ClientGridEditor>, FlowyError> {
|
) -> Result<Arc<GridMetaEditor>, FlowyError> {
|
||||||
let user = self.grid_user.clone();
|
let user = self.grid_user.clone();
|
||||||
let rev_manager = self.make_grid_rev_manager(grid_id, pool.clone())?;
|
let rev_manager = self.make_grid_rev_manager(grid_id, pool.clone())?;
|
||||||
let grid_editor =
|
let grid_editor = GridMetaEditor::new(grid_id, user, rev_manager, self.block_index_cache.clone()).await?;
|
||||||
ClientGridEditor::new(grid_id, user, rev_manager, self.block_index_persistence.clone()).await?;
|
|
||||||
Ok(grid_editor)
|
Ok(grid_editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,31 +148,6 @@ impl GridManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GridEditorMap {
|
|
||||||
inner: DashMap<String, Arc<ClientGridEditor>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GridEditorMap {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self { inner: DashMap::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn insert(&self, grid_id: &str, grid_editor: &Arc<ClientGridEditor>) {
|
|
||||||
if self.inner.contains_key(grid_id) {
|
|
||||||
tracing::warn!("Grid:{} already exists in cache", grid_id);
|
|
||||||
}
|
|
||||||
self.inner.insert(grid_id.to_string(), grid_editor.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get(&self, grid_id: &str) -> Option<Arc<ClientGridEditor>> {
|
|
||||||
Some(self.inner.get(grid_id)?.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn remove(&self, grid_id: &str) {
|
|
||||||
self.inner.remove(grid_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn make_grid_view_data(
|
pub async fn make_grid_view_data(
|
||||||
user_id: &str,
|
user_id: &str,
|
||||||
view_id: &str,
|
view_id: &str,
|
||||||
@ -192,9 +170,7 @@ pub async fn make_grid_view_data(
|
|||||||
|
|
||||||
// Indexing the block's rows
|
// Indexing the block's rows
|
||||||
build_context.block_meta_data.rows.iter().for_each(|row| {
|
build_context.block_meta_data.rows.iter().for_each(|row| {
|
||||||
let _ = grid_manager
|
let _ = grid_manager.block_index_cache.insert(&row.block_id, &row.id);
|
||||||
.block_index_persistence
|
|
||||||
.insert_or_update(&row.block_id, &row.id);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create grid's block
|
// Create grid's block
|
||||||
|
@ -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;
|
||||||
|
@ -24,5 +24,4 @@ enum GridEvent {
|
|||||||
UpdateCell = 71;
|
UpdateCell = 71;
|
||||||
UpdateSelectOptionCell = 72;
|
UpdateSelectOptionCell = 72;
|
||||||
UpdateDateCell = 80;
|
UpdateDateCell = 80;
|
||||||
GetDateCellData = 90;
|
|
||||||
}
|
}
|
||||||
|
@ -8,18 +8,17 @@ use flowy_sync::util::make_delta_from_revisions;
|
|||||||
use lib_infra::future::FutureResult;
|
use lib_infra::future::FutureResult;
|
||||||
use lib_ot::core::PlainTextAttributes;
|
use lib_ot::core::PlainTextAttributes;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
pub struct ClientGridBlockMetaEditor {
|
pub struct GridBlockMetaEditor {
|
||||||
user_id: String,
|
user_id: String,
|
||||||
pub block_id: String,
|
pub block_id: String,
|
||||||
pad: Arc<RwLock<GridBlockMetaPad>>,
|
pad: Arc<RwLock<GridBlockMetaPad>>,
|
||||||
rev_manager: Arc<RevisionManager>,
|
rev_manager: Arc<RevisionManager>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientGridBlockMetaEditor {
|
impl GridBlockMetaEditor {
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
user_id: &str,
|
user_id: &str,
|
||||||
token: &str,
|
token: &str,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||||
use crate::manager::GridUser;
|
use crate::manager::GridUser;
|
||||||
use crate::services::block_meta_editor::ClientGridBlockMetaEditor;
|
use crate::services::block_meta_editor::GridBlockMetaEditor;
|
||||||
use crate::services::persistence::block_index::BlockIndexPersistence;
|
use crate::services::persistence::block_index::BlockIndexCache;
|
||||||
use crate::services::row::{group_row_orders, GridBlockSnapshot};
|
use crate::services::row::{group_row_orders, GridBlockSnapshot};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
@ -15,20 +15,20 @@ use std::borrow::Cow;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub(crate) struct GridBlockMetaEditorManager {
|
type BlockId = String;
|
||||||
|
pub(crate) struct GridBlockManager {
|
||||||
grid_id: String,
|
grid_id: String,
|
||||||
user: Arc<dyn GridUser>,
|
user: Arc<dyn GridUser>,
|
||||||
// Key: block_id
|
persistence: Arc<BlockIndexCache>,
|
||||||
editor_map: DashMap<String, Arc<ClientGridBlockMetaEditor>>,
|
block_editor_map: DashMap<BlockId, Arc<GridBlockMetaEditor>>,
|
||||||
persistence: Arc<BlockIndexPersistence>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GridBlockMetaEditorManager {
|
impl GridBlockManager {
|
||||||
pub(crate) async fn new(
|
pub(crate) async fn new(
|
||||||
grid_id: &str,
|
grid_id: &str,
|
||||||
user: &Arc<dyn GridUser>,
|
user: &Arc<dyn GridUser>,
|
||||||
blocks: Vec<GridBlockMeta>,
|
blocks: Vec<GridBlockMeta>,
|
||||||
persistence: Arc<BlockIndexPersistence>,
|
persistence: Arc<BlockIndexCache>,
|
||||||
) -> FlowyResult<Self> {
|
) -> FlowyResult<Self> {
|
||||||
let editor_map = make_block_meta_editor_map(user, blocks).await?;
|
let editor_map = make_block_meta_editor_map(user, blocks).await?;
|
||||||
let user = user.clone();
|
let user = user.clone();
|
||||||
@ -36,27 +36,27 @@ impl GridBlockMetaEditorManager {
|
|||||||
let manager = Self {
|
let manager = Self {
|
||||||
grid_id,
|
grid_id,
|
||||||
user,
|
user,
|
||||||
editor_map,
|
block_editor_map: editor_map,
|
||||||
persistence,
|
persistence,
|
||||||
};
|
};
|
||||||
Ok(manager)
|
Ok(manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[tracing::instrument(level = "trace", skip(self))]
|
// #[tracing::instrument(level = "trace", skip(self))]
|
||||||
pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult<Arc<ClientGridBlockMetaEditor>> {
|
pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult<Arc<GridBlockMetaEditor>> {
|
||||||
debug_assert!(!block_id.is_empty());
|
debug_assert!(!block_id.is_empty());
|
||||||
match self.editor_map.get(block_id) {
|
match self.block_editor_map.get(block_id) {
|
||||||
None => {
|
None => {
|
||||||
tracing::error!("The is a fatal error, block is not exist");
|
tracing::error!("The is a fatal error, block is not exist");
|
||||||
let editor = Arc::new(make_block_meta_editor(&self.user, block_id).await?);
|
let editor = Arc::new(make_block_meta_editor(&self.user, block_id).await?);
|
||||||
self.editor_map.insert(block_id.to_owned(), editor.clone());
|
self.block_editor_map.insert(block_id.to_owned(), editor.clone());
|
||||||
Ok(editor)
|
Ok(editor)
|
||||||
}
|
}
|
||||||
Some(editor) => Ok(editor.clone()),
|
Some(editor) => Ok(editor.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_editor_from_row_id(&self, row_id: &str) -> FlowyResult<Arc<ClientGridBlockMetaEditor>> {
|
async fn get_editor_from_row_id(&self, row_id: &str) -> FlowyResult<Arc<GridBlockMetaEditor>> {
|
||||||
let block_id = self.persistence.get_block_id(row_id)?;
|
let block_id = self.persistence.get_block_id(row_id)?;
|
||||||
Ok(self.get_editor(&block_id).await?)
|
Ok(self.get_editor(&block_id).await?)
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ impl GridBlockMetaEditorManager {
|
|||||||
row_meta: RowMeta,
|
row_meta: RowMeta,
|
||||||
start_row_id: Option<String>,
|
start_row_id: Option<String>,
|
||||||
) -> FlowyResult<i32> {
|
) -> FlowyResult<i32> {
|
||||||
let _ = self.persistence.insert_or_update(&row_meta.block_id, &row_meta.id)?;
|
let _ = self.persistence.insert(&row_meta.block_id, &row_meta.id)?;
|
||||||
let editor = self.get_editor(&row_meta.block_id).await?;
|
let editor = self.get_editor(&row_meta.block_id).await?;
|
||||||
|
|
||||||
let mut index_row_order = IndexRowOrder::from(&row_meta);
|
let mut index_row_order = IndexRowOrder::from(&row_meta);
|
||||||
@ -90,7 +90,7 @@ impl GridBlockMetaEditorManager {
|
|||||||
let editor = self.get_editor(&block_id).await?;
|
let editor = self.get_editor(&block_id).await?;
|
||||||
let mut row_count = 0;
|
let mut row_count = 0;
|
||||||
for row in row_metas {
|
for row in row_metas {
|
||||||
let _ = self.persistence.insert_or_update(&row.block_id, &row.id)?;
|
let _ = self.persistence.insert(&row.block_id, &row.id)?;
|
||||||
let mut row_order = IndexRowOrder::from(&row);
|
let mut row_order = IndexRowOrder::from(&row);
|
||||||
let (count, index) = editor.create_row(row, None).await?;
|
let (count, index) = editor.create_row(row, None).await?;
|
||||||
row_count = count;
|
row_count = count;
|
||||||
@ -256,7 +256,7 @@ impl GridBlockMetaEditorManager {
|
|||||||
async fn make_block_meta_editor_map(
|
async fn make_block_meta_editor_map(
|
||||||
user: &Arc<dyn GridUser>,
|
user: &Arc<dyn GridUser>,
|
||||||
blocks: Vec<GridBlockMeta>,
|
blocks: Vec<GridBlockMeta>,
|
||||||
) -> FlowyResult<DashMap<String, Arc<ClientGridBlockMetaEditor>>> {
|
) -> FlowyResult<DashMap<String, Arc<GridBlockMetaEditor>>> {
|
||||||
let editor_map = DashMap::new();
|
let editor_map = DashMap::new();
|
||||||
for block in blocks {
|
for block in blocks {
|
||||||
let editor = make_block_meta_editor(user, &block.block_id).await?;
|
let editor = make_block_meta_editor(user, &block.block_id).await?;
|
||||||
@ -266,7 +266,7 @@ async fn make_block_meta_editor_map(
|
|||||||
Ok(editor_map)
|
Ok(editor_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn make_block_meta_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<ClientGridBlockMetaEditor> {
|
async fn make_block_meta_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<GridBlockMetaEditor> {
|
||||||
let token = user.token()?;
|
let token = user.token()?;
|
||||||
let user_id = user.user_id()?;
|
let user_id = user.user_id()?;
|
||||||
let pool = user.db_pool()?;
|
let pool = user.db_pool()?;
|
||||||
@ -274,5 +274,5 @@ async fn make_block_meta_editor(user: &Arc<dyn GridUser>, block_id: &str) -> Flo
|
|||||||
let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool));
|
let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool));
|
||||||
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_id, disk_cache));
|
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_id, disk_cache));
|
||||||
let rev_manager = RevisionManager::new(&user_id, block_id, rev_persistence);
|
let rev_manager = RevisionManager::new(&user_id, block_id, rev_persistence);
|
||||||
ClientGridBlockMetaEditor::new(&user_id, &token, block_id, rev_manager).await
|
GridBlockMetaEditor::new(&user_id, &token, block_id, rev_manager).await
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(cell_data, field_type, field_meta)
|
.decode_cell_data(cell_data, field_type, field_meta)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.content,
|
.to_string(),
|
||||||
expected_str.to_owned()
|
expected_str.to_owned()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||||
use crate::entities::CellIdentifier;
|
use crate::entities::CellIdentifier;
|
||||||
use crate::manager::GridUser;
|
use crate::manager::GridUser;
|
||||||
use crate::services::block_meta_manager::GridBlockMetaEditorManager;
|
use crate::services::block_meta_manager::GridBlockManager;
|
||||||
use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder};
|
use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder};
|
||||||
use crate::services::persistence::block_index::BlockIndexPersistence;
|
use crate::services::persistence::block_index::BlockIndexCache;
|
||||||
use crate::services::row::*;
|
use crate::services::row::*;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||||
@ -19,20 +19,26 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
pub struct ClientGridEditor {
|
pub struct GridMetaEditor {
|
||||||
grid_id: String,
|
grid_id: String,
|
||||||
user: Arc<dyn GridUser>,
|
user: Arc<dyn GridUser>,
|
||||||
grid_pad: Arc<RwLock<GridMetaPad>>,
|
grid_pad: Arc<RwLock<GridMetaPad>>,
|
||||||
rev_manager: Arc<RevisionManager>,
|
rev_manager: Arc<RevisionManager>,
|
||||||
block_meta_manager: Arc<GridBlockMetaEditorManager>,
|
block_manager: Arc<GridBlockManager>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientGridEditor {
|
impl Drop for GridMetaEditor {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
tracing::trace!("Drop GridMetaEditor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GridMetaEditor {
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
grid_id: &str,
|
grid_id: &str,
|
||||||
user: Arc<dyn GridUser>,
|
user: Arc<dyn GridUser>,
|
||||||
mut rev_manager: RevisionManager,
|
mut rev_manager: RevisionManager,
|
||||||
persistence: Arc<BlockIndexPersistence>,
|
persistence: Arc<BlockIndexCache>,
|
||||||
) -> FlowyResult<Arc<Self>> {
|
) -> FlowyResult<Arc<Self>> {
|
||||||
let token = user.token()?;
|
let token = user.token()?;
|
||||||
let cloud = Arc::new(GridRevisionCloudService { token });
|
let cloud = Arc::new(GridRevisionCloudService { token });
|
||||||
@ -41,13 +47,13 @@ impl ClientGridEditor {
|
|||||||
let grid_pad = Arc::new(RwLock::new(grid_pad));
|
let grid_pad = Arc::new(RwLock::new(grid_pad));
|
||||||
let blocks = grid_pad.read().await.get_block_metas();
|
let blocks = grid_pad.read().await.get_block_metas();
|
||||||
|
|
||||||
let block_meta_manager = Arc::new(GridBlockMetaEditorManager::new(grid_id, &user, blocks, persistence).await?);
|
let block_meta_manager = Arc::new(GridBlockManager::new(grid_id, &user, blocks, persistence).await?);
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
grid_id: grid_id.to_owned(),
|
grid_id: grid_id.to_owned(),
|
||||||
user,
|
user,
|
||||||
grid_pad,
|
grid_pad,
|
||||||
rev_manager,
|
rev_manager,
|
||||||
block_meta_manager,
|
block_manager: block_meta_manager,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,10 +260,7 @@ impl ClientGridEditor {
|
|||||||
let row_order = RowOrder::from(&row_meta);
|
let row_order = RowOrder::from(&row_meta);
|
||||||
|
|
||||||
// insert the row
|
// insert the row
|
||||||
let row_count = self
|
let row_count = self.block_manager.create_row(&block_id, row_meta, start_row_id).await?;
|
||||||
.block_meta_manager
|
|
||||||
.create_row(&block_id, row_meta, start_row_id)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// update block row count
|
// update block row count
|
||||||
let changeset = GridBlockMetaChangeset::from_row_count(&block_id, row_count);
|
let changeset = GridBlockMetaChangeset::from_row_count(&block_id, row_count);
|
||||||
@ -277,7 +280,7 @@ impl ClientGridEditor {
|
|||||||
.or_insert_with(Vec::new)
|
.or_insert_with(Vec::new)
|
||||||
.push(row_meta);
|
.push(row_meta);
|
||||||
}
|
}
|
||||||
let changesets = self.block_meta_manager.insert_row(rows_by_block_id).await?;
|
let changesets = self.block_manager.insert_row(rows_by_block_id).await?;
|
||||||
for changeset in changesets {
|
for changeset in changesets {
|
||||||
let _ = self.update_block(changeset).await?;
|
let _ = self.update_block(changeset).await?;
|
||||||
}
|
}
|
||||||
@ -286,7 +289,7 @@ impl ClientGridEditor {
|
|||||||
|
|
||||||
pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
|
pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> {
|
||||||
let field_metas = self.get_field_metas::<FieldOrder>(None).await?;
|
let field_metas = self.get_field_metas::<FieldOrder>(None).await?;
|
||||||
self.block_meta_manager
|
self.block_manager
|
||||||
.update_row(changeset, |row_meta| make_row_from_row_meta(&field_metas, row_meta))
|
.update_row(changeset, |row_meta| make_row_from_row_meta(&field_metas, row_meta))
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@ -309,7 +312,7 @@ impl ClientGridEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_row(&self, row_id: &str) -> FlowyResult<Option<Row>> {
|
pub async fn get_row(&self, row_id: &str) -> FlowyResult<Option<Row>> {
|
||||||
match self.block_meta_manager.get_row_meta(row_id).await? {
|
match self.block_manager.get_row_meta(row_id).await? {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(row_meta) => {
|
Some(row_meta) => {
|
||||||
let field_metas = self.get_field_metas::<FieldOrder>(None).await?;
|
let field_metas = self.get_field_metas::<FieldOrder>(None).await?;
|
||||||
@ -321,7 +324,7 @@ impl ClientGridEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> {
|
pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> {
|
||||||
let _ = self.block_meta_manager.delete_row(row_id).await?;
|
let _ = self.block_manager.delete_row(row_id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,12 +334,12 @@ impl ClientGridEditor {
|
|||||||
|
|
||||||
pub async fn get_cell(&self, params: &CellIdentifier) -> Option<Cell> {
|
pub async fn get_cell(&self, params: &CellIdentifier) -> Option<Cell> {
|
||||||
let field_meta = self.get_field_meta(¶ms.field_id).await?;
|
let field_meta = self.get_field_meta(¶ms.field_id).await?;
|
||||||
let row_meta = self.block_meta_manager.get_row_meta(¶ms.row_id).await.ok()??;
|
let row_meta = self.block_manager.get_row_meta(¶ms.row_id).await.ok()??;
|
||||||
make_cell(¶ms.field_id, &field_meta, &row_meta)
|
make_cell(¶ms.field_id, &field_meta, &row_meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_cell_meta(&self, row_id: &str, field_id: &str) -> FlowyResult<Option<CellMeta>> {
|
pub async fn get_cell_meta(&self, row_id: &str, field_id: &str) -> FlowyResult<Option<CellMeta>> {
|
||||||
let row_meta = self.block_meta_manager.get_row_meta(row_id).await?;
|
let row_meta = self.block_manager.get_row_meta(row_id).await?;
|
||||||
match row_meta {
|
match row_meta {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(row_meta) => {
|
Some(row_meta) => {
|
||||||
@ -382,7 +385,7 @@ impl ClientGridEditor {
|
|||||||
cell_content_changeset,
|
cell_content_changeset,
|
||||||
};
|
};
|
||||||
let _ = self
|
let _ = self
|
||||||
.block_meta_manager
|
.block_manager
|
||||||
.update_cell(cell_changeset, |row_meta| {
|
.update_cell(cell_changeset, |row_meta| {
|
||||||
make_row_from_row_meta(&field_metas, row_meta)
|
make_row_from_row_meta(&field_metas, row_meta)
|
||||||
})
|
})
|
||||||
@ -403,7 +406,7 @@ impl ClientGridEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_rows(&self, row_orders: Vec<RowOrder>) -> FlowyResult<()> {
|
pub async fn delete_rows(&self, row_orders: Vec<RowOrder>) -> FlowyResult<()> {
|
||||||
let changesets = self.block_meta_manager.delete_rows(row_orders).await?;
|
let changesets = self.block_manager.delete_rows(row_orders).await?;
|
||||||
for changeset in changesets {
|
for changeset in changesets {
|
||||||
let _ = self.update_block(changeset).await?;
|
let _ = self.update_block(changeset).await?;
|
||||||
}
|
}
|
||||||
@ -415,7 +418,7 @@ impl ClientGridEditor {
|
|||||||
let field_orders = pad_read_guard.get_field_orders();
|
let field_orders = pad_read_guard.get_field_orders();
|
||||||
let mut block_orders = vec![];
|
let mut block_orders = vec![];
|
||||||
for block_order in pad_read_guard.get_block_metas() {
|
for block_order in pad_read_guard.get_block_metas() {
|
||||||
let row_orders = self.block_meta_manager.get_row_orders(&block_order.block_id).await?;
|
let row_orders = self.block_manager.get_row_orders(&block_order.block_id).await?;
|
||||||
let block_order = GridBlockOrder {
|
let block_order = GridBlockOrder {
|
||||||
block_id: block_order.block_id,
|
block_id: block_order.block_id,
|
||||||
row_orders,
|
row_orders,
|
||||||
@ -442,7 +445,7 @@ impl ClientGridEditor {
|
|||||||
.collect::<Vec<String>>(),
|
.collect::<Vec<String>>(),
|
||||||
Some(block_ids) => block_ids,
|
Some(block_ids) => block_ids,
|
||||||
};
|
};
|
||||||
let snapshots = self.block_meta_manager.make_block_snapshots(block_ids).await?;
|
let snapshots = self.block_manager.make_block_snapshots(block_ids).await?;
|
||||||
Ok(snapshots)
|
Ok(snapshots)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,10 +479,7 @@ impl ClientGridEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn move_row(&self, row_id: &str, from: i32, to: i32) -> FlowyResult<()> {
|
pub async fn move_row(&self, row_id: &str, from: i32, to: i32) -> FlowyResult<()> {
|
||||||
let _ = self
|
let _ = self.block_manager.move_row(row_id, from as usize, to as usize).await?;
|
||||||
.block_meta_manager
|
|
||||||
.move_row(row_id, from as usize, to as usize)
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,7 +565,7 @@ impl ClientGridEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "flowy_unit_test")]
|
#[cfg(feature = "flowy_unit_test")]
|
||||||
impl ClientGridEditor {
|
impl GridMetaEditor {
|
||||||
pub fn rev_manager(&self) -> Arc<RevisionManager> {
|
pub fn rev_manager(&self) -> Arc<RevisionManager> {
|
||||||
self.rev_manager.clone()
|
self.rev_manager.clone()
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,11 @@ use flowy_database::{
|
|||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub struct BlockIndexPersistence {
|
pub struct BlockIndexCache {
|
||||||
database: Arc<dyn GridDatabase>,
|
database: Arc<dyn GridDatabase>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockIndexPersistence {
|
impl BlockIndexCache {
|
||||||
pub fn new(database: Arc<dyn GridDatabase>) -> Self {
|
pub fn new(database: Arc<dyn GridDatabase>) -> Self {
|
||||||
Self { database }
|
Self { database }
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ impl BlockIndexPersistence {
|
|||||||
Ok(block_id)
|
Ok(block_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_or_update(&self, block_id: &str, row_id: &str) -> FlowyResult<()> {
|
pub fn insert(&self, block_id: &str, row_id: &str) -> FlowyResult<()> {
|
||||||
let conn = self.database.db_connection()?;
|
let conn = self.database.db_connection()?;
|
||||||
let item = IndexItem {
|
let item = IndexItem {
|
||||||
row_id: row_id.to_string(),
|
row_id: row_id.to_string(),
|
||||||
|
@ -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;
|
||||||
@ -146,8 +147,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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,6 +167,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
|
||||||
@ -187,13 +196,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())
|
||||||
@ -230,23 +233,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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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};
|
||||||
@ -295,8 +295,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 }];
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use flowy_grid::services::field::*;
|
use flowy_grid::services::field::*;
|
||||||
use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder};
|
use flowy_grid::services::grid_editor::{GridMetaEditor, GridPadBuilder};
|
||||||
use flowy_grid::services::row::CreateRowMetaPayload;
|
use flowy_grid::services::row::CreateRowMetaPayload;
|
||||||
use flowy_grid_data_model::entities::{
|
use flowy_grid_data_model::entities::{
|
||||||
BuildGridContext, CellChangeset, Field, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta,
|
BuildGridContext, CellChangeset, Field, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta,
|
||||||
@ -72,7 +72,7 @@ pub enum EditorScript {
|
|||||||
pub struct GridEditorTest {
|
pub struct GridEditorTest {
|
||||||
pub sdk: FlowySDKTest,
|
pub sdk: FlowySDKTest,
|
||||||
pub grid_id: String,
|
pub grid_id: String,
|
||||||
pub editor: Arc<ClientGridEditor>,
|
pub editor: Arc<GridMetaEditor>,
|
||||||
pub field_metas: Vec<FieldMeta>,
|
pub field_metas: Vec<FieldMeta>,
|
||||||
pub grid_blocks: Vec<GridBlockMeta>,
|
pub grid_blocks: Vec<GridBlockMeta>,
|
||||||
pub row_metas: Vec<Arc<RowMeta>>,
|
pub row_metas: Vec<Arc<RowMeta>>,
|
||||||
@ -239,7 +239,7 @@ impl GridEditorTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_row_metas(editor: &Arc<ClientGridEditor>) -> Vec<Arc<RowMeta>> {
|
async fn get_row_metas(editor: &Arc<GridMetaEditor>) -> Vec<Arc<RowMeta>> {
|
||||||
editor
|
editor
|
||||||
.grid_block_snapshots(None)
|
.grid_block_snapshots(None)
|
||||||
.await
|
.await
|
||||||
|
@ -21,7 +21,7 @@ use lib_ws::WSConnectState;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
|
|
||||||
pub struct ClientTextBlockEditor {
|
pub struct TextBlockEditor {
|
||||||
pub doc_id: String,
|
pub doc_id: String,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
rev_manager: Arc<RevisionManager>,
|
rev_manager: Arc<RevisionManager>,
|
||||||
@ -30,7 +30,7 @@ pub struct ClientTextBlockEditor {
|
|||||||
edit_cmd_tx: EditorCommandSender,
|
edit_cmd_tx: EditorCommandSender,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientTextBlockEditor {
|
impl TextBlockEditor {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub(crate) async fn new(
|
pub(crate) async fn new(
|
||||||
doc_id: &str,
|
doc_id: &str,
|
||||||
@ -185,7 +185,7 @@ impl ClientTextBlockEditor {
|
|||||||
pub(crate) fn receive_ws_state(&self, _state: &WSConnectState) {}
|
pub(crate) fn receive_ws_state(&self, _state: &WSConnectState) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Drop for ClientTextBlockEditor {
|
impl std::ops::Drop for TextBlockEditor {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
tracing::trace!("{} ClientBlockEditor was dropped", self.doc_id)
|
tracing::trace!("{} ClientBlockEditor was dropped", self.doc_id)
|
||||||
}
|
}
|
||||||
@ -204,7 +204,7 @@ fn spawn_edit_queue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "flowy_unit_test")]
|
#[cfg(feature = "flowy_unit_test")]
|
||||||
impl ClientTextBlockEditor {
|
impl TextBlockEditor {
|
||||||
pub async fn text_block_delta(&self) -> FlowyResult<RichTextDelta> {
|
pub async fn text_block_delta(&self) -> FlowyResult<RichTextDelta> {
|
||||||
let (ret, rx) = oneshot::channel::<CollaborateResult<RichTextDelta>>();
|
let (ret, rx) = oneshot::channel::<CollaborateResult<RichTextDelta>>();
|
||||||
let msg = EditorCommand::ReadDelta { ret };
|
let msg = EditorCommand::ReadDelta { ret };
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{editor::ClientTextBlockEditor, errors::FlowyError, BlockCloudService};
|
use crate::{editor::TextBlockEditor, errors::FlowyError, BlockCloudService};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use flowy_database::ConnectionPool;
|
use flowy_database::ConnectionPool;
|
||||||
@ -47,8 +47,8 @@ impl TextBlockManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self, block_id), fields(block_id), err)]
|
#[tracing::instrument(level = "trace", skip(self, block_id), fields(block_id), err)]
|
||||||
pub async fn open_block<T: AsRef<str>>(&self, block_id: T) -> Result<Arc<ClientTextBlockEditor>, FlowyError> {
|
pub async fn open_block<T: AsRef<str>>(&self, block_id: T) -> Result<Arc<TextBlockEditor>, FlowyError> {
|
||||||
let block_id = block_id.as_ref();
|
let block_id = block_id.as_ref();
|
||||||
tracing::Span::current().record("block_id", &block_id);
|
tracing::Span::current().record("block_id", &block_id);
|
||||||
self.get_block_editor(block_id).await
|
self.get_block_editor(block_id).await
|
||||||
@ -108,7 +108,7 @@ impl TextBlockManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TextBlockManager {
|
impl TextBlockManager {
|
||||||
async fn get_block_editor(&self, block_id: &str) -> FlowyResult<Arc<ClientTextBlockEditor>> {
|
async fn get_block_editor(&self, block_id: &str) -> FlowyResult<Arc<TextBlockEditor>> {
|
||||||
match self.editor_map.get(block_id) {
|
match self.editor_map.get(block_id) {
|
||||||
None => {
|
None => {
|
||||||
let db_pool = self.user.db_pool()?;
|
let db_pool = self.user.db_pool()?;
|
||||||
@ -123,7 +123,7 @@ impl TextBlockManager {
|
|||||||
&self,
|
&self,
|
||||||
block_id: &str,
|
block_id: &str,
|
||||||
pool: Arc<ConnectionPool>,
|
pool: Arc<ConnectionPool>,
|
||||||
) -> Result<Arc<ClientTextBlockEditor>, FlowyError> {
|
) -> Result<Arc<TextBlockEditor>, FlowyError> {
|
||||||
let user = self.user.clone();
|
let user = self.user.clone();
|
||||||
let token = self.user.token()?;
|
let token = self.user.token()?;
|
||||||
let rev_manager = self.make_rev_manager(block_id, pool.clone())?;
|
let rev_manager = self.make_rev_manager(block_id, pool.clone())?;
|
||||||
@ -132,7 +132,7 @@ impl TextBlockManager {
|
|||||||
server: self.cloud_service.clone(),
|
server: self.cloud_service.clone(),
|
||||||
});
|
});
|
||||||
let doc_editor =
|
let doc_editor =
|
||||||
ClientTextBlockEditor::new(block_id, user, rev_manager, self.rev_web_socket.clone(), cloud_service).await?;
|
TextBlockEditor::new(block_id, user, rev_manager, self.rev_web_socket.clone(), cloud_service).await?;
|
||||||
self.editor_map.insert(block_id, &doc_editor);
|
self.editor_map.insert(block_id, &doc_editor);
|
||||||
Ok(doc_editor)
|
Ok(doc_editor)
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ impl RevisionCloudService for TextBlockRevisionCloudService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextBlockEditorMap {
|
pub struct TextBlockEditorMap {
|
||||||
inner: DashMap<String, Arc<ClientTextBlockEditor>>,
|
inner: DashMap<String, Arc<TextBlockEditor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextBlockEditorMap {
|
impl TextBlockEditorMap {
|
||||||
@ -188,14 +188,14 @@ impl TextBlockEditorMap {
|
|||||||
Self { inner: DashMap::new() }
|
Self { inner: DashMap::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn insert(&self, block_id: &str, doc: &Arc<ClientTextBlockEditor>) {
|
pub(crate) fn insert(&self, block_id: &str, doc: &Arc<TextBlockEditor>) {
|
||||||
if self.inner.contains_key(block_id) {
|
if self.inner.contains_key(block_id) {
|
||||||
log::warn!("Doc:{} already exists in cache", block_id);
|
log::warn!("Doc:{} already exists in cache", block_id);
|
||||||
}
|
}
|
||||||
self.inner.insert(block_id.to_string(), doc.clone());
|
self.inner.insert(block_id.to_string(), doc.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get(&self, block_id: &str) -> Option<Arc<ClientTextBlockEditor>> {
|
pub(crate) fn get(&self, block_id: &str) -> Option<Arc<TextBlockEditor>> {
|
||||||
Some(self.inner.get(block_id)?.clone())
|
Some(self.inner.get(block_id)?.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use flowy_revision::disk::RevisionState;
|
use flowy_revision::disk::RevisionState;
|
||||||
use flowy_test::{helper::ViewTest, FlowySDKTest};
|
use flowy_test::{helper::ViewTest, FlowySDKTest};
|
||||||
use flowy_text_block::editor::ClientTextBlockEditor;
|
use flowy_text_block::editor::TextBlockEditor;
|
||||||
use flowy_text_block::TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS;
|
use flowy_text_block::TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS;
|
||||||
use lib_ot::{core::Interval, rich_text::RichTextDelta};
|
use lib_ot::{core::Interval, rich_text::RichTextDelta};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -19,7 +19,7 @@ pub enum EditorScript {
|
|||||||
|
|
||||||
pub struct TextBlockEditorTest {
|
pub struct TextBlockEditorTest {
|
||||||
pub sdk: FlowySDKTest,
|
pub sdk: FlowySDKTest,
|
||||||
pub editor: Arc<ClientTextBlockEditor>,
|
pub editor: Arc<TextBlockEditor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextBlockEditorTest {
|
impl TextBlockEditorTest {
|
||||||
|
@ -1,30 +1,18 @@
|
|||||||
|
|
||||||
[tasks.test_local]
|
[tasks.rust_unit_test]
|
||||||
category = "Build"
|
run_task = { name = ["rust_lib_unit_test", "shared_lib_unit_test"] }
|
||||||
dependencies = ["rm_cache"]
|
|
||||||
description = "Build desktop targets."
|
[tasks.rust_lib_unit_test]
|
||||||
|
description = "Run rust-lib unit tests"
|
||||||
script = '''
|
script = '''
|
||||||
cd rust-lib
|
cd rust-lib
|
||||||
cargo test
|
RUST_LOG=info cargo test --no-default-features --features="sync"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
[tasks.shared_lib_unit_test]
|
||||||
|
description = "Run shared-lib unit test"
|
||||||
|
script = '''
|
||||||
|
cd ../shared-lib
|
||||||
|
RUST_LOG=info cargo test --no-default-features
|
||||||
|
'''
|
||||||
|
|
||||||
[tasks.test_remote]
|
|
||||||
dependencies = ["rm_cache"]
|
|
||||||
script = """
|
|
||||||
cd rust-lib
|
|
||||||
cargo test --features "flowy-folder/http_server","flowy-user/http_server"
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
[tasks.run_server]
|
|
||||||
script = """
|
|
||||||
cd backend
|
|
||||||
cargo run
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
[tasks.rm_cache]
|
|
||||||
script = """
|
|
||||||
rm -rf rust-lib/flowy-test/temp
|
|
||||||
"""
|
|
27
frontend/scripts/makefile/tool.toml
Normal file
27
frontend/scripts/makefile/tool.toml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
[tasks.rust_clean]
|
||||||
|
script = [
|
||||||
|
"""
|
||||||
|
cd rust-lib
|
||||||
|
cargo clean
|
||||||
|
|
||||||
|
cd ../../shared-lib
|
||||||
|
cargo clean
|
||||||
|
|
||||||
|
rm -rf lib-infra/.cache
|
||||||
|
""",
|
||||||
|
]
|
||||||
|
script_runner = "@shell"
|
||||||
|
|
||||||
|
[tasks.rust_clean.windows]
|
||||||
|
script = [
|
||||||
|
"""
|
||||||
|
cd rust-lib
|
||||||
|
cargo clean
|
||||||
|
|
||||||
|
cd ../../shared-lib
|
||||||
|
cargo clean
|
||||||
|
|
||||||
|
rmdir /s/q "lib-infra/.cache"
|
||||||
|
""",
|
||||||
|
]
|
||||||
|
script_runner = "@duckscript"
|
@ -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> {
|
||||||
|
@ -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(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
@ -8343,50 +8301,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*m\n\tFieldType\x12\x0c\n\x08RichText\
|
||||||
\x07MoveRow\x10\x01*m\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\x05\x12\x07\n\x03URL\x10\x06b\x06proto3\
|
||||||
\x05\x12\x07\n\x03URL\x10\x06b\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;
|
||||||
|
@ -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;
|
||||||
|
@ -175,7 +175,7 @@ impl GridBlockMetaPad {
|
|||||||
match cal_diff::<PlainTextAttributes>(old, new) {
|
match cal_diff::<PlainTextAttributes>(old, new) {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(delta) => {
|
Some(delta) => {
|
||||||
tracing::debug!("[GridBlockMeta] Composing delta {}", delta.to_delta_str());
|
tracing::trace!("[GridBlockMeta] Composing delta {}", delta.to_delta_str());
|
||||||
// tracing::debug!(
|
// tracing::debug!(
|
||||||
// "[GridBlockMeta] current delta: {}",
|
// "[GridBlockMeta] current delta: {}",
|
||||||
// self.delta.to_str().unwrap_or_else(|_| "".to_string())
|
// self.delta.to_str().unwrap_or_else(|_| "".to_string())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user