mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: support edit imported database (#6061)
* chore: change field type of imported csv * fix: support load 10000 rows * fix: clippy
This commit is contained in:
parent
d3b7c5fea5
commit
a487aa74fd
@ -44,7 +44,8 @@ class RowCache {
|
|||||||
for (final fieldInfo in fieldInfos) {
|
for (final fieldInfo in fieldInfos) {
|
||||||
_cellMemCache.removeCellWithFieldId(fieldInfo.id);
|
_cellMemCache.removeCellWithFieldId(fieldInfo.id);
|
||||||
}
|
}
|
||||||
_changedNotifier.receive(const ChangedReason.fieldDidChange());
|
|
||||||
|
_changedNotifier?.receive(const ChangedReason.fieldDidChange());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ class RowCache {
|
|||||||
final CellMemCache _cellMemCache;
|
final CellMemCache _cellMemCache;
|
||||||
final RowLifeCycle _rowLifeCycle;
|
final RowLifeCycle _rowLifeCycle;
|
||||||
final RowFieldsDelegate _fieldDelegate;
|
final RowFieldsDelegate _fieldDelegate;
|
||||||
final RowChangesetNotifier _changedNotifier;
|
RowChangesetNotifier? _changedNotifier;
|
||||||
|
|
||||||
/// Returns a unmodifiable list of RowInfo
|
/// Returns a unmodifiable list of RowInfo
|
||||||
UnmodifiableListView<RowInfo> get rowInfos {
|
UnmodifiableListView<RowInfo> get rowInfos {
|
||||||
@ -67,7 +68,8 @@ class RowCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CellMemCache get cellCache => _cellMemCache;
|
CellMemCache get cellCache => _cellMemCache;
|
||||||
ChangedReason get changeReason => _changedNotifier.reason;
|
ChangedReason get changeReason =>
|
||||||
|
_changedNotifier?.reason ?? const InitialListState();
|
||||||
|
|
||||||
RowInfo? getRow(RowId rowId) {
|
RowInfo? getRow(RowId rowId) {
|
||||||
return _rowList.get(rowId);
|
return _rowList.get(rowId);
|
||||||
@ -78,18 +80,19 @@ class RowCache {
|
|||||||
final rowInfo = buildGridRow(row);
|
final rowInfo = buildGridRow(row);
|
||||||
_rowList.add(rowInfo);
|
_rowList.add(rowInfo);
|
||||||
}
|
}
|
||||||
_changedNotifier.receive(const ChangedReason.setInitialRows());
|
_changedNotifier?.receive(const ChangedReason.setInitialRows());
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRowMeta(RowMetaPB rowMeta) {
|
void setRowMeta(RowMetaPB rowMeta) {
|
||||||
final rowInfo = buildGridRow(rowMeta);
|
final rowInfo = buildGridRow(rowMeta);
|
||||||
_rowList.add(rowInfo);
|
_rowList.add(rowInfo);
|
||||||
_changedNotifier.receive(const ChangedReason.didFetchRow());
|
_changedNotifier?.receive(const ChangedReason.didFetchRow());
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_rowLifeCycle.onRowDisposed();
|
_rowLifeCycle.onRowDisposed();
|
||||||
_changedNotifier.dispose();
|
_changedNotifier?.dispose();
|
||||||
|
_changedNotifier = null;
|
||||||
_cellMemCache.dispose();
|
_cellMemCache.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +109,7 @@ class RowCache {
|
|||||||
|
|
||||||
void reorderAllRows(List<String> rowIds) {
|
void reorderAllRows(List<String> rowIds) {
|
||||||
_rowList.reorderWithRowIds(rowIds);
|
_rowList.reorderWithRowIds(rowIds);
|
||||||
_changedNotifier.receive(const ChangedReason.reorderRows());
|
_changedNotifier?.receive(const ChangedReason.reorderRows());
|
||||||
}
|
}
|
||||||
|
|
||||||
void reorderSingleRow(ReorderSingleRowPB reorderRow) {
|
void reorderSingleRow(ReorderSingleRowPB reorderRow) {
|
||||||
@ -117,7 +120,7 @@ class RowCache {
|
|||||||
reorderRow.oldIndex,
|
reorderRow.oldIndex,
|
||||||
reorderRow.newIndex,
|
reorderRow.newIndex,
|
||||||
);
|
);
|
||||||
_changedNotifier.receive(
|
_changedNotifier?.receive(
|
||||||
ChangedReason.reorderSingleRow(
|
ChangedReason.reorderSingleRow(
|
||||||
reorderRow,
|
reorderRow,
|
||||||
rowInfo,
|
rowInfo,
|
||||||
@ -130,7 +133,7 @@ class RowCache {
|
|||||||
for (final rowId in deletedRowIds) {
|
for (final rowId in deletedRowIds) {
|
||||||
final deletedRow = _rowList.remove(rowId);
|
final deletedRow = _rowList.remove(rowId);
|
||||||
if (deletedRow != null) {
|
if (deletedRow != null) {
|
||||||
_changedNotifier.receive(ChangedReason.delete(deletedRow));
|
_changedNotifier?.receive(ChangedReason.delete(deletedRow));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,7 +143,7 @@ class RowCache {
|
|||||||
final insertedIndex =
|
final insertedIndex =
|
||||||
_rowList.insert(insertedRow.index, buildGridRow(insertedRow.rowMeta));
|
_rowList.insert(insertedRow.index, buildGridRow(insertedRow.rowMeta));
|
||||||
if (insertedIndex != null) {
|
if (insertedIndex != null) {
|
||||||
_changedNotifier.receive(ChangedReason.insert(insertedIndex));
|
_changedNotifier?.receive(ChangedReason.insert(insertedIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,7 +168,7 @@ class RowCache {
|
|||||||
_rowList.updateRows(updatedList, (rowId) => buildGridRow(rowId));
|
_rowList.updateRows(updatedList, (rowId) => buildGridRow(rowId));
|
||||||
|
|
||||||
if (updatedIndexs.isNotEmpty) {
|
if (updatedIndexs.isNotEmpty) {
|
||||||
_changedNotifier.receive(ChangedReason.update(updatedIndexs));
|
_changedNotifier?.receive(ChangedReason.update(updatedIndexs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +176,7 @@ class RowCache {
|
|||||||
for (final rowId in invisibleRows) {
|
for (final rowId in invisibleRows) {
|
||||||
final deletedRow = _rowList.remove(rowId);
|
final deletedRow = _rowList.remove(rowId);
|
||||||
if (deletedRow != null) {
|
if (deletedRow != null) {
|
||||||
_changedNotifier.receive(ChangedReason.delete(deletedRow));
|
_changedNotifier?.receive(ChangedReason.delete(deletedRow));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,14 +186,16 @@ class RowCache {
|
|||||||
final insertedIndex =
|
final insertedIndex =
|
||||||
_rowList.insert(insertedRow.index, buildGridRow(insertedRow.rowMeta));
|
_rowList.insert(insertedRow.index, buildGridRow(insertedRow.rowMeta));
|
||||||
if (insertedIndex != null) {
|
if (insertedIndex != null) {
|
||||||
_changedNotifier.receive(ChangedReason.insert(insertedIndex));
|
_changedNotifier?.receive(ChangedReason.insert(insertedIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRowsChanged(void Function(ChangedReason) onRowChanged) {
|
void onRowsChanged(void Function(ChangedReason) onRowChanged) {
|
||||||
_changedNotifier.addListener(() {
|
_changedNotifier?.addListener(() {
|
||||||
onRowChanged(_changedNotifier.reason);
|
if (_changedNotifier != null) {
|
||||||
|
onRowChanged(_changedNotifier!.reason);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,17 +208,19 @@ class RowCache {
|
|||||||
final rowInfo = _rowList.get(rowId);
|
final rowInfo = _rowList.get(rowId);
|
||||||
if (rowInfo != null) {
|
if (rowInfo != null) {
|
||||||
final cellDataMap = _makeCells(rowInfo.rowMeta);
|
final cellDataMap = _makeCells(rowInfo.rowMeta);
|
||||||
onRowChanged(cellDataMap, _changedNotifier.reason);
|
if (_changedNotifier != null) {
|
||||||
|
onRowChanged(cellDataMap, _changedNotifier!.reason);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_changedNotifier.addListener(listenerHandler);
|
_changedNotifier?.addListener(listenerHandler);
|
||||||
return listenerHandler;
|
return listenerHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeRowListener(VoidCallback callback) {
|
void removeRowListener(VoidCallback callback) {
|
||||||
_changedNotifier.removeListener(callback);
|
_changedNotifier?.removeListener(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CellContext> loadCells(RowMetaPB rowMeta) {
|
List<CellContext> loadCells(RowMetaPB rowMeta) {
|
||||||
@ -242,7 +249,7 @@ class RowCache {
|
|||||||
rowId: rowMetaPB.id,
|
rowId: rowMetaPB.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
_changedNotifier.receive(ChangedReason.update(updatedIndexs));
|
_changedNotifier?.receive(ChangedReason.update(updatedIndexs));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(err) => Log.error(err),
|
(err) => Log.error(err),
|
||||||
|
@ -18,19 +18,7 @@ class RowController {
|
|||||||
}) : _rowMeta = rowMeta,
|
}) : _rowMeta = rowMeta,
|
||||||
_rowCache = rowCache,
|
_rowCache = rowCache,
|
||||||
_rowBackendSvc = RowBackendService(viewId: viewId),
|
_rowBackendSvc = RowBackendService(viewId: viewId),
|
||||||
_rowListener = RowListener(rowMeta.id) {
|
_rowListener = RowListener(rowMeta.id);
|
||||||
_rowBackendSvc.initRow(rowMeta.id);
|
|
||||||
_rowListener.start(
|
|
||||||
onMetaChanged: (newRowMeta) {
|
|
||||||
if (_isDisposed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_rowMeta = newRowMeta;
|
|
||||||
_rowCache.setRowMeta(newRowMeta);
|
|
||||||
_onRowMetaChanged?.call();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
RowMetaPB _rowMeta;
|
RowMetaPB _rowMeta;
|
||||||
final String? groupId;
|
final String? groupId;
|
||||||
@ -42,13 +30,26 @@ class RowController {
|
|||||||
final RowBackendService _rowBackendSvc;
|
final RowBackendService _rowBackendSvc;
|
||||||
bool _isDisposed = false;
|
bool _isDisposed = false;
|
||||||
|
|
||||||
CellMemCache get cellCache => _rowCache.cellCache;
|
|
||||||
|
|
||||||
String get rowId => rowMeta.id;
|
String get rowId => rowMeta.id;
|
||||||
RowMetaPB get rowMeta => _rowMeta;
|
RowMetaPB get rowMeta => _rowMeta;
|
||||||
|
CellMemCache get cellCache => _rowCache.cellCache;
|
||||||
|
|
||||||
List<CellContext> loadCells() => _rowCache.loadCells(rowMeta);
|
List<CellContext> loadCells() => _rowCache.loadCells(rowMeta);
|
||||||
|
|
||||||
|
Future<void> initialize() async {
|
||||||
|
await _rowBackendSvc.initRow(rowMeta.id);
|
||||||
|
_rowListener.start(
|
||||||
|
onMetaChanged: (newRowMeta) {
|
||||||
|
if (_isDisposed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_rowMeta = newRowMeta;
|
||||||
|
_rowCache.setRowMeta(newRowMeta);
|
||||||
|
_onRowMetaChanged?.call();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void addListener({
|
void addListener({
|
||||||
OnRowChanged? onRowChanged,
|
OnRowChanged? onRowChanged,
|
||||||
VoidCallback? onMetaChanged,
|
VoidCallback? onMetaChanged,
|
||||||
|
@ -2,9 +2,7 @@ import 'dart:async';
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:appflowy/plugins/database/application/row/row_service.dart';
|
import 'package:appflowy/plugins/database/application/row/row_service.dart';
|
||||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
|
||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy_backend/log.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
|
||||||
|
|
||||||
import '../defines.dart';
|
import '../defines.dart';
|
||||||
import '../field/field_controller.dart';
|
import '../field/field_controller.dart';
|
||||||
@ -93,17 +91,6 @@ class DatabaseViewCache {
|
|||||||
(reorderRow) => _rowCache.reorderSingleRow(reorderRow),
|
(reorderRow) => _rowCache.reorderSingleRow(reorderRow),
|
||||||
(err) => Log.error(err),
|
(err) => Log.error(err),
|
||||||
),
|
),
|
||||||
onReloadRows: () {
|
|
||||||
final payload = DatabaseViewIdPB(value: viewId);
|
|
||||||
DatabaseEventGetAllRows(payload).send().then((result) {
|
|
||||||
result.fold(
|
|
||||||
(rows) {
|
|
||||||
_rowCache.setInitialRows(rows.items);
|
|
||||||
},
|
|
||||||
(err) => Log.error(err),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_rowCache.onRowsChanged(
|
_rowCache.onRowsChanged(
|
||||||
|
@ -32,7 +32,6 @@ class DatabaseViewListener {
|
|||||||
required ReorderAllRowsCallback onReorderAllRows,
|
required ReorderAllRowsCallback onReorderAllRows,
|
||||||
required SingleRowCallback onReorderSingleRow,
|
required SingleRowCallback onReorderSingleRow,
|
||||||
required RowsVisibilityCallback onRowsVisibilityChanged,
|
required RowsVisibilityCallback onRowsVisibilityChanged,
|
||||||
required void Function() onReloadRows,
|
|
||||||
}) {
|
}) {
|
||||||
// Stop any existing listener
|
// Stop any existing listener
|
||||||
_listener?.stop();
|
_listener?.stop();
|
||||||
@ -47,7 +46,6 @@ class DatabaseViewListener {
|
|||||||
onReorderAllRows,
|
onReorderAllRows,
|
||||||
onReorderSingleRow,
|
onReorderSingleRow,
|
||||||
onRowsVisibilityChanged,
|
onRowsVisibilityChanged,
|
||||||
onReloadRows,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -59,7 +57,6 @@ class DatabaseViewListener {
|
|||||||
ReorderAllRowsCallback onReorderAllRows,
|
ReorderAllRowsCallback onReorderAllRows,
|
||||||
SingleRowCallback onReorderSingleRow,
|
SingleRowCallback onReorderSingleRow,
|
||||||
RowsVisibilityCallback onRowsVisibilityChanged,
|
RowsVisibilityCallback onRowsVisibilityChanged,
|
||||||
void Function() onReloadRows,
|
|
||||||
) {
|
) {
|
||||||
switch (ty) {
|
switch (ty) {
|
||||||
case DatabaseNotification.DidUpdateViewRowsVisibility:
|
case DatabaseNotification.DidUpdateViewRowsVisibility:
|
||||||
@ -94,9 +91,6 @@ class DatabaseViewListener {
|
|||||||
(error) => onReorderSingleRow(FlowyResult.failure(error)),
|
(error) => onReorderSingleRow(FlowyResult.failure(error)),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case DatabaseNotification.ReloadRows:
|
|
||||||
onReloadRows();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
|||||||
_dispatch();
|
_dispatch();
|
||||||
_startListening();
|
_startListening();
|
||||||
_init();
|
_init();
|
||||||
|
rowController.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
final FieldController fieldController;
|
final FieldController fieldController;
|
||||||
|
@ -342,7 +342,7 @@ class _GridRowsState extends State<_GridRows> {
|
|||||||
child: ReorderableListView.builder(
|
child: ReorderableListView.builder(
|
||||||
/// This is a workaround related to
|
/// This is a workaround related to
|
||||||
/// https://github.com/flutter/flutter/issues/25652
|
/// https://github.com/flutter/flutter/issues/25652
|
||||||
cacheExtent: 5000,
|
cacheExtent: 600,
|
||||||
scrollController: widget.scrollController.verticalController,
|
scrollController: widget.scrollController.verticalController,
|
||||||
physics: const ClampingScrollPhysics(),
|
physics: const ClampingScrollPhysics(),
|
||||||
buildDefaultDragHandles: false,
|
buildDefaultDragHandles: false,
|
||||||
@ -421,7 +421,7 @@ class _GridRowsState extends State<_GridRows> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final child = GridRow(
|
final child = GridRow(
|
||||||
key: ValueKey(rowMeta.id),
|
key: ValueKey(rowId),
|
||||||
fieldController: databaseController.fieldController,
|
fieldController: databaseController.fieldController,
|
||||||
rowId: rowId,
|
rowId: rowId,
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
|
@ -8,6 +8,7 @@ import 'package:appflowy/workspace/presentation/home/toast.dart';
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/size.dart';
|
import 'package:flowy_infra/size.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@ -202,9 +203,15 @@ class _URLAccessoryIconContainer extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
borderRadius: Corners.s6Border,
|
borderRadius: Corners.s6Border,
|
||||||
),
|
),
|
||||||
|
child: FlowyHover(
|
||||||
|
style: HoverStyle(
|
||||||
|
backgroundColor: AFThemeExtension.of(context).background,
|
||||||
|
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||||
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
14
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -964,7 +964,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab"
|
name = "collab"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -989,7 +989,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-database"
|
name = "collab-database"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -1018,7 +1018,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-document"
|
name = "collab-document"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -1038,7 +1038,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-entity"
|
name = "collab-entity"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1057,7 +1057,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-folder"
|
name = "collab-folder"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -1100,7 +1100,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-plugins"
|
name = "collab-plugins"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -1180,7 +1180,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-user"
|
name = "collab-user"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
|
@ -116,13 +116,13 @@ custom-protocol = ["tauri/custom-protocol"]
|
|||||||
# To switch to the local path, run:
|
# To switch to the local path, run:
|
||||||
# scripts/tool/update_collab_source.sh
|
# scripts/tool/update_collab_source.sh
|
||||||
# ⚠️⚠️⚠️️
|
# ⚠️⚠️⚠️️
|
||||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
|
|
||||||
# Working directory: frontend
|
# Working directory: frontend
|
||||||
# To update the commit ID, run:
|
# To update the commit ID, run:
|
||||||
|
14
frontend/appflowy_web_app/src-tauri/Cargo.lock
generated
14
frontend/appflowy_web_app/src-tauri/Cargo.lock
generated
@ -947,7 +947,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab"
|
name = "collab"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -972,7 +972,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-database"
|
name = "collab-database"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -1001,7 +1001,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-document"
|
name = "collab-document"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -1021,7 +1021,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-entity"
|
name = "collab-entity"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1040,7 +1040,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-folder"
|
name = "collab-folder"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -1083,7 +1083,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-plugins"
|
name = "collab-plugins"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -1163,7 +1163,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-user"
|
name = "collab-user"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
|
@ -116,13 +116,13 @@ custom-protocol = ["tauri/custom-protocol"]
|
|||||||
# To switch to the local path, run:
|
# To switch to the local path, run:
|
||||||
# scripts/tool/update_collab_source.sh
|
# scripts/tool/update_collab_source.sh
|
||||||
# ⚠️⚠️⚠️️
|
# ⚠️⚠️⚠️️
|
||||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
|
|
||||||
# Working directory: frontend
|
# Working directory: frontend
|
||||||
# To update the commit ID, run:
|
# To update the commit ID, run:
|
||||||
|
14
frontend/rust-lib/Cargo.lock
generated
14
frontend/rust-lib/Cargo.lock
generated
@ -825,7 +825,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab"
|
name = "collab"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -850,7 +850,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-database"
|
name = "collab-database"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -879,7 +879,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-document"
|
name = "collab-document"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -899,7 +899,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-entity"
|
name = "collab-entity"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -918,7 +918,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-folder"
|
name = "collab-folder"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@ -961,7 +961,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-plugins"
|
name = "collab-plugins"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -1041,7 +1041,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collab-user"
|
name = "collab-user"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=c714b6bd458420663c7a5b29370d6892902e995c#c714b6bd458420663c7a5b29370d6892902e995c"
|
source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=e51cde161cbce9af08f707ab1b3a3564eee90bac#e51cde161cbce9af08f707ab1b3a3564eee90bac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collab",
|
"collab",
|
||||||
|
@ -136,13 +136,13 @@ rocksdb = { git = "https://github.com/rust-rocksdb/rust-rocksdb", rev = "1710120
|
|||||||
# To switch to the local path, run:
|
# To switch to the local path, run:
|
||||||
# scripts/tool/update_collab_source.sh
|
# scripts/tool/update_collab_source.sh
|
||||||
# ⚠️⚠️⚠️️
|
# ⚠️⚠️⚠️️
|
||||||
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-entity = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-folder = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-document = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-database = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-plugins = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||||
|
|
||||||
# Working directory: frontend
|
# Working directory: frontend
|
||||||
# To update the commit ID, run:
|
# To update the commit ID, run:
|
||||||
|
@ -3,14 +3,13 @@ use std::convert::TryFrom;
|
|||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use collab_database::database::timestamp;
|
use collab_database::database::timestamp;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::Field;
|
use collab_database::fields::Field;
|
||||||
use collab_database::rows::{Row, RowId};
|
use collab_database::rows::{Row, RowId};
|
||||||
use flowy_database2::entities::*;
|
use flowy_database2::entities::*;
|
||||||
use flowy_database2::event_map::DatabaseEvent;
|
use flowy_database2::event_map::DatabaseEvent;
|
||||||
use flowy_database2::services::cell::CellBuilder;
|
use flowy_database2::services::cell::CellBuilder;
|
||||||
use flowy_database2::services::field::{
|
use flowy_database2::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
|
||||||
MultiSelectTypeOption, SelectOption, SingleSelectTypeOption,
|
|
||||||
};
|
|
||||||
use flowy_database2::services::share::csv::CSVFormat;
|
use flowy_database2::services::share::csv::CSVFormat;
|
||||||
use flowy_folder::entities::*;
|
use flowy_folder::entities::*;
|
||||||
use flowy_folder::event_map::FolderEvent;
|
use flowy_folder::event_map::FolderEvent;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use collab_database::database::{gen_database_id, gen_database_view_id, gen_row_id, DatabaseData};
|
use collab_database::database::{gen_database_id, gen_database_view_id, gen_row_id, DatabaseData};
|
||||||
use collab_database::entity::DatabaseView;
|
use collab_database::entity::{DatabaseView, SelectOption, SelectOptionColor};
|
||||||
use collab_database::views::DatabaseLayout;
|
use collab_database::views::DatabaseLayout;
|
||||||
use event_integration_test::database_event::TestRowBuilder;
|
use event_integration_test::database_event::TestRowBuilder;
|
||||||
|
|
||||||
@ -9,8 +9,7 @@ use flowy_database2::entities::FieldType;
|
|||||||
use flowy_database2::services::field::summary_type_option::summary::SummarizationTypeOption;
|
use flowy_database2::services::field::summary_type_option::summary::SummarizationTypeOption;
|
||||||
use flowy_database2::services::field::translate_type_option::translate::TranslateTypeOption;
|
use flowy_database2::services::field::translate_type_option::translate::TranslateTypeOption;
|
||||||
use flowy_database2::services::field::{
|
use flowy_database2::services::field::{
|
||||||
FieldBuilder, NumberFormat, NumberTypeOption, SelectOption, SelectOptionColor,
|
FieldBuilder, NumberFormat, NumberTypeOption, SingleSelectTypeOption,
|
||||||
SingleSelectTypeOption,
|
|
||||||
};
|
};
|
||||||
use flowy_database2::services::field_settings::default_field_settings_for_fields;
|
use flowy_database2::services::field_settings::default_field_settings_for_fields;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
@ -245,7 +245,7 @@ async fn get_row_event_test() {
|
|||||||
assert!(row.is_some());
|
assert!(row.is_some());
|
||||||
|
|
||||||
let row = test.get_row_meta(&grid_view.id, &database.rows[0].id).await;
|
let row = test.get_row_meta(&grid_view.id, &database.rows[0].id).await;
|
||||||
assert!(!row.document_id.is_empty());
|
assert!(row.document_id.is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -85,5 +85,6 @@ openssl_vendored = ["flowy-sqlite/openssl_vendored"]
|
|||||||
# Enable/Disable AppFlowy Verbose Log Configuration
|
# Enable/Disable AppFlowy Verbose Log Configuration
|
||||||
verbose_log = [
|
verbose_log = [
|
||||||
"flowy-document/verbose_log",
|
"flowy-document/verbose_log",
|
||||||
|
"flowy-database2/verbose_log",
|
||||||
"client-api/sync_verbose_log"
|
"client-api/sync_verbose_log"
|
||||||
]
|
]
|
||||||
|
@ -61,3 +61,4 @@ flowy-codegen.workspace = true
|
|||||||
[features]
|
[features]
|
||||||
dart = ["flowy-codegen/dart", "flowy-notification/dart"]
|
dart = ["flowy-codegen/dart", "flowy-notification/dart"]
|
||||||
ts = ["flowy-codegen/ts", "flowy-notification/tauri_ts"]
|
ts = ["flowy-codegen/ts", "flowy-notification/tauri_ts"]
|
||||||
|
verbose_log = ["collab-database/verbose_log"]
|
@ -55,8 +55,8 @@ pub struct RowMetaPB {
|
|||||||
#[pb(index = 1)]
|
#[pb(index = 1)]
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2, one_of)]
|
||||||
pub document_id: String,
|
pub document_id: Option<String>,
|
||||||
|
|
||||||
#[pb(index = 3, one_of)]
|
#[pb(index = 3, one_of)]
|
||||||
pub icon: Option<String>,
|
pub icon: Option<String>,
|
||||||
@ -64,8 +64,8 @@ pub struct RowMetaPB {
|
|||||||
#[pb(index = 4, one_of)]
|
#[pb(index = 4, one_of)]
|
||||||
pub cover: Option<String>,
|
pub cover: Option<String>,
|
||||||
|
|
||||||
#[pb(index = 5)]
|
#[pb(index = 5, one_of)]
|
||||||
pub is_document_empty: bool,
|
pub is_document_empty: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, ProtoBuf)]
|
#[derive(Debug, Default, ProtoBuf)]
|
||||||
@ -74,25 +74,26 @@ pub struct RepeatedRowMetaPB {
|
|||||||
pub items: Vec<RowMetaPB>,
|
pub items: Vec<RowMetaPB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<&RowDetail> for RowMetaPB {
|
impl From<RowOrder> for RowMetaPB {
|
||||||
fn from(row_detail: &RowDetail) -> Self {
|
fn from(data: RowOrder) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: row_detail.row.id.to_string(),
|
id: data.id.into_inner(),
|
||||||
document_id: row_detail.document_id.clone(),
|
document_id: None,
|
||||||
icon: row_detail.meta.icon_url.clone(),
|
icon: None,
|
||||||
cover: row_detail.meta.cover_url.clone(),
|
cover: None,
|
||||||
is_document_empty: row_detail.meta.is_document_empty,
|
is_document_empty: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<RowDetail> for RowMetaPB {
|
impl std::convert::From<RowDetail> for RowMetaPB {
|
||||||
fn from(row_detail: RowDetail) -> Self {
|
fn from(row_detail: RowDetail) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: row_detail.row.id.to_string(),
|
id: row_detail.row.id.to_string(),
|
||||||
document_id: row_detail.document_id,
|
document_id: Some(row_detail.document_id),
|
||||||
icon: row_detail.meta.icon_url,
|
icon: row_detail.meta.icon_url,
|
||||||
cover: row_detail.meta.cover_url,
|
cover: row_detail.meta.cover_url,
|
||||||
is_document_empty: row_detail.meta.is_document_empty,
|
is_document_empty: Some(row_detail.meta.is_document_empty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::rows::RowId;
|
use collab_database::rows::RowId;
|
||||||
|
|
||||||
use flowy_derive::ProtoBuf;
|
use flowy_derive::ProtoBuf;
|
||||||
@ -5,7 +6,6 @@ use flowy_error::{ErrorCode, FlowyError};
|
|||||||
|
|
||||||
use crate::entities::parser::NotEmptyStr;
|
use crate::entities::parser::NotEmptyStr;
|
||||||
use crate::entities::SelectOptionPB;
|
use crate::entities::SelectOptionPB;
|
||||||
use crate::services::field::SelectOption;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||||
pub struct ChecklistCellDataPB {
|
pub struct ChecklistCellDataPB {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use crate::entities::parser::NotEmptyStr;
|
use crate::entities::parser::NotEmptyStr;
|
||||||
use crate::entities::{CellIdPB, CellIdParams};
|
use crate::entities::{CellIdPB, CellIdParams};
|
||||||
use crate::services::field::checklist_type_option::ChecklistTypeOption;
|
use crate::services::field::checklist_type_option::ChecklistTypeOption;
|
||||||
use crate::services::field::{
|
use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
|
||||||
MultiSelectTypeOption, SelectOption, SelectOptionColor, SingleSelectTypeOption,
|
use collab_database::entity::{SelectOption, SelectOptionColor};
|
||||||
};
|
|
||||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||||
use flowy_error::ErrorCode;
|
use flowy_error::ErrorCode;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ pub(crate) async fn get_database_data_handler(
|
|||||||
.get_database_id_with_view_id(view_id.as_ref())
|
.get_database_id_with_view_id(view_id.as_ref())
|
||||||
.await?;
|
.await?;
|
||||||
let database_editor = manager.get_database_editor(&database_id).await?;
|
let database_editor = manager.get_database_editor(&database_id).await?;
|
||||||
let data = database_editor.get_database_data(view_id.as_ref()).await?;
|
let data = database_editor.open_database(view_id.as_ref()).await?;
|
||||||
trace!(
|
trace!(
|
||||||
"layout: {:?}, rows: {}, fields: {}",
|
"layout: {:?}, rows: {}, fields: {}",
|
||||||
data.layout_type,
|
data.layout_type,
|
||||||
@ -57,8 +57,14 @@ pub(crate) async fn get_all_rows_handler(
|
|||||||
.get_database_id_with_view_id(view_id.as_ref())
|
.get_database_id_with_view_id(view_id.as_ref())
|
||||||
.await?;
|
.await?;
|
||||||
let database_editor = manager.get_database_editor(&database_id).await?;
|
let database_editor = manager.get_database_editor(&database_id).await?;
|
||||||
let data = database_editor.get_all_rows(view_id.as_ref()).await?;
|
let row_details = database_editor
|
||||||
data_result_ok(data)
|
.get_all_row_details(view_id.as_ref())
|
||||||
|
.await?;
|
||||||
|
let rows = row_details
|
||||||
|
.into_iter()
|
||||||
|
.map(|detail| RowMetaPB::from(detail.as_ref().clone()))
|
||||||
|
.collect::<Vec<RowMetaPB>>();
|
||||||
|
data_result_ok(RepeatedRowMetaPB { items: rows })
|
||||||
}
|
}
|
||||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||||
pub(crate) async fn open_database_handler(
|
pub(crate) async fn open_database_handler(
|
||||||
@ -326,7 +332,7 @@ pub(crate) async fn switch_to_field_handler(
|
|||||||
.await?;
|
.await?;
|
||||||
let old_field = database_editor.get_field(¶ms.field_id).await;
|
let old_field = database_editor.get_field(¶ms.field_id).await;
|
||||||
database_editor
|
database_editor
|
||||||
.switch_to_field_type(¶ms.field_id, params.field_type)
|
.switch_to_field_type(¶ms.view_id, ¶ms.field_id, params.field_type)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(new_type_option) = database_editor
|
if let Some(new_type_option) = database_editor
|
||||||
|
@ -307,6 +307,7 @@ impl DatabaseManager {
|
|||||||
if should_remove {
|
if should_remove {
|
||||||
trace!("remove database editor:{}", database_id);
|
trace!("remove database editor:{}", database_id);
|
||||||
if let Some(editor) = editors.remove(&database_id) {
|
if let Some(editor) = editors.remove(&database_id) {
|
||||||
|
editor.close_database().await;
|
||||||
self
|
self
|
||||||
.removing_editor
|
.removing_editor
|
||||||
.lock()
|
.lock()
|
||||||
@ -793,8 +794,8 @@ impl DatabaseCollabService for WorkspaceDatabaseCollabServiceImpl {
|
|||||||
Ok(collab)
|
Ok(collab)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persistence(&self) -> Option<Box<dyn DatabaseCollabPersistenceService>> {
|
fn persistence(&self) -> Option<Arc<dyn DatabaseCollabPersistenceService>> {
|
||||||
Some(Box::new(DatabasePersistenceImpl {
|
Some(Arc::new(DatabasePersistenceImpl {
|
||||||
user: self.user.clone(),
|
user: self.user.clone(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,6 @@ pub enum DatabaseNotification {
|
|||||||
DidUpdateFieldSettings = 86,
|
DidUpdateFieldSettings = 86,
|
||||||
// Trigger when Calculation changed
|
// Trigger when Calculation changed
|
||||||
DidUpdateCalculation = 87,
|
DidUpdateCalculation = 87,
|
||||||
ReloadRows = 88,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<DatabaseNotification> for i32 {
|
impl std::convert::From<DatabaseNotification> for i32 {
|
||||||
|
@ -7,11 +7,11 @@ use crate::services::database::util::database_view_setting_pb_from_view;
|
|||||||
use crate::services::database_view::{
|
use crate::services::database_view::{
|
||||||
DatabaseViewChanged, DatabaseViewOperation, DatabaseViews, EditorByViewId,
|
DatabaseViewChanged, DatabaseViewOperation, DatabaseViews, EditorByViewId,
|
||||||
};
|
};
|
||||||
|
use crate::services::field::type_option_transform::transform_type_option;
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
default_type_option_data_from_type, select_type_option_from_field, transform_type_option,
|
default_type_option_data_from_type, select_type_option_from_field, type_option_data_from_pb,
|
||||||
type_option_data_from_pb, ChecklistCellChangeset, RelationTypeOption, SelectOptionCellChangeset,
|
ChecklistCellChangeset, RelationTypeOption, SelectOptionCellChangeset, StringCellData,
|
||||||
StringCellData, TimestampCellData, TimestampCellDataWrapper, TypeOptionCellDataHandler,
|
TimestampCellData, TimestampCellDataWrapper, TypeOptionCellDataHandler, TypeOptionCellExt,
|
||||||
TypeOptionCellExt,
|
|
||||||
};
|
};
|
||||||
use crate::services::field_settings::{default_field_settings_by_layout_map, FieldSettings};
|
use crate::services::field_settings::{default_field_settings_by_layout_map, FieldSettings};
|
||||||
use crate::services::filter::{Filter, FilterChangeset};
|
use crate::services::filter::{Filter, FilterChangeset};
|
||||||
@ -36,9 +36,9 @@ use lib_infra::util::timestamp;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{broadcast, RwLock};
|
use tokio::sync::{broadcast, RwLock};
|
||||||
use tracing::{debug, error, event, instrument, trace, warn};
|
use tokio_util::sync::CancellationToken;
|
||||||
|
use tracing::{debug, error, event, info, instrument, trace, warn};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct DatabaseEditor {
|
pub struct DatabaseEditor {
|
||||||
pub(crate) database: Arc<RwLock<Database>>,
|
pub(crate) database: Arc<RwLock<Database>>,
|
||||||
pub cell_cache: CellCache,
|
pub cell_cache: CellCache,
|
||||||
@ -48,6 +48,7 @@ pub struct DatabaseEditor {
|
|||||||
notification_sender: Arc<DebounceNotificationSender>,
|
notification_sender: Arc<DebounceNotificationSender>,
|
||||||
user: Arc<dyn DatabaseUser>,
|
user: Arc<dyn DatabaseUser>,
|
||||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||||
|
database_cancellation: Arc<RwLock<Option<CancellationToken>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DatabaseEditor {
|
impl DatabaseEditor {
|
||||||
@ -60,6 +61,7 @@ impl DatabaseEditor {
|
|||||||
let notification_sender = Arc::new(DebounceNotificationSender::new(200));
|
let notification_sender = Arc::new(DebounceNotificationSender::new(200));
|
||||||
let cell_cache = AnyTypeCache::<u64>::new();
|
let cell_cache = AnyTypeCache::<u64>::new();
|
||||||
let database_id = database.read().await.get_database_id();
|
let database_id = database.read().await.get_database_id();
|
||||||
|
let database_cancellation = Arc::new(RwLock::new(None));
|
||||||
// Receive database sync state and send to frontend via the notification
|
// Receive database sync state and send to frontend via the notification
|
||||||
observe_sync_state(&database_id, &database).await;
|
observe_sync_state(&database_id, &database).await;
|
||||||
// observe_view_change(&database_id, &database).await;
|
// observe_view_change(&database_id, &database).await;
|
||||||
@ -73,6 +75,7 @@ impl DatabaseEditor {
|
|||||||
task_scheduler: task_scheduler.clone(),
|
task_scheduler: task_scheduler.clone(),
|
||||||
cell_cache: cell_cache.clone(),
|
cell_cache: cell_cache.clone(),
|
||||||
editor_by_view_id: editor_by_view_id.clone(),
|
editor_by_view_id: editor_by_view_id.clone(),
|
||||||
|
database_cancellation: database_cancellation.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let database_views = Arc::new(
|
let database_views = Arc::new(
|
||||||
@ -104,6 +107,7 @@ impl DatabaseEditor {
|
|||||||
database_views,
|
database_views,
|
||||||
notification_sender,
|
notification_sender,
|
||||||
collab_builder,
|
collab_builder,
|
||||||
|
database_cancellation,
|
||||||
});
|
});
|
||||||
observe_block_event(&database_id, &this).await;
|
observe_block_event(&database_id, &this).await;
|
||||||
Ok(this)
|
Ok(this)
|
||||||
@ -419,6 +423,7 @@ impl DatabaseEditor {
|
|||||||
|
|
||||||
pub async fn switch_to_field_type(
|
pub async fn switch_to_field_type(
|
||||||
&self,
|
&self,
|
||||||
|
view_id: &str,
|
||||||
field_id: &str,
|
field_id: &str,
|
||||||
new_field_type: FieldType,
|
new_field_type: FieldType,
|
||||||
) -> FlowyResult<()> {
|
) -> FlowyResult<()> {
|
||||||
@ -441,11 +446,16 @@ impl DatabaseEditor {
|
|||||||
.unwrap_or_else(|| default_type_option_data_from_type(new_field_type));
|
.unwrap_or_else(|| default_type_option_data_from_type(new_field_type));
|
||||||
|
|
||||||
let transformed_type_option = transform_type_option(
|
let transformed_type_option = transform_type_option(
|
||||||
|
view_id,
|
||||||
|
field_id,
|
||||||
old_field_type,
|
old_field_type,
|
||||||
new_field_type,
|
new_field_type,
|
||||||
old_type_option_data,
|
old_type_option_data,
|
||||||
new_type_option_data,
|
new_type_option_data,
|
||||||
);
|
&database,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
database.update_field(field_id, |update| {
|
database.update_field(field_id, |update| {
|
||||||
update
|
update
|
||||||
.set_field_type(new_field_type.into())
|
.set_field_type(new_field_type.into())
|
||||||
@ -667,9 +677,9 @@ impl DatabaseEditor {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_row_details(&self, view_id: &str) -> FlowyResult<Vec<Arc<RowDetail>>> {
|
pub async fn get_all_row_details(&self, view_id: &str) -> FlowyResult<Vec<Arc<RowDetail>>> {
|
||||||
let view_editor = self.database_views.get_view_editor(view_id).await?;
|
let view_editor = self.database_views.get_view_editor(view_id).await?;
|
||||||
Ok(view_editor.v_get_row_details().await)
|
Ok(view_editor.v_get_all_row_details().await)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_row(&self, view_id: &str, row_id: &RowId) -> Option<Row> {
|
pub async fn get_row(&self, view_id: &str, row_id: &RowId) -> Option<Row> {
|
||||||
@ -731,10 +741,10 @@ impl DatabaseEditor {
|
|||||||
let row_document_id = database.get_row_document_id(row_id)?;
|
let row_document_id = database.get_row_document_id(row_id)?;
|
||||||
Some(RowMetaPB {
|
Some(RowMetaPB {
|
||||||
id: row_id.clone().into_inner(),
|
id: row_id.clone().into_inner(),
|
||||||
document_id: row_document_id,
|
document_id: Some(row_document_id),
|
||||||
icon: row_meta.icon_url,
|
icon: row_meta.icon_url,
|
||||||
cover: row_meta.cover_url,
|
cover: row_meta.cover_url,
|
||||||
is_document_empty: row_meta.is_document_empty,
|
is_document_empty: Some(row_meta.is_document_empty),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
warn!("the row:{} is exist in view:{}", row_id.as_str(), view_id);
|
warn!("the row:{} is exist in view:{}", row_id.as_str(), view_id);
|
||||||
@ -786,13 +796,8 @@ impl DatabaseEditor {
|
|||||||
|
|
||||||
// Notifies the client that the row meta has been updated.
|
// Notifies the client that the row meta has been updated.
|
||||||
send_notification(row_id.as_str(), DatabaseNotification::DidUpdateRowMeta)
|
send_notification(row_id.as_str(), DatabaseNotification::DidUpdateRowMeta)
|
||||||
.payload(RowMetaPB::from(&row_detail))
|
.payload(RowMetaPB::from(row_detail))
|
||||||
.send();
|
.send();
|
||||||
|
|
||||||
// Update the last modified time of the row
|
|
||||||
self
|
|
||||||
.update_last_modified_time(row_detail.clone(), &changeset.view_id)
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -885,24 +890,6 @@ impl DatabaseEditor {
|
|||||||
self.update_cell(view_id, row_id, field_id, new_cell).await
|
self.update_cell(view_id, row_id, field_id, new_cell).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_last_modified_time(&self, row_detail: RowDetail, view_id: &str) {
|
|
||||||
self
|
|
||||||
.database
|
|
||||||
.write()
|
|
||||||
.await
|
|
||||||
.update_row(row_detail.row.id.clone(), |row_update| {
|
|
||||||
row_update.set_last_modified(timestamp());
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let editor = self.database_views.get_view_editor(view_id).await;
|
|
||||||
if let Ok(editor) = editor {
|
|
||||||
editor
|
|
||||||
.v_did_update_row(&Some(row_detail.clone()), &row_detail, None)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update a cell in the database.
|
/// Update a cell in the database.
|
||||||
/// This will notify all views that the cell has been updated.
|
/// This will notify all views that the cell has been updated.
|
||||||
pub async fn update_cell(
|
pub async fn update_cell(
|
||||||
@ -919,7 +906,9 @@ impl DatabaseEditor {
|
|||||||
.write()
|
.write()
|
||||||
.await
|
.await
|
||||||
.update_row(row_id.clone(), |row_update| {
|
.update_row(row_id.clone(), |row_update| {
|
||||||
row_update.update_cells(|cell_update| {
|
row_update
|
||||||
|
.set_last_modified(timestamp())
|
||||||
|
.update_cells(|cell_update| {
|
||||||
cell_update.insert(field_id, new_cell);
|
cell_update.insert(field_id, new_cell);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -1170,7 +1159,7 @@ impl DatabaseEditor {
|
|||||||
let to_row = if to_row.is_some() {
|
let to_row = if to_row.is_some() {
|
||||||
to_row
|
to_row
|
||||||
} else {
|
} else {
|
||||||
let row_details = self.get_row_details(view_id).await?;
|
let row_details = self.get_all_row_details(view_id).await?;
|
||||||
row_details
|
row_details
|
||||||
.last()
|
.last()
|
||||||
.map(|row_detail| row_detail.row.id.clone())
|
.map(|row_detail| row_detail.row.id.clone())
|
||||||
@ -1189,7 +1178,9 @@ impl DatabaseEditor {
|
|||||||
.write()
|
.write()
|
||||||
.await
|
.await
|
||||||
.update_row(row_detail.row.id, |row| {
|
.update_row(row_detail.row.id, |row| {
|
||||||
row.set_cells(Cells::from(row_changeset.cell_by_field_id.clone()));
|
row
|
||||||
|
.set_last_modified(timestamp())
|
||||||
|
.set_cells(Cells::from(row_changeset.cell_by_field_id.clone()));
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
},
|
},
|
||||||
@ -1296,14 +1287,34 @@ impl DatabaseEditor {
|
|||||||
Ok(database_view_setting_pb_from_view(view))
|
Ok(database_view_setting_pb_from_view(view))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_database_data(&self, view_id: &str) -> FlowyResult<DatabasePB> {
|
pub async fn close_database(&self) {
|
||||||
let database_view = self.database_views.get_view_editor(view_id).await?;
|
let cancellation = self.database_cancellation.read().await;
|
||||||
let view = database_view
|
if let Some(cancellation) = &*cancellation {
|
||||||
.v_get_view()
|
info!("Cancel database operation");
|
||||||
.await
|
cancellation.cancel();
|
||||||
.ok_or_else(FlowyError::record_not_found)?;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn open_database(&self, view_id: &str) -> FlowyResult<DatabasePB> {
|
||||||
|
let view_layout = self.database.read().await.get_database_view_layout(view_id);
|
||||||
|
let new_token = CancellationToken::new();
|
||||||
|
|
||||||
|
if let Some(old_token) = self
|
||||||
|
.database_cancellation
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.replace(new_token.clone())
|
||||||
|
{
|
||||||
|
old_token.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
let row_details = self
|
||||||
|
.database_views
|
||||||
|
.get_view_editor(view_id)
|
||||||
|
.await?
|
||||||
|
.v_get_all_row_details()
|
||||||
|
.await;
|
||||||
|
|
||||||
let row_details = database_view.v_get_row_details().await;
|
|
||||||
let (database_id, fields, is_linked) = {
|
let (database_id, fields, is_linked) = {
|
||||||
let database = self.database.read().await;
|
let database = self.database.read().await;
|
||||||
let database_id = database.get_database_id();
|
let database_id = database.get_database_id();
|
||||||
@ -1318,7 +1329,7 @@ impl DatabaseEditor {
|
|||||||
|
|
||||||
let rows = row_details
|
let rows = row_details
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|detail| RowMetaPB::from(detail.as_ref()))
|
.map(|order| RowMetaPB::from(order.as_ref().clone()))
|
||||||
.collect::<Vec<RowMetaPB>>();
|
.collect::<Vec<RowMetaPB>>();
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
@ -1327,25 +1338,16 @@ impl DatabaseEditor {
|
|||||||
fields.len(),
|
fields.len(),
|
||||||
rows.len()
|
rows.len()
|
||||||
);
|
);
|
||||||
|
self.database_cancellation.write().await.take();
|
||||||
Ok(DatabasePB {
|
Ok(DatabasePB {
|
||||||
id: database_id,
|
id: database_id,
|
||||||
fields,
|
fields,
|
||||||
rows,
|
rows,
|
||||||
layout_type: view.layout.into(),
|
layout_type: view_layout.into(),
|
||||||
is_linked,
|
is_linked,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all_rows(&self, view_id: &str) -> FlowyResult<RepeatedRowMetaPB> {
|
|
||||||
let database_view = self.database_views.get_view_editor(view_id).await?;
|
|
||||||
let row_details = database_view.v_get_row_details().await;
|
|
||||||
let rows = row_details
|
|
||||||
.into_iter()
|
|
||||||
.map(|detail| RowMetaPB::from(detail.as_ref()))
|
|
||||||
.collect::<Vec<RowMetaPB>>();
|
|
||||||
Ok(RepeatedRowMetaPB { items: rows })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn export_csv(&self, style: CSVFormat) -> FlowyResult<String> {
|
pub async fn export_csv(&self, style: CSVFormat) -> FlowyResult<String> {
|
||||||
let database = self.database.clone();
|
let database = self.database.clone();
|
||||||
let database_guard = database.read().await;
|
let database_guard = database.read().await;
|
||||||
@ -1467,6 +1469,7 @@ struct DatabaseViewOperationImpl {
|
|||||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||||
cell_cache: CellCache,
|
cell_cache: CellCache,
|
||||||
editor_by_view_id: Arc<RwLock<EditorByViewId>>,
|
editor_by_view_id: Arc<RwLock<EditorByViewId>>,
|
||||||
|
database_cancellation: Arc<RwLock<Option<CancellationToken>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -1559,19 +1562,30 @@ impl DatabaseViewOperation for DatabaseViewOperationImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_row_details(&self, view_id: &str) -> Vec<Arc<RowDetail>> {
|
async fn get_all_row_details(&self, view_id: &str) -> Vec<Arc<RowDetail>> {
|
||||||
let view_id = view_id.to_string();
|
let view_id = view_id.to_string();
|
||||||
let row_orders = self.database.read().await.get_row_orders_for_view(&view_id);
|
let row_orders = self.database.read().await.get_row_orders_for_view(&view_id);
|
||||||
trace!("total row orders: {}", row_orders.len());
|
trace!("{} has total row orders: {}", view_id, row_orders.len());
|
||||||
|
|
||||||
let mut row_details_list = vec![];
|
let mut row_details_list = vec![];
|
||||||
// Loading the rows in chunks of 10 rows in order to prevent blocking the main asynchronous runtime
|
// Loading the rows in chunks of 10 rows in order to prevent blocking the main asynchronous runtime
|
||||||
const CHUNK_SIZE: usize = 10;
|
const CHUNK_SIZE: usize = 10;
|
||||||
|
let cancellation = self
|
||||||
|
.database_cancellation
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.as_ref()
|
||||||
|
.map(|c| c.clone());
|
||||||
for chunk in row_orders.chunks(CHUNK_SIZE) {
|
for chunk in row_orders.chunks(CHUNK_SIZE) {
|
||||||
let database_read_guard = self.database.read().await;
|
let database_read_guard = self.database.read().await;
|
||||||
let chunk = chunk.to_vec();
|
let chunk = chunk.to_vec();
|
||||||
let rows = database_read_guard.get_rows_from_row_orders(&chunk).await;
|
let rows = database_read_guard.get_rows_from_row_orders(&chunk).await;
|
||||||
for row in rows {
|
for row in rows {
|
||||||
|
if let Some(cancellation) = &cancellation {
|
||||||
|
if cancellation.is_cancelled() {
|
||||||
|
info!("Get all database row is cancelled:{}", view_id);
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
}
|
||||||
match database_read_guard.get_row_detail(&row.id).await {
|
match database_read_guard.get_row_detail(&row.id).await {
|
||||||
None => warn!("Failed to get row detail for row: {}", row.id.as_str()),
|
None => warn!("Failed to get row detail for row: {}", row.id.as_str()),
|
||||||
Some(row_details) => {
|
Some(row_details) => {
|
||||||
|
@ -10,9 +10,7 @@ use flowy_notification::{DebounceNotificationSender, NotificationBuilder};
|
|||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use lib_dispatch::prelude::af_spawn;
|
use lib_dispatch::prelude::af_spawn;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tokio_util::sync::CancellationToken;
|
|
||||||
use tracing::{trace, warn};
|
use tracing::{trace, warn};
|
||||||
|
|
||||||
pub(crate) async fn observe_sync_state(database_id: &str, database: &Arc<RwLock<Database>>) {
|
pub(crate) async fn observe_sync_state(database_id: &str, database: &Arc<RwLock<Database>>) {
|
||||||
@ -147,7 +145,7 @@ pub(crate) async fn observe_block_event(database_id: &str, database_editor: &Arc
|
|||||||
.subscribe_block_event();
|
.subscribe_block_event();
|
||||||
let database_editor = Arc::downgrade(database_editor);
|
let database_editor = Arc::downgrade(database_editor);
|
||||||
af_spawn(async move {
|
af_spawn(async move {
|
||||||
let token = CancellationToken::new();
|
// let token = CancellationToken::new();
|
||||||
while let Ok(event) = block_event_rx.recv().await {
|
while let Ok(event) = block_event_rx.recv().await {
|
||||||
if database_editor.upgrade().is_none() {
|
if database_editor.upgrade().is_none() {
|
||||||
break;
|
break;
|
||||||
@ -170,23 +168,17 @@ pub(crate) async fn observe_block_event(database_id: &str, database_editor: &Arc
|
|||||||
.send();
|
.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
let cloned_token = token.clone();
|
// let cloned_token = token.clone();
|
||||||
let cloned_database_editor = database_editor.clone();
|
// tokio::spawn(async move {
|
||||||
tokio::spawn(async move {
|
// tokio::time::sleep(Duration::from_secs(2)).await;
|
||||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
// if cloned_token.is_cancelled() {
|
||||||
if cloned_token.is_cancelled() {
|
// }
|
||||||
return;
|
// // if let Some(database_editor) = cloned_database_editor.upgrade() {
|
||||||
}
|
// // TODO(nathan): calculate inserted row with RowsVisibilityChangePB
|
||||||
if let Some(database_editor) = cloned_database_editor.upgrade() {
|
// // for view_editor in database_editor.database_views.editors().await {
|
||||||
for view_editor in database_editor.database_views.editors().await {
|
// // }
|
||||||
send_notification(
|
// // }
|
||||||
&view_editor.view_id.clone(),
|
// });
|
||||||
DatabaseNotification::ReloadRows,
|
|
||||||
)
|
|
||||||
.send();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,8 +313,8 @@ impl DatabaseViewEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "info", skip(self))]
|
#[instrument(level = "info", skip(self))]
|
||||||
pub async fn v_get_row_details(&self) -> Vec<Arc<RowDetail>> {
|
pub async fn v_get_all_row_details(&self) -> Vec<Arc<RowDetail>> {
|
||||||
let mut rows = self.delegate.get_row_details(&self.view_id).await;
|
let mut rows = self.delegate.get_all_row_details(&self.view_id).await;
|
||||||
self.v_filter_rows(&mut rows).await;
|
self.v_filter_rows(&mut rows).await;
|
||||||
self.v_sort_rows(&mut rows).await;
|
self.v_sort_rows(&mut rows).await;
|
||||||
rows
|
rows
|
||||||
@ -937,7 +937,7 @@ impl DatabaseViewEditor {
|
|||||||
|
|
||||||
let (_, row_detail) = self.delegate.get_row_detail(&self.view_id, &row_id).await?;
|
let (_, row_detail) = self.delegate.get_row_detail(&self.view_id, &row_id).await?;
|
||||||
Some(CalendarEventPB {
|
Some(CalendarEventPB {
|
||||||
row_meta: RowMetaPB::from(row_detail.as_ref()),
|
row_meta: RowMetaPB::from(row_detail.as_ref().clone()),
|
||||||
date_field_id: date_field.id.clone(),
|
date_field_id: date_field.id.clone(),
|
||||||
title,
|
title,
|
||||||
timestamp,
|
timestamp,
|
||||||
@ -1000,7 +1000,7 @@ impl DatabaseViewEditor {
|
|||||||
|
|
||||||
let (_, row_detail) = self.delegate.get_row_detail(&self.view_id, &row_id).await?;
|
let (_, row_detail) = self.delegate.get_row_detail(&self.view_id, &row_id).await?;
|
||||||
let event = CalendarEventPB {
|
let event = CalendarEventPB {
|
||||||
row_meta: RowMetaPB::from(row_detail.as_ref()),
|
row_meta: RowMetaPB::from(row_detail.as_ref().clone()),
|
||||||
date_field_id: calendar_setting.field_id.clone(),
|
date_field_id: calendar_setting.field_id.clone(),
|
||||||
title,
|
title,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
@ -53,7 +53,7 @@ impl FilterDelegate for DatabaseViewFilterDelegateImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn get_rows(&self, view_id: &str) -> Vec<Arc<RowDetail>> {
|
async fn get_rows(&self, view_id: &str) -> Vec<Arc<RowDetail>> {
|
||||||
self.0.get_row_details(view_id).await
|
self.0.get_all_row_details(view_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_row(&self, view_id: &str, rows_id: &RowId) -> Option<(usize, Arc<RowDetail>)> {
|
async fn get_row(&self, view_id: &str, rows_id: &RowId) -> Option<(usize, Arc<RowDetail>)> {
|
||||||
|
@ -97,7 +97,7 @@ impl GroupControllerDelegate for GroupControllerDelegateImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn get_all_rows(&self, view_id: &str) -> Vec<Arc<RowDetail>> {
|
async fn get_all_rows(&self, view_id: &str) -> Vec<Arc<RowDetail>> {
|
||||||
let mut row_details = self.delegate.get_row_details(view_id).await;
|
let mut row_details = self.delegate.get_all_row_details(view_id).await;
|
||||||
self.filter_controller.filter_rows(&mut row_details).await;
|
self.filter_controller.filter_rows(&mut row_details).await;
|
||||||
row_details
|
row_details
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ pub trait DatabaseViewOperation: Send + Sync + 'static {
|
|||||||
async fn get_row_detail(&self, view_id: &str, row_id: &RowId) -> Option<(usize, Arc<RowDetail>)>;
|
async fn get_row_detail(&self, view_id: &str, row_id: &RowId) -> Option<(usize, Arc<RowDetail>)>;
|
||||||
|
|
||||||
/// Returns all the rows in the view
|
/// Returns all the rows in the view
|
||||||
async fn get_row_details(&self, view_id: &str) -> Vec<Arc<RowDetail>>;
|
async fn get_all_row_details(&self, view_id: &str) -> Vec<Arc<RowDetail>>;
|
||||||
|
|
||||||
async fn remove_row(&self, row_id: &RowId) -> Option<Row>;
|
async fn remove_row(&self, row_id: &RowId) -> Option<Row>;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ impl SortDelegate for DatabaseViewSortDelegateImpl {
|
|||||||
|
|
||||||
async fn get_rows(&self, view_id: &str) -> Vec<Arc<RowDetail>> {
|
async fn get_rows(&self, view_id: &str) -> Vec<Arc<RowDetail>> {
|
||||||
let view_id = view_id.to_string();
|
let view_id = view_id.to_string();
|
||||||
let mut row_details = self.delegate.get_row_details(&view_id).await;
|
let mut row_details = self.delegate.get_all_row_details(&view_id).await;
|
||||||
self.filter_controller.filter_rows(&mut row_details).await;
|
self.filter_controller.filter_rows(&mut row_details).await;
|
||||||
row_details
|
row_details
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
mod field_builder;
|
mod field_builder;
|
||||||
mod field_operation;
|
mod field_operation;
|
||||||
|
pub(crate) mod type_option_transform;
|
||||||
pub mod type_options;
|
pub mod type_options;
|
||||||
|
|
||||||
pub use field_builder::*;
|
pub use field_builder::*;
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
use crate::entities::FieldType;
|
||||||
|
use crate::services::field::summary_type_option::summary::SummarizationTypeOption;
|
||||||
|
use crate::services::field::translate_type_option::translate::TranslateTypeOption;
|
||||||
|
use crate::services::field::{
|
||||||
|
CheckboxTypeOption, ChecklistTypeOption, DateTypeOption, MultiSelectTypeOption, NumberTypeOption,
|
||||||
|
RelationTypeOption, RichTextTypeOption, SingleSelectTypeOption, TimeTypeOption,
|
||||||
|
TimestampTypeOption, TypeOptionTransform, URLTypeOption,
|
||||||
|
};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use collab_database::database::Database;
|
||||||
|
use collab_database::fields::TypeOptionData;
|
||||||
|
|
||||||
|
pub async fn transform_type_option(
|
||||||
|
view_id: &str,
|
||||||
|
field_id: &str,
|
||||||
|
old_field_type: FieldType,
|
||||||
|
new_field_type: FieldType,
|
||||||
|
old_type_option_data: Option<TypeOptionData>,
|
||||||
|
new_type_option_data: TypeOptionData,
|
||||||
|
database: &Database,
|
||||||
|
) -> TypeOptionData {
|
||||||
|
if let Some(old_type_option_data) = old_type_option_data {
|
||||||
|
let mut transform_handler =
|
||||||
|
get_type_option_transform_handler(new_type_option_data, new_field_type);
|
||||||
|
transform_handler
|
||||||
|
.transform(
|
||||||
|
view_id,
|
||||||
|
field_id,
|
||||||
|
old_field_type,
|
||||||
|
old_type_option_data,
|
||||||
|
database,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
transform_handler.to_type_option_data()
|
||||||
|
} else {
|
||||||
|
new_type_option_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper trait that used to erase the `Self` of `TypeOption` trait to make it become a Object-safe trait.
|
||||||
|
#[async_trait]
|
||||||
|
pub trait TypeOptionTransformHandler: Send + Sync {
|
||||||
|
async fn transform(
|
||||||
|
&mut self,
|
||||||
|
view_id: &str,
|
||||||
|
field_id: &str,
|
||||||
|
old_type_option_field_type: FieldType,
|
||||||
|
old_type_option_data: TypeOptionData,
|
||||||
|
database: &Database,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn to_type_option_data(&self) -> TypeOptionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<T> TypeOptionTransformHandler for T
|
||||||
|
where
|
||||||
|
T: TypeOptionTransform + Clone,
|
||||||
|
{
|
||||||
|
async fn transform(
|
||||||
|
&mut self,
|
||||||
|
view_id: &str,
|
||||||
|
field_id: &str,
|
||||||
|
old_type_option_field_type: FieldType,
|
||||||
|
old_type_option_data: TypeOptionData,
|
||||||
|
database: &Database,
|
||||||
|
) {
|
||||||
|
self
|
||||||
|
.transform_type_option(
|
||||||
|
view_id,
|
||||||
|
field_id,
|
||||||
|
old_type_option_field_type,
|
||||||
|
old_type_option_data,
|
||||||
|
database,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_type_option_data(&self) -> TypeOptionData {
|
||||||
|
self.clone().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_type_option_transform_handler(
|
||||||
|
type_option_data: TypeOptionData,
|
||||||
|
field_type: FieldType,
|
||||||
|
) -> Box<dyn TypeOptionTransformHandler> {
|
||||||
|
match field_type {
|
||||||
|
FieldType::RichText => {
|
||||||
|
Box::new(RichTextTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::Number => {
|
||||||
|
Box::new(NumberTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::DateTime => {
|
||||||
|
Box::new(DateTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::LastEditedTime | FieldType::CreatedTime => {
|
||||||
|
Box::new(TimestampTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::SingleSelect => Box::new(SingleSelectTypeOption::from(type_option_data))
|
||||||
|
as Box<dyn TypeOptionTransformHandler>,
|
||||||
|
FieldType::MultiSelect => {
|
||||||
|
Box::new(MultiSelectTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::Checkbox => {
|
||||||
|
Box::new(CheckboxTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::URL => {
|
||||||
|
Box::new(URLTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::Checklist => {
|
||||||
|
Box::new(ChecklistTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::Relation => {
|
||||||
|
Box::new(RelationTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::Summary => Box::new(SummarizationTypeOption::from(type_option_data))
|
||||||
|
as Box<dyn TypeOptionTransformHandler>,
|
||||||
|
FieldType::Time => {
|
||||||
|
Box::new(TimeTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
FieldType::Translate => {
|
||||||
|
Box::new(TranslateTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,15 @@
|
|||||||
use std::cmp::Ordering;
|
use collab_database::entity::SelectOption;
|
||||||
|
|
||||||
use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder};
|
use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder};
|
||||||
use collab_database::rows::Cell;
|
use collab_database::rows::Cell;
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use crate::entities::{ChecklistCellDataPB, ChecklistFilterPB, SelectOptionPB};
|
use crate::entities::{ChecklistCellDataPB, ChecklistFilterPB, SelectOptionPB};
|
||||||
use crate::services::cell::{CellDataChangeset, CellDataDecoder};
|
use crate::services::cell::{CellDataChangeset, CellDataDecoder};
|
||||||
use crate::services::field::checklist_type_option::{ChecklistCellChangeset, ChecklistCellData};
|
use crate::services::field::checklist_type_option::{ChecklistCellChangeset, ChecklistCellData};
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
SelectOption, TypeOption, TypeOptionCellData, TypeOptionCellDataCompare,
|
TypeOption, TypeOptionCellData, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
||||||
TypeOptionCellDataFilter, TypeOptionCellDataSerde, TypeOptionTransform, SELECTION_IDS_SEPARATOR,
|
TypeOptionCellDataSerde, TypeOptionTransform, SELECTION_IDS_SEPARATOR,
|
||||||
};
|
};
|
||||||
use crate::services::sort::SortCondition;
|
use crate::services::sort::SortCondition;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::entities::FieldType;
|
use crate::entities::FieldType;
|
||||||
use crate::services::field::{SelectOption, TypeOptionCellData, CELL_DATA};
|
use crate::services::field::{TypeOptionCellData, CELL_DATA};
|
||||||
use collab::util::AnyMapExt;
|
use collab::util::AnyMapExt;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::rows::{new_cell_builder, Cell};
|
use collab_database::rows::{new_cell_builder, Cell};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::Field;
|
use collab_database::fields::Field;
|
||||||
use collab_database::rows::Cell;
|
use collab_database::rows::Cell;
|
||||||
|
|
||||||
use crate::entities::{ChecklistFilterConditionPB, ChecklistFilterPB};
|
use crate::entities::{ChecklistFilterConditionPB, ChecklistFilterPB};
|
||||||
use crate::services::field::SelectOption;
|
|
||||||
use crate::services::filter::PreFillCellsWithFilter;
|
use crate::services::filter::PreFillCellsWithFilter;
|
||||||
|
|
||||||
impl ChecklistFilterPB {
|
impl ChecklistFilterPB {
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
use collab::util::AnyMapExt;
|
use collab::util::AnyMapExt;
|
||||||
use std::cmp::Ordering;
|
use collab_database::entity::SelectOption;
|
||||||
|
|
||||||
use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder};
|
use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder};
|
||||||
use collab_database::rows::Cell;
|
use collab_database::rows::Cell;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
|
|
||||||
use crate::entities::{FieldType, SelectOptionCellDataPB, SelectOptionFilterPB};
|
use crate::entities::{FieldType, SelectOptionCellDataPB, SelectOptionFilterPB};
|
||||||
use crate::services::cell::CellDataChangeset;
|
use crate::services::cell::CellDataChangeset;
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
default_order, SelectOption, SelectOptionCellChangeset, SelectOptionIds,
|
default_order, SelectOptionCellChangeset, SelectOptionIds, SelectTypeOptionSharedAction,
|
||||||
SelectTypeOptionSharedAction, TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter, TypeOptionCellDataSerde,
|
||||||
TypeOptionCellDataSerde,
|
|
||||||
};
|
};
|
||||||
use crate::services::sort::SortCondition;
|
use crate::services::sort::SortCondition;
|
||||||
|
|
||||||
@ -176,39 +175,10 @@ impl TypeOptionCellDataCompare for MultiSelectTypeOption {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::entities::FieldType;
|
|
||||||
use crate::services::cell::CellDataChangeset;
|
use crate::services::cell::CellDataChangeset;
|
||||||
use crate::services::field::type_options::selection_type_option::*;
|
use crate::services::field::type_options::selection_type_option::*;
|
||||||
use crate::services::field::MultiSelectTypeOption;
|
use crate::services::field::MultiSelectTypeOption;
|
||||||
use crate::services::field::{CheckboxTypeOption, TypeOptionTransform};
|
use collab_database::entity::SelectOption;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multi_select_transform_with_checkbox_type_option_test() {
|
|
||||||
let checkbox_type_option = CheckboxTypeOption();
|
|
||||||
let mut multi_select = MultiSelectTypeOption::default();
|
|
||||||
multi_select.transform_type_option(FieldType::Checkbox, checkbox_type_option.clone().into());
|
|
||||||
debug_assert_eq!(multi_select.options.len(), 2);
|
|
||||||
|
|
||||||
// Already contain the yes/no option. It doesn't need to insert new options
|
|
||||||
multi_select.transform_type_option(FieldType::Checkbox, checkbox_type_option.into());
|
|
||||||
debug_assert_eq!(multi_select.options.len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multi_select_transform_with_single_select_type_option_test() {
|
|
||||||
let google = SelectOption::new("Google");
|
|
||||||
let facebook = SelectOption::new("Facebook");
|
|
||||||
let single_select = SingleSelectTypeOption {
|
|
||||||
options: vec![google, facebook],
|
|
||||||
disable_color: false,
|
|
||||||
};
|
|
||||||
let mut multi_select = MultiSelectTypeOption {
|
|
||||||
options: vec![],
|
|
||||||
disable_color: false,
|
|
||||||
};
|
|
||||||
multi_select.transform_type_option(FieldType::MultiSelect, single_select.into());
|
|
||||||
debug_assert_eq!(multi_select.options.len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multi_select_insert_multi_option_test() {
|
fn multi_select_insert_multi_option_test() {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::Field;
|
use collab_database::fields::Field;
|
||||||
use collab_database::rows::Cell;
|
use collab_database::rows::Cell;
|
||||||
|
|
||||||
use crate::entities::{SelectOptionFilterConditionPB, SelectOptionFilterPB};
|
use crate::entities::{SelectOptionFilterConditionPB, SelectOptionFilterPB};
|
||||||
use crate::services::cell::insert_select_option_cell;
|
use crate::services::cell::insert_select_option_cell;
|
||||||
use crate::services::field::{select_type_option_from_field, SelectOption};
|
use crate::services::field::select_type_option_from_field;
|
||||||
use crate::services::filter::PreFillCellsWithFilter;
|
use crate::services::filter::PreFillCellsWithFilter;
|
||||||
|
|
||||||
impl SelectOptionFilterPB {
|
impl SelectOptionFilterPB {
|
||||||
@ -132,7 +133,7 @@ impl PreFillCellsWithFilter for SelectOptionFilterPB {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::entities::{SelectOptionFilterConditionPB, SelectOptionFilterPB};
|
use crate::entities::{SelectOptionFilterConditionPB, SelectOptionFilterPB};
|
||||||
use crate::services::field::SelectOption;
|
use collab_database::entity::SelectOption;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn select_option_filter_is_empty_test() {
|
fn select_option_filter_is_empty_test() {
|
||||||
|
@ -1,50 +1,6 @@
|
|||||||
use crate::entities::SelectOptionCellDataPB;
|
use crate::entities::SelectOptionCellDataPB;
|
||||||
use crate::services::field::SelectOptionIds;
|
use crate::services::field::SelectOptionIds;
|
||||||
use collab_database::database::gen_option_id;
|
use collab_database::entity::SelectOption;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// [SelectOption] represents an option for a single select, and multiple select.
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub struct SelectOption {
|
|
||||||
pub id: String,
|
|
||||||
pub name: String,
|
|
||||||
pub color: SelectOptionColor,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SelectOption {
|
|
||||||
pub fn new(name: &str) -> Self {
|
|
||||||
SelectOption {
|
|
||||||
id: gen_option_id(),
|
|
||||||
name: name.to_owned(),
|
|
||||||
color: SelectOptionColor::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_color(name: &str, color: SelectOptionColor) -> Self {
|
|
||||||
SelectOption {
|
|
||||||
id: gen_option_id(),
|
|
||||||
name: name.to_owned(),
|
|
||||||
color,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Clone)]
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Default)]
|
|
||||||
pub enum SelectOptionColor {
|
|
||||||
#[default]
|
|
||||||
Purple = 0,
|
|
||||||
Pink = 1,
|
|
||||||
LightPink = 2,
|
|
||||||
Orange = 3,
|
|
||||||
Yellow = 4,
|
|
||||||
Lime = 5,
|
|
||||||
Green = 6,
|
|
||||||
Aqua = 7,
|
|
||||||
Blue = 8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SelectOptionCellData {
|
pub struct SelectOptionCellData {
|
||||||
pub select_options: Vec<SelectOption>,
|
pub select_options: Vec<SelectOption>,
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
use std::str::FromStr;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
use collab_database::database::Database;
|
||||||
|
use collab_database::entity::{SelectOption, SelectOptionColor};
|
||||||
use collab_database::fields::{Field, TypeOptionData};
|
use collab_database::fields::{Field, TypeOptionData};
|
||||||
use collab_database::rows::Cell;
|
use collab_database::rows::Cell;
|
||||||
|
|
||||||
use flowy_error::{internal_error, ErrorCode, FlowyResult};
|
use flowy_error::{internal_error, ErrorCode, FlowyResult};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::entities::{CheckboxCellDataPB, FieldType, SelectOptionCellDataPB};
|
use crate::entities::{CheckboxCellDataPB, FieldType, SelectOptionCellDataPB};
|
||||||
use crate::services::cell::{CellDataDecoder, CellProtobufBlobParser};
|
use crate::services::cell::{CellDataDecoder, CellProtobufBlobParser};
|
||||||
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformHelper;
|
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformHelper;
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
make_selected_options, MultiSelectTypeOption, SelectOption, SelectOptionCellData,
|
make_selected_options, MultiSelectTypeOption, SelectOptionCellData, SelectOptionIds,
|
||||||
SelectOptionColor, SelectOptionIds, SingleSelectTypeOption, TypeOption, TypeOptionCellDataSerde,
|
SingleSelectTypeOption, StringCellData, TypeOption, TypeOptionCellDataSerde, TypeOptionTransform,
|
||||||
TypeOptionTransform, SELECTION_IDS_SEPARATOR,
|
SELECTION_IDS_SEPARATOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Defines the shared actions used by SingleSelect or Multi-Select.
|
/// Defines the shared actions used by SingleSelect or Multi-Select.
|
||||||
@ -68,20 +69,28 @@ pub trait SelectTypeOptionSharedAction: Send + Sync {
|
|||||||
fn mut_options(&mut self) -> &mut Vec<SelectOption>;
|
fn mut_options(&mut self) -> &mut Vec<SelectOption>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl<T> TypeOptionTransform for T
|
impl<T> TypeOptionTransform for T
|
||||||
where
|
where
|
||||||
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds> + CellDataDecoder,
|
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds> + CellDataDecoder,
|
||||||
{
|
{
|
||||||
fn transform_type_option(
|
async fn transform_type_option(
|
||||||
&mut self,
|
&mut self,
|
||||||
_old_type_option_field_type: FieldType,
|
view_id: &str,
|
||||||
_old_type_option_data: TypeOptionData,
|
field_id: &str,
|
||||||
|
old_type_option_field_type: FieldType,
|
||||||
|
old_type_option_data: TypeOptionData,
|
||||||
|
database: &Database,
|
||||||
) {
|
) {
|
||||||
SelectOptionTypeOptionTransformHelper::transform_type_option(
|
SelectOptionTypeOptionTransformHelper::transform_type_option(
|
||||||
self,
|
self,
|
||||||
&_old_type_option_field_type,
|
view_id,
|
||||||
_old_type_option_data,
|
field_id,
|
||||||
);
|
&old_type_option_field_type,
|
||||||
|
old_type_option_data,
|
||||||
|
database,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +110,15 @@ where
|
|||||||
_field: &Field,
|
_field: &Field,
|
||||||
) -> Option<<Self as TypeOption>::CellData> {
|
) -> Option<<Self as TypeOption>::CellData> {
|
||||||
match from_field_type {
|
match from_field_type {
|
||||||
|
FieldType::RichText => {
|
||||||
|
let text_cell = StringCellData::from(cell).into_inner();
|
||||||
|
let mut transformed_ids = Vec::new();
|
||||||
|
let options = self.options();
|
||||||
|
if let Some(option) = options.iter().find(|option| option.name == text_cell) {
|
||||||
|
transformed_ids.push(option.id.clone());
|
||||||
|
}
|
||||||
|
Some(SelectOptionIds::from(transformed_ids))
|
||||||
|
},
|
||||||
FieldType::Checkbox => {
|
FieldType::Checkbox => {
|
||||||
let cell_content = CheckboxCellDataPB::from(cell).to_string();
|
let cell_content = CheckboxCellDataPB::from(cell).to_string();
|
||||||
let mut transformed_ids = Vec::new();
|
let mut transformed_ids = Vec::new();
|
||||||
@ -110,7 +128,6 @@ where
|
|||||||
}
|
}
|
||||||
Some(SelectOptionIds::from(transformed_ids))
|
Some(SelectOptionIds::from(transformed_ids))
|
||||||
},
|
},
|
||||||
FieldType::RichText => Some(SelectOptionIds::from(cell)),
|
|
||||||
FieldType::SingleSelect | FieldType::MultiSelect => Some(SelectOptionIds::from(cell)),
|
FieldType::SingleSelect | FieldType::MultiSelect => Some(SelectOptionIds::from(cell)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::entities::{FieldType, SelectOptionCellDataPB, SelectOptionFilterPB};
|
use crate::entities::{FieldType, SelectOptionCellDataPB, SelectOptionFilterPB};
|
||||||
use crate::services::cell::CellDataChangeset;
|
use crate::services::cell::CellDataChangeset;
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
default_order, SelectOption, TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
default_order, TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
||||||
TypeOptionCellDataSerde,
|
TypeOptionCellDataSerde,
|
||||||
};
|
};
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
@ -9,6 +9,7 @@ use crate::services::field::{
|
|||||||
};
|
};
|
||||||
use crate::services::sort::SortCondition;
|
use crate::services::sort::SortCondition;
|
||||||
use collab::util::AnyMapExt;
|
use collab::util::AnyMapExt;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder};
|
use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder};
|
||||||
use collab_database::rows::Cell;
|
use collab_database::rows::Cell;
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
@ -149,40 +150,9 @@ impl TypeOptionCellDataCompare for SingleSelectTypeOption {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::entities::FieldType;
|
|
||||||
use crate::services::cell::CellDataChangeset;
|
use crate::services::cell::CellDataChangeset;
|
||||||
use crate::services::field::type_options::*;
|
use crate::services::field::type_options::*;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
#[test]
|
|
||||||
fn single_select_transform_with_checkbox_type_option_test() {
|
|
||||||
let checkbox = CheckboxTypeOption::default();
|
|
||||||
|
|
||||||
let mut single_select = SingleSelectTypeOption::default();
|
|
||||||
single_select.transform_type_option(FieldType::Checkbox, checkbox.clone().into());
|
|
||||||
debug_assert_eq!(single_select.options.len(), 2);
|
|
||||||
|
|
||||||
// Already contain the yes/no option. It doesn't need to insert new options
|
|
||||||
single_select.transform_type_option(FieldType::Checkbox, checkbox.into());
|
|
||||||
debug_assert_eq!(single_select.options.len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn single_select_transform_with_multi_select_type_option_test() {
|
|
||||||
let google = SelectOption::new("Google");
|
|
||||||
let facebook = SelectOption::new("Facebook");
|
|
||||||
let multi_select = MultiSelectTypeOption {
|
|
||||||
options: vec![google, facebook],
|
|
||||||
disable_color: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut single_select = SingleSelectTypeOption::default();
|
|
||||||
single_select.transform_type_option(FieldType::MultiSelect, multi_select.clone().into());
|
|
||||||
debug_assert_eq!(single_select.options.len(), 2);
|
|
||||||
|
|
||||||
// Already contain the yes/no option. It doesn't need to insert new options
|
|
||||||
single_select.transform_type_option(FieldType::MultiSelect, multi_select.into());
|
|
||||||
debug_assert_eq!(single_select.options.len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_select_insert_multi_option_test() {
|
fn single_select_insert_multi_option_test() {
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
use crate::entities::FieldType;
|
use crate::entities::FieldType;
|
||||||
|
use crate::services::cell::CellDataDecoder;
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
MultiSelectTypeOption, SelectOption, SelectOptionColor, SelectOptionIds,
|
MultiSelectTypeOption, RichTextTypeOption, SelectOptionIds, SelectTypeOptionSharedAction,
|
||||||
SelectTypeOptionSharedAction, SingleSelectTypeOption, TypeOption, CHECK, UNCHECK,
|
SingleSelectTypeOption, TypeOption, CHECK, UNCHECK,
|
||||||
};
|
};
|
||||||
|
use collab_database::database::Database;
|
||||||
|
use collab_database::entity::{SelectOption, SelectOptionColor};
|
||||||
use collab_database::fields::TypeOptionData;
|
use collab_database::fields::TypeOptionData;
|
||||||
|
use collab_database::template::option_parse::build_options_from_cells;
|
||||||
|
|
||||||
/// Handles how to transform the cell data when switching between different field types
|
/// Handles how to transform the cell data when switching between different field types
|
||||||
pub(crate) struct SelectOptionTypeOptionTransformHelper();
|
pub(crate) struct SelectOptionTypeOptionTransformHelper();
|
||||||
@ -14,14 +18,37 @@ impl SelectOptionTypeOptionTransformHelper {
|
|||||||
///
|
///
|
||||||
/// * `old_field_type`: the FieldType of the passed-in TypeOptionData
|
/// * `old_field_type`: the FieldType of the passed-in TypeOptionData
|
||||||
///
|
///
|
||||||
pub fn transform_type_option<T>(
|
pub async fn transform_type_option<T>(
|
||||||
shared: &mut T,
|
shared: &mut T,
|
||||||
|
view_id: &str,
|
||||||
|
field_id: &str,
|
||||||
old_field_type: &FieldType,
|
old_field_type: &FieldType,
|
||||||
old_type_option_data: TypeOptionData,
|
old_type_option_data: TypeOptionData,
|
||||||
|
database: &Database,
|
||||||
) where
|
) where
|
||||||
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds>,
|
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds>,
|
||||||
{
|
{
|
||||||
match old_field_type {
|
match old_field_type {
|
||||||
|
FieldType::RichText => {
|
||||||
|
if !shared.options().is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let text_type_option = RichTextTypeOption::from(old_type_option_data);
|
||||||
|
let cells = database
|
||||||
|
.get_cells_for_field(view_id, field_id)
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| e.cell)
|
||||||
|
.map(|cell| {
|
||||||
|
text_type_option
|
||||||
|
.decode_cell(&cell)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_inner()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let options = build_options_from_cells(&cells);
|
||||||
|
shared.mut_options().extend(options);
|
||||||
|
},
|
||||||
FieldType::Checkbox => {
|
FieldType::Checkbox => {
|
||||||
// add Yes and No options if it does not exist.
|
// add Yes and No options if it does not exist.
|
||||||
if !shared.options().iter().any(|option| option.name == CHECK) {
|
if !shared.options().iter().any(|option| option.name == CHECK) {
|
||||||
|
@ -4,6 +4,7 @@ mod tests {
|
|||||||
use crate::services::cell::{insert_select_option_cell, stringify_cell};
|
use crate::services::cell::{insert_select_option_cell, stringify_cell};
|
||||||
use crate::services::field::FieldBuilder;
|
use crate::services::field::FieldBuilder;
|
||||||
use crate::services::field::*;
|
use crate::services::field::*;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
|
|
||||||
// Test parser the cell data which field's type is FieldType::Date to cell data
|
// Test parser the cell data which field's type is FieldType::Date to cell data
|
||||||
// which field's type is FieldType::Text
|
// which field's type is FieldType::Text
|
||||||
|
@ -147,6 +147,11 @@ impl TypeOptionCellDataCompare for RichTextTypeOption {
|
|||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct StringCellData(pub String);
|
pub struct StringCellData(pub String);
|
||||||
|
impl StringCellData {
|
||||||
|
pub fn into_inner(self) -> String {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::ops::Deref for StringCellData {
|
impl std::ops::Deref for StringCellData {
|
||||||
type Target = String;
|
type Target = String;
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use std::cmp::Ordering;
|
use async_trait::async_trait;
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
use collab_database::database::Database;
|
||||||
use collab_database::fields::TypeOptionData;
|
use collab_database::fields::TypeOptionData;
|
||||||
use collab_database::rows::Cell;
|
use collab_database::rows::Cell;
|
||||||
use protobuf::ProtobufError;
|
use protobuf::ProtobufError;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
|
|
||||||
@ -92,7 +93,8 @@ pub trait TypeOptionCellData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TypeOptionTransform: TypeOption {
|
#[async_trait]
|
||||||
|
pub trait TypeOptionTransform: TypeOption + Send + Sync {
|
||||||
/// Transform the TypeOption from one field type to another
|
/// Transform the TypeOption from one field type to another
|
||||||
/// For example, when switching from `Checkbox` type option to `Single-Select`
|
/// For example, when switching from `Checkbox` type option to `Single-Select`
|
||||||
/// type option, adding the `Yes` option if the `Single-select` type-option doesn't contain it.
|
/// type option, adding the `Yes` option if the `Single-select` type-option doesn't contain it.
|
||||||
@ -104,10 +106,13 @@ pub trait TypeOptionTransform: TypeOption {
|
|||||||
/// * `old_type_option_field_type`: the FieldType of the passed-in TypeOption
|
/// * `old_type_option_field_type`: the FieldType of the passed-in TypeOption
|
||||||
/// * `old_type_option_data`: the data that can be parsed into corresponding `TypeOption`.
|
/// * `old_type_option_data`: the data that can be parsed into corresponding `TypeOption`.
|
||||||
///
|
///
|
||||||
fn transform_type_option(
|
async fn transform_type_option(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
_view_id: &str,
|
||||||
|
_field_id: &str,
|
||||||
_old_type_option_field_type: FieldType,
|
_old_type_option_field_type: FieldType,
|
||||||
_old_type_option_data: TypeOptionData,
|
_old_type_option_data: TypeOptionData,
|
||||||
|
_database: &Database,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,8 @@ use std::collections::hash_map::DefaultHasher;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
use collab_database::fields::{Field, TypeOptionData};
|
use collab_database::fields::Field;
|
||||||
use collab_database::rows::{get_field_type_from_cell, Cell, RowId};
|
use collab_database::rows::{get_field_type_from_cell, Cell, RowId};
|
||||||
|
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
use lib_infra::box_any::BoxAny;
|
use lib_infra::box_any::BoxAny;
|
||||||
|
|
||||||
@ -93,6 +92,7 @@ pub trait TypeOptionCellDataHandler: Send + Sync + 'static {
|
|||||||
fn handle_is_cell_empty(&self, cell: &Cell, field: &Field) -> bool;
|
fn handle_is_cell_empty(&self, cell: &Cell, field: &Field) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct CellDataCacheKey(u64);
|
struct CellDataCacheKey(u64);
|
||||||
impl CellDataCacheKey {
|
impl CellDataCacheKey {
|
||||||
pub fn new(field_rev: &Field, decoded_field_type: FieldType, cell: &Cell) -> Self {
|
pub fn new(field_rev: &Field, decoded_field_type: FieldType, cell: &Cell) -> Self {
|
||||||
@ -185,9 +185,7 @@ where
|
|||||||
|
|
||||||
fn get_cell_data_from_cache(&self, cell: &Cell, field: &Field) -> Option<T::CellData> {
|
fn get_cell_data_from_cache(&self, cell: &Cell, field: &Field) -> Option<T::CellData> {
|
||||||
let key = self.get_cell_data_cache_key(cell, field);
|
let key = self.get_cell_data_cache_key(cell, field);
|
||||||
|
|
||||||
let cell_data_cache = self.cell_data_cache.as_ref()?;
|
let cell_data_cache = self.cell_data_cache.as_ref()?;
|
||||||
|
|
||||||
let cell = cell_data_cache.get::<T::CellData>(key.as_ref())?;
|
let cell = cell_data_cache.get::<T::CellData>(key.as_ref())?;
|
||||||
Some(cell.value().clone())
|
Some(cell.value().clone())
|
||||||
}
|
}
|
||||||
@ -507,109 +505,27 @@ impl<'a> TypeOptionCellExt<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// when return true, the to_field_type must implement [CellDataDecoder]'s decode_cell_with_transform
|
||||||
pub fn is_type_option_cell_transformable(
|
pub fn is_type_option_cell_transformable(
|
||||||
from_field_type: FieldType,
|
from_field_type: FieldType,
|
||||||
to_field_type: FieldType,
|
to_field_type: FieldType,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
(from_field_type, to_field_type),
|
(from_field_type, to_field_type),
|
||||||
|
// Checkbox
|
||||||
(FieldType::Checkbox, FieldType::SingleSelect)
|
(FieldType::Checkbox, FieldType::SingleSelect)
|
||||||
| (FieldType::Checkbox, FieldType::MultiSelect)
|
| (FieldType::Checkbox, FieldType::MultiSelect)
|
||||||
|
// SingleSelect or MultiSelect
|
||||||
| (FieldType::SingleSelect, FieldType::MultiSelect)
|
| (FieldType::SingleSelect, FieldType::MultiSelect)
|
||||||
| (FieldType::MultiSelect, FieldType::SingleSelect)
|
| (FieldType::MultiSelect, FieldType::SingleSelect)
|
||||||
|
// Text
|
||||||
|
| (FieldType::RichText, FieldType::SingleSelect)
|
||||||
|
| (FieldType::RichText, FieldType::MultiSelect)
|
||||||
|
| (FieldType::RichText, FieldType::URL)
|
||||||
| (_, FieldType::RichText)
|
| (_, FieldType::RichText)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transform_type_option(
|
|
||||||
old_field_type: FieldType,
|
|
||||||
new_field_type: FieldType,
|
|
||||||
old_type_option_data: Option<TypeOptionData>,
|
|
||||||
new_type_option_data: TypeOptionData,
|
|
||||||
) -> TypeOptionData {
|
|
||||||
if let Some(old_type_option_data) = old_type_option_data {
|
|
||||||
let mut transform_handler =
|
|
||||||
get_type_option_transform_handler(new_type_option_data, new_field_type);
|
|
||||||
transform_handler.transform(old_field_type, old_type_option_data);
|
|
||||||
transform_handler.to_type_option_data()
|
|
||||||
} else {
|
|
||||||
new_type_option_data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A helper trait that used to erase the `Self` of `TypeOption` trait to make it become a Object-safe trait.
|
|
||||||
pub trait TypeOptionTransformHandler {
|
|
||||||
fn transform(
|
|
||||||
&mut self,
|
|
||||||
old_type_option_field_type: FieldType,
|
|
||||||
old_type_option_data: TypeOptionData,
|
|
||||||
);
|
|
||||||
|
|
||||||
fn to_type_option_data(&self) -> TypeOptionData;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> TypeOptionTransformHandler for T
|
|
||||||
where
|
|
||||||
T: TypeOptionTransform + Clone,
|
|
||||||
{
|
|
||||||
fn transform(
|
|
||||||
&mut self,
|
|
||||||
old_type_option_field_type: FieldType,
|
|
||||||
old_type_option_data: TypeOptionData,
|
|
||||||
) {
|
|
||||||
self.transform_type_option(old_type_option_field_type, old_type_option_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_type_option_data(&self) -> TypeOptionData {
|
|
||||||
self.clone().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_type_option_transform_handler(
|
|
||||||
type_option_data: TypeOptionData,
|
|
||||||
field_type: FieldType,
|
|
||||||
) -> Box<dyn TypeOptionTransformHandler> {
|
|
||||||
match field_type {
|
|
||||||
FieldType::RichText => {
|
|
||||||
Box::new(RichTextTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::Number => {
|
|
||||||
Box::new(NumberTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::DateTime => {
|
|
||||||
Box::new(DateTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::LastEditedTime | FieldType::CreatedTime => {
|
|
||||||
Box::new(TimestampTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::SingleSelect => Box::new(SingleSelectTypeOption::from(type_option_data))
|
|
||||||
as Box<dyn TypeOptionTransformHandler>,
|
|
||||||
FieldType::MultiSelect => {
|
|
||||||
Box::new(MultiSelectTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::Checkbox => {
|
|
||||||
Box::new(CheckboxTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::URL => {
|
|
||||||
Box::new(URLTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::Checklist => {
|
|
||||||
Box::new(ChecklistTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::Relation => {
|
|
||||||
Box::new(RelationTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::Summary => Box::new(SummarizationTypeOption::from(type_option_data))
|
|
||||||
as Box<dyn TypeOptionTransformHandler>,
|
|
||||||
FieldType::Time => {
|
|
||||||
Box::new(TimeTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
FieldType::Translate => {
|
|
||||||
Box::new(TranslateTypeOption::from(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type BoxCellData = BoxAny;
|
pub type BoxCellData = BoxAny;
|
||||||
|
|
||||||
pub struct RowSingleCellData {
|
pub struct RowSingleCellData {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use collab::preclude::encoding::serde::from_any;
|
use collab::preclude::encoding::serde::from_any;
|
||||||
use collab::preclude::Any;
|
use collab::preclude::Any;
|
||||||
use std::cmp::Ordering;
|
|
||||||
|
|
||||||
use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder};
|
use collab_database::fields::{Field, TypeOptionData, TypeOptionDataBuilder};
|
||||||
use collab_database::rows::Cell;
|
use collab_database::rows::Cell;
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use crate::entities::{TextFilterPB, URLCellDataPB};
|
use crate::entities::{FieldType, TextFilterPB, URLCellDataPB};
|
||||||
use crate::services::cell::{CellDataChangeset, CellDataDecoder};
|
use crate::services::cell::{CellDataChangeset, CellDataDecoder};
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter, TypeOptionCellDataSerde,
|
TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter, TypeOptionCellDataSerde,
|
||||||
@ -64,6 +64,17 @@ impl CellDataDecoder for URLTypeOption {
|
|||||||
fn decode_cell(&self, cell: &Cell) -> FlowyResult<<Self as TypeOption>::CellData> {
|
fn decode_cell(&self, cell: &Cell) -> FlowyResult<<Self as TypeOption>::CellData> {
|
||||||
self.parse_cell(cell)
|
self.parse_cell(cell)
|
||||||
}
|
}
|
||||||
|
fn decode_cell_with_transform(
|
||||||
|
&self,
|
||||||
|
cell: &Cell,
|
||||||
|
from_field_type: FieldType,
|
||||||
|
_field: &Field,
|
||||||
|
) -> Option<<Self as TypeOption>::CellData> {
|
||||||
|
match from_field_type {
|
||||||
|
FieldType::RichText => Some(Self::CellData::from(cell)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn stringify_cell_data(&self, cell_data: <Self as TypeOption>::CellData) -> String {
|
fn stringify_cell_data(&self, cell_data: <Self as TypeOption>::CellData) -> String {
|
||||||
cell_data.data
|
cell_data.data
|
||||||
|
@ -360,7 +360,8 @@ impl FilterController {
|
|||||||
if is_visible {
|
if is_visible {
|
||||||
if let Some((index, _row)) = self.delegate.get_row(&self.view_id, &row_id).await {
|
if let Some((index, _row)) = self.delegate.get_row(&self.view_id, &row_id).await {
|
||||||
notification.visible_rows.push(
|
notification.visible_rows.push(
|
||||||
InsertedRowPB::new(RowMetaPB::from(row_detail.as_ref())).with_index(index as i32),
|
InsertedRowPB::new(RowMetaPB::from(row_detail.as_ref().clone()))
|
||||||
|
.with_index(index as i32),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -397,7 +398,7 @@ impl FilterController {
|
|||||||
&filters,
|
&filters,
|
||||||
) {
|
) {
|
||||||
if is_visible {
|
if is_visible {
|
||||||
let row_meta = RowMetaPB::from(row_detail.as_ref());
|
let row_meta = RowMetaPB::from(row_detail.as_ref().clone());
|
||||||
visible_rows.push(InsertedRowPB::new(row_meta).with_index(index as i32))
|
visible_rows.push(InsertedRowPB::new(row_meta).with_index(index as i32))
|
||||||
} else {
|
} else {
|
||||||
invisible_rows.push(row_detail.row.id.clone());
|
invisible_rows.push(row_detail.row.id.clone());
|
||||||
|
@ -115,7 +115,7 @@ where
|
|||||||
if !no_status_group_rows.is_empty() {
|
if !no_status_group_rows.is_empty() {
|
||||||
changeset
|
changeset
|
||||||
.inserted_rows
|
.inserted_rows
|
||||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||||
no_status_group.add_row(row_detail.clone());
|
no_status_group.add_row(row_detail.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ impl GroupCustomize for CheckboxGroupController {
|
|||||||
if is_not_contained {
|
if is_not_contained {
|
||||||
changeset
|
changeset
|
||||||
.inserted_rows
|
.inserted_rows
|
||||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||||
group.add_row(row_detail.clone());
|
group.add_row(row_detail.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ impl GroupCustomize for CheckboxGroupController {
|
|||||||
if is_not_contained {
|
if is_not_contained {
|
||||||
changeset
|
changeset
|
||||||
.inserted_rows
|
.inserted_rows
|
||||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||||
group.add_row(row_detail.clone());
|
group.add_row(row_detail.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,10 @@ impl GroupCustomize for DateGroupController {
|
|||||||
{
|
{
|
||||||
let group = make_group_from_date_cell(&_cell_data.into(), &setting_content);
|
let group = make_group_from_date_cell(&_cell_data.into(), &setting_content);
|
||||||
let mut new_group = self.context.add_new_group(group)?;
|
let mut new_group = self.context.add_new_group(group)?;
|
||||||
new_group.group.rows.push(RowMetaPB::from(_row_detail));
|
new_group
|
||||||
|
.group
|
||||||
|
.rows
|
||||||
|
.push(RowMetaPB::from(_row_detail.clone()));
|
||||||
inserted_group = Some(new_group);
|
inserted_group = Some(new_group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +133,7 @@ impl GroupCustomize for DateGroupController {
|
|||||||
if !group.contains_row(&row_detail.row.id) {
|
if !group.contains_row(&row_detail.row.id) {
|
||||||
changeset
|
changeset
|
||||||
.inserted_rows
|
.inserted_rows
|
||||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||||
group.add_row(row_detail.clone());
|
group.add_row(row_detail.clone());
|
||||||
}
|
}
|
||||||
} else if group.contains_row(&row_detail.row.id) {
|
} else if group.contains_row(&row_detail.row.id) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::{Field, TypeOptionData};
|
use collab_database::fields::{Field, TypeOptionData};
|
||||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||||
use flowy_error::{FlowyError, FlowyResult};
|
use flowy_error::{FlowyError, FlowyResult};
|
||||||
@ -7,8 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::entities::{FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
use crate::entities::{FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
||||||
use crate::services::cell::insert_select_option_cell;
|
use crate::services::cell::insert_select_option_cell;
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
MultiSelectTypeOption, SelectOption, SelectOptionCellDataParser, SelectTypeOptionSharedAction,
|
MultiSelectTypeOption, SelectOptionCellDataParser, SelectTypeOptionSharedAction, TypeOption,
|
||||||
TypeOption,
|
|
||||||
};
|
};
|
||||||
use crate::services::group::action::GroupCustomize;
|
use crate::services::group::action::GroupCustomize;
|
||||||
use crate::services::group::controller::BaseGroupController;
|
use crate::services::group::controller::BaseGroupController;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::{Field, TypeOptionData};
|
use collab_database::fields::{Field, TypeOptionData};
|
||||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||||
use flowy_error::{FlowyError, FlowyResult};
|
use flowy_error::{FlowyError, FlowyResult};
|
||||||
@ -7,8 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::entities::{FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
use crate::entities::{FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
||||||
use crate::services::cell::insert_select_option_cell;
|
use crate::services::cell::insert_select_option_cell;
|
||||||
use crate::services::field::{
|
use crate::services::field::{
|
||||||
SelectOption, SelectOptionCellDataParser, SelectTypeOptionSharedAction, SingleSelectTypeOption,
|
SelectOptionCellDataParser, SelectTypeOptionSharedAction, SingleSelectTypeOption, TypeOption,
|
||||||
TypeOption,
|
|
||||||
};
|
};
|
||||||
use crate::services::group::action::GroupCustomize;
|
use crate::services::group::action::GroupCustomize;
|
||||||
use crate::services::group::controller::BaseGroupController;
|
use crate::services::group::controller::BaseGroupController;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::Field;
|
use collab_database::fields::Field;
|
||||||
use collab_database::rows::{Cell, Row, RowDetail};
|
use collab_database::rows::{Cell, Row, RowDetail};
|
||||||
|
|
||||||
@ -8,7 +9,7 @@ use crate::entities::{
|
|||||||
use crate::services::cell::{
|
use crate::services::cell::{
|
||||||
insert_checkbox_cell, insert_date_cell, insert_select_option_cell, insert_url_cell,
|
insert_checkbox_cell, insert_date_cell, insert_select_option_cell, insert_url_cell,
|
||||||
};
|
};
|
||||||
use crate::services::field::{SelectOption, SelectOptionIds, CHECK};
|
use crate::services::field::{SelectOptionIds, CHECK};
|
||||||
use crate::services::group::{Group, GroupData, MoveGroupRowContext};
|
use crate::services::group::{Group, GroupData, MoveGroupRowContext};
|
||||||
|
|
||||||
pub fn add_or_remove_select_option_row(
|
pub fn add_or_remove_select_option_row(
|
||||||
@ -30,7 +31,7 @@ pub fn add_or_remove_select_option_row(
|
|||||||
if !group.contains_row(&row_detail.row.id) {
|
if !group.contains_row(&row_detail.row.id) {
|
||||||
changeset
|
changeset
|
||||||
.inserted_rows
|
.inserted_rows
|
||||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||||
group.add_row(row_detail.clone());
|
group.add_row(row_detail.clone());
|
||||||
}
|
}
|
||||||
} else if group.contains_row(&row_detail.row.id) {
|
} else if group.contains_row(&row_detail.row.id) {
|
||||||
|
@ -57,7 +57,10 @@ impl GroupCustomize for URLGroupController {
|
|||||||
let cell_data: URLCellData = _cell_data.clone().into();
|
let cell_data: URLCellData = _cell_data.clone().into();
|
||||||
let group = Group::new(cell_data.data);
|
let group = Group::new(cell_data.data);
|
||||||
let mut new_group = self.context.add_new_group(group)?;
|
let mut new_group = self.context.add_new_group(group)?;
|
||||||
new_group.group.rows.push(RowMetaPB::from(_row_detail));
|
new_group
|
||||||
|
.group
|
||||||
|
.rows
|
||||||
|
.push(RowMetaPB::from(_row_detail.clone()));
|
||||||
inserted_group = Some(new_group);
|
inserted_group = Some(new_group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +101,7 @@ impl GroupCustomize for URLGroupController {
|
|||||||
if !group.contains_row(&row_detail.row.id) {
|
if !group.contains_row(&row_detail.row.id) {
|
||||||
changeset
|
changeset
|
||||||
.inserted_rows
|
.inserted_rows
|
||||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||||
group.add_row(row_detail.clone());
|
group.add_row(row_detail.clone());
|
||||||
}
|
}
|
||||||
} else if group.contains_row(&row_detail.row.id) {
|
} else if group.contains_row(&row_detail.row.id) {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use collab_database::database::{gen_database_id, gen_row_id, timestamp};
|
use collab_database::database::{gen_database_id, gen_row_id, timestamp};
|
||||||
use collab_database::entity::{CreateDatabaseParams, CreateViewParams};
|
use collab_database::entity::{
|
||||||
|
CreateDatabaseParams, CreateViewParams, SelectOption, SelectOptionColor,
|
||||||
|
};
|
||||||
use collab_database::rows::CreateRowParams;
|
use collab_database::rows::CreateRowParams;
|
||||||
use collab_database::views::{DatabaseLayout, LayoutSettings};
|
use collab_database::views::{DatabaseLayout, LayoutSettings};
|
||||||
|
|
||||||
use crate::entities::FieldType;
|
use crate::entities::FieldType;
|
||||||
use crate::services::cell::{insert_select_option_cell, insert_text_cell};
|
use crate::services::cell::{insert_select_option_cell, insert_text_cell};
|
||||||
use crate::services::field::{
|
use crate::services::field::{FieldBuilder, SingleSelectTypeOption};
|
||||||
FieldBuilder, SelectOption, SelectOptionColor, SingleSelectTypeOption,
|
|
||||||
};
|
|
||||||
use crate::services::field_settings::default_field_settings_for_fields;
|
use crate::services::field_settings::default_field_settings_for_fields;
|
||||||
use crate::services::setting::{BoardLayoutSetting, CalendarLayoutSetting};
|
use crate::services::setting::{BoardLayoutSetting, CalendarLayoutSetting};
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use collab_database::database::gen_database_view_id;
|
use collab_database::database::gen_database_view_id;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::Field;
|
use collab_database::fields::Field;
|
||||||
use collab_database::rows::{RowDetail, RowId};
|
use collab_database::rows::{RowDetail, RowId};
|
||||||
use lib_infra::box_any::BoxAny;
|
use lib_infra::box_any::BoxAny;
|
||||||
@ -16,8 +17,7 @@ use flowy_database2::services::field::checklist_type_option::{
|
|||||||
ChecklistCellChangeset, ChecklistTypeOption,
|
ChecklistCellChangeset, ChecklistTypeOption,
|
||||||
};
|
};
|
||||||
use flowy_database2::services::field::{
|
use flowy_database2::services::field::{
|
||||||
CheckboxTypeOption, MultiSelectTypeOption, SelectOption, SelectOptionCellChangeset,
|
CheckboxTypeOption, MultiSelectTypeOption, SelectOptionCellChangeset, SingleSelectTypeOption,
|
||||||
SingleSelectTypeOption,
|
|
||||||
};
|
};
|
||||||
use flowy_database2::services::share::csv::{CSVFormat, ImportResult};
|
use flowy_database2::services::share::csv::{CSVFormat, ImportResult};
|
||||||
use flowy_error::FlowyResult;
|
use flowy_error::FlowyResult;
|
||||||
@ -86,7 +86,7 @@ impl DatabaseEditorTest {
|
|||||||
.map(Arc::new)
|
.map(Arc::new)
|
||||||
.collect();
|
.collect();
|
||||||
let rows = editor
|
let rows = editor
|
||||||
.get_row_details(&test.child_view.id)
|
.get_all_row_details(&test.child_view.id)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -109,7 +109,11 @@ impl DatabaseEditorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_rows(&self) -> Vec<Arc<RowDetail>> {
|
pub async fn get_rows(&self) -> Vec<Arc<RowDetail>> {
|
||||||
self.editor.get_row_details(&self.view_id).await.unwrap()
|
self
|
||||||
|
.editor
|
||||||
|
.get_all_row_details(&self.view_id)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_field(&self, field_id: &str, field_type: FieldType) -> Field {
|
pub async fn get_field(&self, field_id: &str, field_type: FieldType) -> Field {
|
||||||
|
@ -16,6 +16,7 @@ pub enum FieldScript {
|
|||||||
field: Field,
|
field: Field,
|
||||||
},
|
},
|
||||||
SwitchToField {
|
SwitchToField {
|
||||||
|
view_id: String,
|
||||||
field_id: String,
|
field_id: String,
|
||||||
new_field_type: FieldType,
|
new_field_type: FieldType,
|
||||||
},
|
},
|
||||||
@ -80,13 +81,14 @@ impl DatabaseFieldTest {
|
|||||||
assert_eq!(self.field_count, fields.len());
|
assert_eq!(self.field_count, fields.len());
|
||||||
},
|
},
|
||||||
FieldScript::SwitchToField {
|
FieldScript::SwitchToField {
|
||||||
|
view_id,
|
||||||
field_id,
|
field_id,
|
||||||
new_field_type,
|
new_field_type,
|
||||||
} => {
|
} => {
|
||||||
//
|
//
|
||||||
self
|
self
|
||||||
.editor
|
.editor
|
||||||
.switch_to_field_type(&field_id, new_field_type)
|
.switch_to_field_type(&view_id, &field_id, new_field_type)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
@ -121,7 +123,11 @@ impl DatabaseFieldTest {
|
|||||||
} => {
|
} => {
|
||||||
let field = self.editor.get_field(&field_id).await.unwrap();
|
let field = self.editor.get_field(&field_id).await.unwrap();
|
||||||
|
|
||||||
let rows = self.editor.get_row_details(&self.view_id()).await.unwrap();
|
let rows = self
|
||||||
|
.editor
|
||||||
|
.get_all_row_details(&self.view_id())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
let row_detail = rows.get(row_index).unwrap();
|
let row_detail = rows.get(row_index).unwrap();
|
||||||
|
|
||||||
let cell = row_detail.row.cells.get(&field_id).unwrap().clone();
|
let cell = row_detail.row.cells.get(&field_id).unwrap().clone();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use collab_database::database::gen_option_id;
|
use collab_database::database::gen_option_id;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
use flowy_database2::entities::{FieldChangesetParams, FieldType};
|
use flowy_database2::entities::{FieldChangesetParams, FieldType};
|
||||||
use flowy_database2::services::field::{SelectOption, SingleSelectTypeOption, CHECK, UNCHECK};
|
use flowy_database2::services::field::{SingleSelectTypeOption, CHECK, UNCHECK};
|
||||||
|
|
||||||
use crate::database::field_test::script::DatabaseFieldTest;
|
use crate::database::field_test::script::DatabaseFieldTest;
|
||||||
use crate::database::field_test::script::FieldScript::*;
|
use crate::database::field_test::script::FieldScript::*;
|
||||||
@ -122,6 +122,7 @@ async fn grid_delete_field() {
|
|||||||
async fn grid_switch_from_select_option_to_checkbox_test() {
|
async fn grid_switch_from_select_option_to_checkbox_test() {
|
||||||
let mut test = DatabaseFieldTest::new().await;
|
let mut test = DatabaseFieldTest::new().await;
|
||||||
let field = test.get_first_field(FieldType::SingleSelect).await;
|
let field = test.get_first_field(FieldType::SingleSelect).await;
|
||||||
|
let view_id = test.view_id();
|
||||||
|
|
||||||
// Update the type option data of single select option
|
// Update the type option data of single select option
|
||||||
let mut options = test.get_single_select_type_option(&field.id).await;
|
let mut options = test.get_single_select_type_option(&field.id).await;
|
||||||
@ -149,6 +150,7 @@ async fn grid_switch_from_select_option_to_checkbox_test() {
|
|||||||
.into(),
|
.into(),
|
||||||
},
|
},
|
||||||
SwitchToField {
|
SwitchToField {
|
||||||
|
view_id: view_id.clone(),
|
||||||
field_id: field.id.clone(),
|
field_id: field.id.clone(),
|
||||||
new_field_type: FieldType::Checkbox,
|
new_field_type: FieldType::Checkbox,
|
||||||
},
|
},
|
||||||
@ -163,6 +165,7 @@ async fn grid_switch_from_checkbox_to_select_option_test() {
|
|||||||
let scripts = vec![
|
let scripts = vec![
|
||||||
// switch to single-select field type
|
// switch to single-select field type
|
||||||
SwitchToField {
|
SwitchToField {
|
||||||
|
view_id: test.view_id(),
|
||||||
field_id: checkbox_field.id.clone(),
|
field_id: checkbox_field.id.clone(),
|
||||||
new_field_type: FieldType::SingleSelect,
|
new_field_type: FieldType::SingleSelect,
|
||||||
},
|
},
|
||||||
@ -199,6 +202,7 @@ async fn grid_switch_from_multi_select_to_text_test() {
|
|||||||
let multi_select_type_option = test.get_multi_select_type_option(&field_rev.id).await;
|
let multi_select_type_option = test.get_multi_select_type_option(&field_rev.id).await;
|
||||||
|
|
||||||
let script_switch_field = vec![SwitchToField {
|
let script_switch_field = vec![SwitchToField {
|
||||||
|
view_id: test.view_id(),
|
||||||
field_id: field_rev.id.clone(),
|
field_id: field_rev.id.clone(),
|
||||||
new_field_type: FieldType::RichText,
|
new_field_type: FieldType::RichText,
|
||||||
}];
|
}];
|
||||||
@ -229,6 +233,7 @@ async fn grid_switch_from_checkbox_to_text_test() {
|
|||||||
|
|
||||||
let scripts = vec![
|
let scripts = vec![
|
||||||
SwitchToField {
|
SwitchToField {
|
||||||
|
view_id: test.view_id(),
|
||||||
field_id: field_rev.id.clone(),
|
field_id: field_rev.id.clone(),
|
||||||
new_field_type: FieldType::RichText,
|
new_field_type: FieldType::RichText,
|
||||||
},
|
},
|
||||||
@ -255,6 +260,7 @@ async fn grid_switch_from_date_to_text_test() {
|
|||||||
let field = test.get_first_field(FieldType::DateTime).await.clone();
|
let field = test.get_first_field(FieldType::DateTime).await.clone();
|
||||||
let scripts = vec![
|
let scripts = vec![
|
||||||
SwitchToField {
|
SwitchToField {
|
||||||
|
view_id: test.view_id(),
|
||||||
field_id: field.id.clone(),
|
field_id: field.id.clone(),
|
||||||
new_field_type: FieldType::RichText,
|
new_field_type: FieldType::RichText,
|
||||||
},
|
},
|
||||||
@ -282,6 +288,7 @@ async fn grid_switch_from_number_to_text_test() {
|
|||||||
|
|
||||||
let scripts = vec![
|
let scripts = vec![
|
||||||
SwitchToField {
|
SwitchToField {
|
||||||
|
view_id: test.view_id(),
|
||||||
field_id: field.id.clone(),
|
field_id: field.id.clone(),
|
||||||
new_field_type: FieldType::RichText,
|
new_field_type: FieldType::RichText,
|
||||||
},
|
},
|
||||||
@ -308,6 +315,7 @@ async fn grid_switch_from_checklist_to_text_test() {
|
|||||||
|
|
||||||
let scripts = vec![
|
let scripts = vec![
|
||||||
SwitchToField {
|
SwitchToField {
|
||||||
|
view_id: test.view_id(),
|
||||||
field_id: field_rev.id.clone(),
|
field_id: field_rev.id.clone(),
|
||||||
new_field_type: FieldType::RichText,
|
new_field_type: FieldType::RichText,
|
||||||
},
|
},
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::Field;
|
use collab_database::fields::Field;
|
||||||
use collab_database::views::OrderObjectPosition;
|
use collab_database::views::OrderObjectPosition;
|
||||||
|
|
||||||
use flowy_database2::entities::{CreateFieldParams, FieldType};
|
use flowy_database2::entities::{CreateFieldParams, FieldType};
|
||||||
use flowy_database2::services::field::{
|
use flowy_database2::services::field::{
|
||||||
type_option_to_pb, DateFormat, DateTypeOption, FieldBuilder, RichTextTypeOption, SelectOption,
|
type_option_to_pb, DateFormat, DateTypeOption, FieldBuilder, RichTextTypeOption,
|
||||||
SingleSelectTypeOption, TimeFormat, TimeTypeOption, TimestampTypeOption,
|
SingleSelectTypeOption, TimeFormat, TimeTypeOption, TimestampTypeOption,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ impl DatabaseFilterTest {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
FilterScript::AssertNumberOfVisibleRows { expected } => {
|
FilterScript::AssertNumberOfVisibleRows { expected } => {
|
||||||
let grid = self.editor.get_database_data(&self.view_id).await.unwrap();
|
let grid = self.editor.open_database(&self.view_id).await.unwrap();
|
||||||
assert_eq!(grid.rows.len(), expected);
|
assert_eq!(grid.rows.len(), expected);
|
||||||
},
|
},
|
||||||
FilterScript::Wait { millisecond } => {
|
FilterScript::Wait { millisecond } => {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use collab_database::entity::SelectOption;
|
||||||
use collab_database::fields::Field;
|
use collab_database::fields::Field;
|
||||||
use collab_database::rows::RowId;
|
use collab_database::rows::RowId;
|
||||||
|
|
||||||
@ -6,8 +7,7 @@ use flowy_database2::services::cell::{
|
|||||||
delete_select_option_cell, insert_date_cell, insert_select_option_cell, insert_url_cell,
|
delete_select_option_cell, insert_date_cell, insert_select_option_cell, insert_url_cell,
|
||||||
};
|
};
|
||||||
use flowy_database2::services::field::{
|
use flowy_database2::services::field::{
|
||||||
edit_single_select_type_option, SelectOption, SelectTypeOptionSharedAction,
|
edit_single_select_type_option, SelectTypeOptionSharedAction, SingleSelectTypeOption,
|
||||||
SingleSelectTypeOption,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::database::database_editor::DatabaseEditorTest;
|
use crate::database::database_editor::DatabaseEditorTest;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use flowy_database2::services::field::SelectOption;
|
|
||||||
|
|
||||||
use crate::database::group_test::script::DatabaseGroupTest;
|
use crate::database::group_test::script::DatabaseGroupTest;
|
||||||
use crate::database::group_test::script::GroupScript::*;
|
use crate::database::group_test::script::GroupScript::*;
|
||||||
|
use collab_database::entity::SelectOption;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn group_init_test() {
|
async fn group_init_test() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use collab_database::database::{gen_database_id, gen_database_view_id, gen_row_id, DatabaseData};
|
use collab_database::database::{gen_database_id, gen_database_view_id, gen_row_id, DatabaseData};
|
||||||
use collab_database::entity::DatabaseView;
|
use collab_database::entity::{DatabaseView, SelectOption, SelectOptionColor};
|
||||||
use collab_database::views::{DatabaseLayout, LayoutSetting, LayoutSettings};
|
use collab_database::views::{DatabaseLayout, LayoutSetting, LayoutSettings};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ use flowy_database2::services::field::checklist_type_option::ChecklistTypeOption
|
|||||||
use flowy_database2::services::field::summary_type_option::summary::SummarizationTypeOption;
|
use flowy_database2::services::field::summary_type_option::summary::SummarizationTypeOption;
|
||||||
use flowy_database2::services::field::{
|
use flowy_database2::services::field::{
|
||||||
DateFormat, DateTypeOption, FieldBuilder, MultiSelectTypeOption, RelationTypeOption,
|
DateFormat, DateTypeOption, FieldBuilder, MultiSelectTypeOption, RelationTypeOption,
|
||||||
SelectOption, SelectOptionColor, SingleSelectTypeOption, TimeFormat, TimestampTypeOption,
|
SingleSelectTypeOption, TimeFormat, TimestampTypeOption,
|
||||||
};
|
};
|
||||||
use flowy_database2::services::field_settings::default_field_settings_for_fields;
|
use flowy_database2::services::field_settings::default_field_settings_for_fields;
|
||||||
use flowy_database2::services::setting::BoardLayoutSetting;
|
use flowy_database2::services::setting::BoardLayoutSetting;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use collab_database::database::{gen_database_id, gen_database_view_id, gen_row_id, DatabaseData};
|
use collab_database::database::{gen_database_id, gen_database_view_id, gen_row_id, DatabaseData};
|
||||||
use collab_database::entity::DatabaseView;
|
use collab_database::entity::{DatabaseView, SelectOption, SelectOptionColor};
|
||||||
use collab_database::views::DatabaseLayout;
|
use collab_database::views::DatabaseLayout;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
@ -10,8 +10,8 @@ use flowy_database2::services::field::summary_type_option::summary::Summarizatio
|
|||||||
use flowy_database2::services::field::translate_type_option::translate::TranslateTypeOption;
|
use flowy_database2::services::field::translate_type_option::translate::TranslateTypeOption;
|
||||||
use flowy_database2::services::field::{
|
use flowy_database2::services::field::{
|
||||||
ChecklistTypeOption, DateFormat, DateTypeOption, FieldBuilder, MultiSelectTypeOption,
|
ChecklistTypeOption, DateFormat, DateTypeOption, FieldBuilder, MultiSelectTypeOption,
|
||||||
NumberFormat, NumberTypeOption, RelationTypeOption, SelectOption, SelectOptionColor,
|
NumberFormat, NumberTypeOption, RelationTypeOption, SingleSelectTypeOption, TimeFormat,
|
||||||
SingleSelectTypeOption, TimeFormat, TimeTypeOption, TimestampTypeOption,
|
TimeTypeOption, TimestampTypeOption,
|
||||||
};
|
};
|
||||||
use flowy_database2::services::field_settings::default_field_settings_for_fields;
|
use flowy_database2::services::field_settings::default_field_settings_for_fields;
|
||||||
|
|
||||||
|
@ -86,7 +86,11 @@ impl DatabasePreFillRowCellTest {
|
|||||||
.await
|
.await
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
PreFillRowCellTestScript::AssertRowCount(expected_row_count) => {
|
PreFillRowCellTestScript::AssertRowCount(expected_row_count) => {
|
||||||
let rows = self.editor.get_row_details(&self.view_id).await.unwrap();
|
let rows = self
|
||||||
|
.editor
|
||||||
|
.get_all_row_details(&self.view_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
assert_eq!(expected_row_count, rows.len());
|
assert_eq!(expected_row_count, rows.len());
|
||||||
},
|
},
|
||||||
PreFillRowCellTestScript::AssertCellExistence {
|
PreFillRowCellTestScript::AssertCellExistence {
|
||||||
@ -94,7 +98,11 @@ impl DatabasePreFillRowCellTest {
|
|||||||
row_index,
|
row_index,
|
||||||
exists,
|
exists,
|
||||||
} => {
|
} => {
|
||||||
let rows = self.editor.get_row_details(&self.view_id).await.unwrap();
|
let rows = self
|
||||||
|
.editor
|
||||||
|
.get_all_row_details(&self.view_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
let row_detail = rows.get(row_index).unwrap();
|
let row_detail = rows.get(row_index).unwrap();
|
||||||
|
|
||||||
let cell = row_detail.row.cells.get(&field_id).cloned();
|
let cell = row_detail.row.cells.get(&field_id).cloned();
|
||||||
@ -108,7 +116,11 @@ impl DatabasePreFillRowCellTest {
|
|||||||
} => {
|
} => {
|
||||||
let field = self.editor.get_field(&field_id).await.unwrap();
|
let field = self.editor.get_field(&field_id).await.unwrap();
|
||||||
|
|
||||||
let rows = self.editor.get_row_details(&self.view_id).await.unwrap();
|
let rows = self
|
||||||
|
.editor
|
||||||
|
.get_all_row_details(&self.view_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
let row_detail = rows.get(row_index).unwrap();
|
let row_detail = rows.get(row_index).unwrap();
|
||||||
|
|
||||||
let cell = row_detail
|
let cell = row_detail
|
||||||
@ -125,7 +137,11 @@ impl DatabasePreFillRowCellTest {
|
|||||||
row_index,
|
row_index,
|
||||||
expected_content,
|
expected_content,
|
||||||
} => {
|
} => {
|
||||||
let rows = self.editor.get_row_details(&self.view_id).await.unwrap();
|
let rows = self
|
||||||
|
.editor
|
||||||
|
.get_all_row_details(&self.view_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
let row_detail = rows.get(row_index).unwrap();
|
let row_detail = rows.get(row_index).unwrap();
|
||||||
|
|
||||||
let cell = row_detail
|
let cell = row_detail
|
||||||
|
@ -33,7 +33,7 @@ async fn export_and_then_import_meta_csv_test() {
|
|||||||
let database = test.get_database(&result.database_id).await.unwrap();
|
let database = test.get_database(&result.database_id).await.unwrap();
|
||||||
|
|
||||||
let fields = database.get_fields(&result.view_id, None).await;
|
let fields = database.get_fields(&result.view_id, None).await;
|
||||||
let rows = database.get_row_details(&result.view_id).await.unwrap();
|
let rows = database.get_all_row_details(&result.view_id).await.unwrap();
|
||||||
assert_eq!(fields[0].field_type, 0);
|
assert_eq!(fields[0].field_type, 0);
|
||||||
assert_eq!(fields[1].field_type, 1);
|
assert_eq!(fields[1].field_type, 1);
|
||||||
assert_eq!(fields[2].field_type, 2);
|
assert_eq!(fields[2].field_type, 2);
|
||||||
@ -112,7 +112,7 @@ async fn history_database_import_test() {
|
|||||||
let database = test.get_database(&result.database_id).await.unwrap();
|
let database = test.get_database(&result.database_id).await.unwrap();
|
||||||
|
|
||||||
let fields = database.get_fields(&result.view_id, None).await;
|
let fields = database.get_fields(&result.view_id, None).await;
|
||||||
let rows = database.get_row_details(&result.view_id).await.unwrap();
|
let rows = database.get_all_row_details(&result.view_id).await.unwrap();
|
||||||
assert_eq!(fields[0].field_type, 0);
|
assert_eq!(fields[0].field_type, 0);
|
||||||
assert_eq!(fields[1].field_type, 1);
|
assert_eq!(fields[1].field_type, 1);
|
||||||
assert_eq!(fields[2].field_type, 2);
|
assert_eq!(fields[2].field_type, 2);
|
||||||
|
@ -117,7 +117,11 @@ impl DatabaseSortTest {
|
|||||||
},
|
},
|
||||||
SortScript::AssertCellContentOrder { field_id, orders } => {
|
SortScript::AssertCellContentOrder { field_id, orders } => {
|
||||||
let mut cells = vec![];
|
let mut cells = vec![];
|
||||||
let rows = self.editor.get_row_details(&self.view_id).await.unwrap();
|
let rows = self
|
||||||
|
.editor
|
||||||
|
.get_all_row_details(&self.view_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
let field = self.editor.get_field(&field_id).await.unwrap();
|
let field = self.editor.get_field(&field_id).await.unwrap();
|
||||||
for row_detail in rows {
|
for row_detail in rows {
|
||||||
if let Some(cell) = row_detail.row.cells.get(&field_id) {
|
if let Some(cell) = row_detail.row.cells.get(&field_id) {
|
||||||
|
Loading…
Reference in New Issue
Block a user