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) {
|
||||
_cellMemCache.removeCellWithFieldId(fieldInfo.id);
|
||||
}
|
||||
_changedNotifier.receive(const ChangedReason.fieldDidChange());
|
||||
|
||||
_changedNotifier?.receive(const ChangedReason.fieldDidChange());
|
||||
});
|
||||
}
|
||||
|
||||
@ -53,7 +54,7 @@ class RowCache {
|
||||
final CellMemCache _cellMemCache;
|
||||
final RowLifeCycle _rowLifeCycle;
|
||||
final RowFieldsDelegate _fieldDelegate;
|
||||
final RowChangesetNotifier _changedNotifier;
|
||||
RowChangesetNotifier? _changedNotifier;
|
||||
|
||||
/// Returns a unmodifiable list of RowInfo
|
||||
UnmodifiableListView<RowInfo> get rowInfos {
|
||||
@ -67,7 +68,8 @@ class RowCache {
|
||||
}
|
||||
|
||||
CellMemCache get cellCache => _cellMemCache;
|
||||
ChangedReason get changeReason => _changedNotifier.reason;
|
||||
ChangedReason get changeReason =>
|
||||
_changedNotifier?.reason ?? const InitialListState();
|
||||
|
||||
RowInfo? getRow(RowId rowId) {
|
||||
return _rowList.get(rowId);
|
||||
@ -78,18 +80,19 @@ class RowCache {
|
||||
final rowInfo = buildGridRow(row);
|
||||
_rowList.add(rowInfo);
|
||||
}
|
||||
_changedNotifier.receive(const ChangedReason.setInitialRows());
|
||||
_changedNotifier?.receive(const ChangedReason.setInitialRows());
|
||||
}
|
||||
|
||||
void setRowMeta(RowMetaPB rowMeta) {
|
||||
final rowInfo = buildGridRow(rowMeta);
|
||||
_rowList.add(rowInfo);
|
||||
_changedNotifier.receive(const ChangedReason.didFetchRow());
|
||||
_changedNotifier?.receive(const ChangedReason.didFetchRow());
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_rowLifeCycle.onRowDisposed();
|
||||
_changedNotifier.dispose();
|
||||
_changedNotifier?.dispose();
|
||||
_changedNotifier = null;
|
||||
_cellMemCache.dispose();
|
||||
}
|
||||
|
||||
@ -106,7 +109,7 @@ class RowCache {
|
||||
|
||||
void reorderAllRows(List<String> rowIds) {
|
||||
_rowList.reorderWithRowIds(rowIds);
|
||||
_changedNotifier.receive(const ChangedReason.reorderRows());
|
||||
_changedNotifier?.receive(const ChangedReason.reorderRows());
|
||||
}
|
||||
|
||||
void reorderSingleRow(ReorderSingleRowPB reorderRow) {
|
||||
@ -117,7 +120,7 @@ class RowCache {
|
||||
reorderRow.oldIndex,
|
||||
reorderRow.newIndex,
|
||||
);
|
||||
_changedNotifier.receive(
|
||||
_changedNotifier?.receive(
|
||||
ChangedReason.reorderSingleRow(
|
||||
reorderRow,
|
||||
rowInfo,
|
||||
@ -130,7 +133,7 @@ class RowCache {
|
||||
for (final rowId in deletedRowIds) {
|
||||
final deletedRow = _rowList.remove(rowId);
|
||||
if (deletedRow != null) {
|
||||
_changedNotifier.receive(ChangedReason.delete(deletedRow));
|
||||
_changedNotifier?.receive(ChangedReason.delete(deletedRow));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,7 +143,7 @@ class RowCache {
|
||||
final insertedIndex =
|
||||
_rowList.insert(insertedRow.index, buildGridRow(insertedRow.rowMeta));
|
||||
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));
|
||||
|
||||
if (updatedIndexs.isNotEmpty) {
|
||||
_changedNotifier.receive(ChangedReason.update(updatedIndexs));
|
||||
_changedNotifier?.receive(ChangedReason.update(updatedIndexs));
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,7 +176,7 @@ class RowCache {
|
||||
for (final rowId in invisibleRows) {
|
||||
final deletedRow = _rowList.remove(rowId);
|
||||
if (deletedRow != null) {
|
||||
_changedNotifier.receive(ChangedReason.delete(deletedRow));
|
||||
_changedNotifier?.receive(ChangedReason.delete(deletedRow));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -183,14 +186,16 @@ class RowCache {
|
||||
final insertedIndex =
|
||||
_rowList.insert(insertedRow.index, buildGridRow(insertedRow.rowMeta));
|
||||
if (insertedIndex != null) {
|
||||
_changedNotifier.receive(ChangedReason.insert(insertedIndex));
|
||||
_changedNotifier?.receive(ChangedReason.insert(insertedIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onRowsChanged(void Function(ChangedReason) onRowChanged) {
|
||||
_changedNotifier.addListener(() {
|
||||
onRowChanged(_changedNotifier.reason);
|
||||
_changedNotifier?.addListener(() {
|
||||
if (_changedNotifier != null) {
|
||||
onRowChanged(_changedNotifier!.reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -203,17 +208,19 @@ class RowCache {
|
||||
final rowInfo = _rowList.get(rowId);
|
||||
if (rowInfo != null) {
|
||||
final cellDataMap = _makeCells(rowInfo.rowMeta);
|
||||
onRowChanged(cellDataMap, _changedNotifier.reason);
|
||||
if (_changedNotifier != null) {
|
||||
onRowChanged(cellDataMap, _changedNotifier!.reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_changedNotifier.addListener(listenerHandler);
|
||||
_changedNotifier?.addListener(listenerHandler);
|
||||
return listenerHandler;
|
||||
}
|
||||
|
||||
void removeRowListener(VoidCallback callback) {
|
||||
_changedNotifier.removeListener(callback);
|
||||
_changedNotifier?.removeListener(callback);
|
||||
}
|
||||
|
||||
List<CellContext> loadCells(RowMetaPB rowMeta) {
|
||||
@ -242,7 +249,7 @@ class RowCache {
|
||||
rowId: rowMetaPB.id,
|
||||
);
|
||||
|
||||
_changedNotifier.receive(ChangedReason.update(updatedIndexs));
|
||||
_changedNotifier?.receive(ChangedReason.update(updatedIndexs));
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
|
@ -18,19 +18,7 @@ class RowController {
|
||||
}) : _rowMeta = rowMeta,
|
||||
_rowCache = rowCache,
|
||||
_rowBackendSvc = RowBackendService(viewId: viewId),
|
||||
_rowListener = RowListener(rowMeta.id) {
|
||||
_rowBackendSvc.initRow(rowMeta.id);
|
||||
_rowListener.start(
|
||||
onMetaChanged: (newRowMeta) {
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
_rowMeta = newRowMeta;
|
||||
_rowCache.setRowMeta(newRowMeta);
|
||||
_onRowMetaChanged?.call();
|
||||
},
|
||||
);
|
||||
}
|
||||
_rowListener = RowListener(rowMeta.id);
|
||||
|
||||
RowMetaPB _rowMeta;
|
||||
final String? groupId;
|
||||
@ -42,13 +30,26 @@ class RowController {
|
||||
final RowBackendService _rowBackendSvc;
|
||||
bool _isDisposed = false;
|
||||
|
||||
CellMemCache get cellCache => _rowCache.cellCache;
|
||||
|
||||
String get rowId => rowMeta.id;
|
||||
RowMetaPB get rowMeta => _rowMeta;
|
||||
CellMemCache get cellCache => _rowCache.cellCache;
|
||||
|
||||
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({
|
||||
OnRowChanged? onRowChanged,
|
||||
VoidCallback? onMetaChanged,
|
||||
|
@ -2,9 +2,7 @@ import 'dart:async';
|
||||
import 'dart:collection';
|
||||
|
||||
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/protobuf/flowy-database2/protobuf.dart';
|
||||
|
||||
import '../defines.dart';
|
||||
import '../field/field_controller.dart';
|
||||
@ -93,17 +91,6 @@ class DatabaseViewCache {
|
||||
(reorderRow) => _rowCache.reorderSingleRow(reorderRow),
|
||||
(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(
|
||||
|
@ -32,7 +32,6 @@ class DatabaseViewListener {
|
||||
required ReorderAllRowsCallback onReorderAllRows,
|
||||
required SingleRowCallback onReorderSingleRow,
|
||||
required RowsVisibilityCallback onRowsVisibilityChanged,
|
||||
required void Function() onReloadRows,
|
||||
}) {
|
||||
// Stop any existing listener
|
||||
_listener?.stop();
|
||||
@ -47,7 +46,6 @@ class DatabaseViewListener {
|
||||
onReorderAllRows,
|
||||
onReorderSingleRow,
|
||||
onRowsVisibilityChanged,
|
||||
onReloadRows,
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -59,7 +57,6 @@ class DatabaseViewListener {
|
||||
ReorderAllRowsCallback onReorderAllRows,
|
||||
SingleRowCallback onReorderSingleRow,
|
||||
RowsVisibilityCallback onRowsVisibilityChanged,
|
||||
void Function() onReloadRows,
|
||||
) {
|
||||
switch (ty) {
|
||||
case DatabaseNotification.DidUpdateViewRowsVisibility:
|
||||
@ -94,9 +91,6 @@ class DatabaseViewListener {
|
||||
(error) => onReorderSingleRow(FlowyResult.failure(error)),
|
||||
);
|
||||
break;
|
||||
case DatabaseNotification.ReloadRows:
|
||||
onReloadRows();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
|
||||
_dispatch();
|
||||
_startListening();
|
||||
_init();
|
||||
rowController.initialize();
|
||||
}
|
||||
|
||||
final FieldController fieldController;
|
||||
|
@ -342,7 +342,7 @@ class _GridRowsState extends State<_GridRows> {
|
||||
child: ReorderableListView.builder(
|
||||
/// This is a workaround related to
|
||||
/// https://github.com/flutter/flutter/issues/25652
|
||||
cacheExtent: 5000,
|
||||
cacheExtent: 600,
|
||||
scrollController: widget.scrollController.verticalController,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
buildDefaultDragHandles: false,
|
||||
@ -421,7 +421,7 @@ class _GridRowsState extends State<_GridRows> {
|
||||
);
|
||||
|
||||
final child = GridRow(
|
||||
key: ValueKey(rowMeta.id),
|
||||
key: ValueKey(rowId),
|
||||
fieldController: databaseController.fieldController,
|
||||
rowId: rowId,
|
||||
viewId: viewId,
|
||||
|
@ -8,6 +8,7 @@ import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/size.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:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@ -202,9 +203,15 @@ class _URLAccessoryIconContainer extends StatelessWidget {
|
||||
),
|
||||
borderRadius: Corners.s6Border,
|
||||
),
|
||||
child: FlowyHover(
|
||||
style: HoverStyle(
|
||||
backgroundColor: AFThemeExtension.of(context).background,
|
||||
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
||||
),
|
||||
child: Center(
|
||||
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]]
|
||||
name = "collab"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -989,7 +989,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1018,7 +1018,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1038,7 +1038,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -1057,7 +1057,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1100,7 +1100,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1180,7 +1180,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
|
@ -116,13 +116,13 @@ custom-protocol = ["tauri/custom-protocol"]
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { 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 = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
||||
collab-folder = { 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 = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
||||
collab-database = { 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 = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
||||
collab-user = { 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 = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
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 = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
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 = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
|
||||
# Working directory: frontend
|
||||
# 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]]
|
||||
name = "collab"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -972,7 +972,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -1001,7 +1001,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1021,7 +1021,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -1040,7 +1040,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -1083,7 +1083,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1163,7 +1163,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
|
@ -116,13 +116,13 @@ custom-protocol = ["tauri/custom-protocol"]
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { 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 = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
||||
collab-folder = { 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 = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
||||
collab-database = { 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 = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
||||
collab-user = { 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 = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
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 = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
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 = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
|
||||
# Working directory: frontend
|
||||
# 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]]
|
||||
name = "collab"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -850,7 +850,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-database"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@ -879,7 +879,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-document"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -899,7 +899,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-entity"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@ -918,7 +918,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-folder"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@ -961,7 +961,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-plugins"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1041,7 +1041,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collab-user"
|
||||
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 = [
|
||||
"anyhow",
|
||||
"collab",
|
||||
|
@ -136,13 +136,13 @@ rocksdb = { git = "https://github.com/rust-rocksdb/rust-rocksdb", rev = "1710120
|
||||
# To switch to the local path, run:
|
||||
# scripts/tool/update_collab_source.sh
|
||||
# ⚠️⚠️⚠️️
|
||||
collab = { 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 = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
||||
collab-folder = { 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 = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
||||
collab-database = { 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 = "c714b6bd458420663c7a5b29370d6892902e995c" }
|
||||
collab-user = { 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 = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
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 = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
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 = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
collab-user = { version = "0.2", git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "e51cde161cbce9af08f707ab1b3a3564eee90bac" }
|
||||
|
||||
# Working directory: frontend
|
||||
# To update the commit ID, run:
|
||||
|
@ -3,14 +3,13 @@ use std::convert::TryFrom;
|
||||
|
||||
use bytes::Bytes;
|
||||
use collab_database::database::timestamp;
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Row, RowId};
|
||||
use flowy_database2::entities::*;
|
||||
use flowy_database2::event_map::DatabaseEvent;
|
||||
use flowy_database2::services::cell::CellBuilder;
|
||||
use flowy_database2::services::field::{
|
||||
MultiSelectTypeOption, SelectOption, SingleSelectTypeOption,
|
||||
};
|
||||
use flowy_database2::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
|
||||
use flowy_database2::services::share::csv::CSVFormat;
|
||||
use flowy_folder::entities::*;
|
||||
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::entity::DatabaseView;
|
||||
use collab_database::entity::{DatabaseView, SelectOption, SelectOptionColor};
|
||||
use collab_database::views::DatabaseLayout;
|
||||
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::translate_type_option::translate::TranslateTypeOption;
|
||||
use flowy_database2::services::field::{
|
||||
FieldBuilder, NumberFormat, NumberTypeOption, SelectOption, SelectOptionColor,
|
||||
SingleSelectTypeOption,
|
||||
FieldBuilder, NumberFormat, NumberTypeOption, SingleSelectTypeOption,
|
||||
};
|
||||
use flowy_database2::services::field_settings::default_field_settings_for_fields;
|
||||
use strum::IntoEnumIterator;
|
||||
|
@ -245,7 +245,7 @@ async fn get_row_event_test() {
|
||||
assert!(row.is_some());
|
||||
|
||||
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]
|
||||
|
@ -85,5 +85,6 @@ openssl_vendored = ["flowy-sqlite/openssl_vendored"]
|
||||
# Enable/Disable AppFlowy Verbose Log Configuration
|
||||
verbose_log = [
|
||||
"flowy-document/verbose_log",
|
||||
"flowy-database2/verbose_log",
|
||||
"client-api/sync_verbose_log"
|
||||
]
|
||||
|
@ -61,3 +61,4 @@ flowy-codegen.workspace = true
|
||||
[features]
|
||||
dart = ["flowy-codegen/dart", "flowy-notification/dart"]
|
||||
ts = ["flowy-codegen/ts", "flowy-notification/tauri_ts"]
|
||||
verbose_log = ["collab-database/verbose_log"]
|
@ -55,8 +55,8 @@ pub struct RowMetaPB {
|
||||
#[pb(index = 1)]
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub document_id: String,
|
||||
#[pb(index = 2, one_of)]
|
||||
pub document_id: Option<String>,
|
||||
|
||||
#[pb(index = 3, one_of)]
|
||||
pub icon: Option<String>,
|
||||
@ -64,8 +64,8 @@ pub struct RowMetaPB {
|
||||
#[pb(index = 4, one_of)]
|
||||
pub cover: Option<String>,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub is_document_empty: bool,
|
||||
#[pb(index = 5, one_of)]
|
||||
pub is_document_empty: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
@ -74,25 +74,26 @@ pub struct RepeatedRowMetaPB {
|
||||
pub items: Vec<RowMetaPB>,
|
||||
}
|
||||
|
||||
impl std::convert::From<&RowDetail> for RowMetaPB {
|
||||
fn from(row_detail: &RowDetail) -> Self {
|
||||
impl From<RowOrder> for RowMetaPB {
|
||||
fn from(data: RowOrder) -> Self {
|
||||
Self {
|
||||
id: row_detail.row.id.to_string(),
|
||||
document_id: row_detail.document_id.clone(),
|
||||
icon: row_detail.meta.icon_url.clone(),
|
||||
cover: row_detail.meta.cover_url.clone(),
|
||||
is_document_empty: row_detail.meta.is_document_empty,
|
||||
id: data.id.into_inner(),
|
||||
document_id: None,
|
||||
icon: None,
|
||||
cover: None,
|
||||
is_document_empty: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<RowDetail> for RowMetaPB {
|
||||
fn from(row_detail: RowDetail) -> Self {
|
||||
Self {
|
||||
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,
|
||||
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 flowy_derive::ProtoBuf;
|
||||
@ -5,7 +6,6 @@ use flowy_error::{ErrorCode, FlowyError};
|
||||
|
||||
use crate::entities::parser::NotEmptyStr;
|
||||
use crate::entities::SelectOptionPB;
|
||||
use crate::services::field::SelectOption;
|
||||
|
||||
#[derive(Debug, Clone, Default, ProtoBuf)]
|
||||
pub struct ChecklistCellDataPB {
|
||||
|
@ -1,9 +1,8 @@
|
||||
use crate::entities::parser::NotEmptyStr;
|
||||
use crate::entities::{CellIdPB, CellIdParams};
|
||||
use crate::services::field::checklist_type_option::ChecklistTypeOption;
|
||||
use crate::services::field::{
|
||||
MultiSelectTypeOption, SelectOption, SelectOptionColor, SingleSelectTypeOption,
|
||||
};
|
||||
use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
|
||||
use collab_database::entity::{SelectOption, SelectOptionColor};
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
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())
|
||||
.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!(
|
||||
"layout: {:?}, rows: {}, fields: {}",
|
||||
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())
|
||||
.await?;
|
||||
let database_editor = manager.get_database_editor(&database_id).await?;
|
||||
let data = database_editor.get_all_rows(view_id.as_ref()).await?;
|
||||
data_result_ok(data)
|
||||
let row_details = database_editor
|
||||
.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)]
|
||||
pub(crate) async fn open_database_handler(
|
||||
@ -326,7 +332,7 @@ pub(crate) async fn switch_to_field_handler(
|
||||
.await?;
|
||||
let old_field = database_editor.get_field(¶ms.field_id).await;
|
||||
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?;
|
||||
|
||||
if let Some(new_type_option) = database_editor
|
||||
|
@ -307,6 +307,7 @@ impl DatabaseManager {
|
||||
if should_remove {
|
||||
trace!("remove database editor:{}", database_id);
|
||||
if let Some(editor) = editors.remove(&database_id) {
|
||||
editor.close_database().await;
|
||||
self
|
||||
.removing_editor
|
||||
.lock()
|
||||
@ -793,8 +794,8 @@ impl DatabaseCollabService for WorkspaceDatabaseCollabServiceImpl {
|
||||
Ok(collab)
|
||||
}
|
||||
|
||||
fn persistence(&self) -> Option<Box<dyn DatabaseCollabPersistenceService>> {
|
||||
Some(Box::new(DatabasePersistenceImpl {
|
||||
fn persistence(&self) -> Option<Arc<dyn DatabaseCollabPersistenceService>> {
|
||||
Some(Arc::new(DatabasePersistenceImpl {
|
||||
user: self.user.clone(),
|
||||
}))
|
||||
}
|
||||
|
@ -52,7 +52,6 @@ pub enum DatabaseNotification {
|
||||
DidUpdateFieldSettings = 86,
|
||||
// Trigger when Calculation changed
|
||||
DidUpdateCalculation = 87,
|
||||
ReloadRows = 88,
|
||||
}
|
||||
|
||||
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::{
|
||||
DatabaseViewChanged, DatabaseViewOperation, DatabaseViews, EditorByViewId,
|
||||
};
|
||||
use crate::services::field::type_option_transform::transform_type_option;
|
||||
use crate::services::field::{
|
||||
default_type_option_data_from_type, select_type_option_from_field, transform_type_option,
|
||||
type_option_data_from_pb, ChecklistCellChangeset, RelationTypeOption, SelectOptionCellChangeset,
|
||||
StringCellData, TimestampCellData, TimestampCellDataWrapper, TypeOptionCellDataHandler,
|
||||
TypeOptionCellExt,
|
||||
default_type_option_data_from_type, select_type_option_from_field, type_option_data_from_pb,
|
||||
ChecklistCellChangeset, RelationTypeOption, SelectOptionCellChangeset, StringCellData,
|
||||
TimestampCellData, TimestampCellDataWrapper, TypeOptionCellDataHandler, TypeOptionCellExt,
|
||||
};
|
||||
use crate::services::field_settings::{default_field_settings_by_layout_map, FieldSettings};
|
||||
use crate::services::filter::{Filter, FilterChangeset};
|
||||
@ -36,9 +36,9 @@ use lib_infra::util::timestamp;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
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(crate) database: Arc<RwLock<Database>>,
|
||||
pub cell_cache: CellCache,
|
||||
@ -48,6 +48,7 @@ pub struct DatabaseEditor {
|
||||
notification_sender: Arc<DebounceNotificationSender>,
|
||||
user: Arc<dyn DatabaseUser>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
database_cancellation: Arc<RwLock<Option<CancellationToken>>>,
|
||||
}
|
||||
|
||||
impl DatabaseEditor {
|
||||
@ -60,6 +61,7 @@ impl DatabaseEditor {
|
||||
let notification_sender = Arc::new(DebounceNotificationSender::new(200));
|
||||
let cell_cache = AnyTypeCache::<u64>::new();
|
||||
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
|
||||
observe_sync_state(&database_id, &database).await;
|
||||
// observe_view_change(&database_id, &database).await;
|
||||
@ -73,6 +75,7 @@ impl DatabaseEditor {
|
||||
task_scheduler: task_scheduler.clone(),
|
||||
cell_cache: cell_cache.clone(),
|
||||
editor_by_view_id: editor_by_view_id.clone(),
|
||||
database_cancellation: database_cancellation.clone(),
|
||||
});
|
||||
|
||||
let database_views = Arc::new(
|
||||
@ -104,6 +107,7 @@ impl DatabaseEditor {
|
||||
database_views,
|
||||
notification_sender,
|
||||
collab_builder,
|
||||
database_cancellation,
|
||||
});
|
||||
observe_block_event(&database_id, &this).await;
|
||||
Ok(this)
|
||||
@ -419,6 +423,7 @@ impl DatabaseEditor {
|
||||
|
||||
pub async fn switch_to_field_type(
|
||||
&self,
|
||||
view_id: &str,
|
||||
field_id: &str,
|
||||
new_field_type: FieldType,
|
||||
) -> FlowyResult<()> {
|
||||
@ -441,11 +446,16 @@ impl DatabaseEditor {
|
||||
.unwrap_or_else(|| default_type_option_data_from_type(new_field_type));
|
||||
|
||||
let transformed_type_option = transform_type_option(
|
||||
view_id,
|
||||
field_id,
|
||||
old_field_type,
|
||||
new_field_type,
|
||||
old_type_option_data,
|
||||
new_type_option_data,
|
||||
);
|
||||
&database,
|
||||
)
|
||||
.await;
|
||||
|
||||
database.update_field(field_id, |update| {
|
||||
update
|
||||
.set_field_type(new_field_type.into())
|
||||
@ -667,9 +677,9 @@ impl DatabaseEditor {
|
||||
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?;
|
||||
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> {
|
||||
@ -731,10 +741,10 @@ impl DatabaseEditor {
|
||||
let row_document_id = database.get_row_document_id(row_id)?;
|
||||
Some(RowMetaPB {
|
||||
id: row_id.clone().into_inner(),
|
||||
document_id: row_document_id,
|
||||
document_id: Some(row_document_id),
|
||||
icon: row_meta.icon_url,
|
||||
cover: row_meta.cover_url,
|
||||
is_document_empty: row_meta.is_document_empty,
|
||||
is_document_empty: Some(row_meta.is_document_empty),
|
||||
})
|
||||
} else {
|
||||
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.
|
||||
send_notification(row_id.as_str(), DatabaseNotification::DidUpdateRowMeta)
|
||||
.payload(RowMetaPB::from(&row_detail))
|
||||
.payload(RowMetaPB::from(row_detail))
|
||||
.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
|
||||
}
|
||||
|
||||
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.
|
||||
/// This will notify all views that the cell has been updated.
|
||||
pub async fn update_cell(
|
||||
@ -919,7 +906,9 @@ impl DatabaseEditor {
|
||||
.write()
|
||||
.await
|
||||
.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);
|
||||
});
|
||||
})
|
||||
@ -1170,7 +1159,7 @@ impl DatabaseEditor {
|
||||
let to_row = if to_row.is_some() {
|
||||
to_row
|
||||
} else {
|
||||
let row_details = self.get_row_details(view_id).await?;
|
||||
let row_details = self.get_all_row_details(view_id).await?;
|
||||
row_details
|
||||
.last()
|
||||
.map(|row_detail| row_detail.row.id.clone())
|
||||
@ -1189,7 +1178,9 @@ impl DatabaseEditor {
|
||||
.write()
|
||||
.await
|
||||
.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;
|
||||
},
|
||||
@ -1296,14 +1287,34 @@ impl DatabaseEditor {
|
||||
Ok(database_view_setting_pb_from_view(view))
|
||||
}
|
||||
|
||||
pub async fn get_database_data(&self, view_id: &str) -> FlowyResult<DatabasePB> {
|
||||
let database_view = self.database_views.get_view_editor(view_id).await?;
|
||||
let view = database_view
|
||||
.v_get_view()
|
||||
.await
|
||||
.ok_or_else(FlowyError::record_not_found)?;
|
||||
pub async fn close_database(&self) {
|
||||
let cancellation = self.database_cancellation.read().await;
|
||||
if let Some(cancellation) = &*cancellation {
|
||||
info!("Cancel database operation");
|
||||
cancellation.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
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 = self.database.read().await;
|
||||
let database_id = database.get_database_id();
|
||||
@ -1318,7 +1329,7 @@ impl DatabaseEditor {
|
||||
|
||||
let rows = row_details
|
||||
.into_iter()
|
||||
.map(|detail| RowMetaPB::from(detail.as_ref()))
|
||||
.map(|order| RowMetaPB::from(order.as_ref().clone()))
|
||||
.collect::<Vec<RowMetaPB>>();
|
||||
|
||||
trace!(
|
||||
@ -1327,25 +1338,16 @@ impl DatabaseEditor {
|
||||
fields.len(),
|
||||
rows.len()
|
||||
);
|
||||
self.database_cancellation.write().await.take();
|
||||
Ok(DatabasePB {
|
||||
id: database_id,
|
||||
fields,
|
||||
rows,
|
||||
layout_type: view.layout.into(),
|
||||
layout_type: view_layout.into(),
|
||||
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> {
|
||||
let database = self.database.clone();
|
||||
let database_guard = database.read().await;
|
||||
@ -1467,6 +1469,7 @@ struct DatabaseViewOperationImpl {
|
||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||
cell_cache: CellCache,
|
||||
editor_by_view_id: Arc<RwLock<EditorByViewId>>,
|
||||
database_cancellation: Arc<RwLock<Option<CancellationToken>>>,
|
||||
}
|
||||
|
||||
#[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 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![];
|
||||
// Loading the rows in chunks of 10 rows in order to prevent blocking the main asynchronous runtime
|
||||
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) {
|
||||
let database_read_guard = self.database.read().await;
|
||||
let chunk = chunk.to_vec();
|
||||
let rows = database_read_guard.get_rows_from_row_orders(&chunk).await;
|
||||
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 {
|
||||
None => warn!("Failed to get row detail for row: {}", row.id.as_str()),
|
||||
Some(row_details) => {
|
||||
|
@ -10,9 +10,7 @@ use flowy_notification::{DebounceNotificationSender, NotificationBuilder};
|
||||
use futures::StreamExt;
|
||||
use lib_dispatch::prelude::af_spawn;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{trace, warn};
|
||||
|
||||
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();
|
||||
let database_editor = Arc::downgrade(database_editor);
|
||||
af_spawn(async move {
|
||||
let token = CancellationToken::new();
|
||||
// let token = CancellationToken::new();
|
||||
while let Ok(event) = block_event_rx.recv().await {
|
||||
if database_editor.upgrade().is_none() {
|
||||
break;
|
||||
@ -170,23 +168,17 @@ pub(crate) async fn observe_block_event(database_id: &str, database_editor: &Arc
|
||||
.send();
|
||||
}
|
||||
|
||||
let cloned_token = token.clone();
|
||||
let cloned_database_editor = database_editor.clone();
|
||||
tokio::spawn(async move {
|
||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||
if cloned_token.is_cancelled() {
|
||||
return;
|
||||
}
|
||||
if let Some(database_editor) = cloned_database_editor.upgrade() {
|
||||
for view_editor in database_editor.database_views.editors().await {
|
||||
send_notification(
|
||||
&view_editor.view_id.clone(),
|
||||
DatabaseNotification::ReloadRows,
|
||||
)
|
||||
.send();
|
||||
}
|
||||
}
|
||||
});
|
||||
// let cloned_token = token.clone();
|
||||
// tokio::spawn(async move {
|
||||
// tokio::time::sleep(Duration::from_secs(2)).await;
|
||||
// if cloned_token.is_cancelled() {
|
||||
// }
|
||||
// // if let Some(database_editor) = cloned_database_editor.upgrade() {
|
||||
// // TODO(nathan): calculate inserted row with RowsVisibilityChangePB
|
||||
// // for view_editor in database_editor.database_views.editors().await {
|
||||
// // }
|
||||
// // }
|
||||
// });
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -313,8 +313,8 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
#[instrument(level = "info", skip(self))]
|
||||
pub async fn v_get_row_details(&self) -> Vec<Arc<RowDetail>> {
|
||||
let mut rows = self.delegate.get_row_details(&self.view_id).await;
|
||||
pub async fn v_get_all_row_details(&self) -> Vec<Arc<RowDetail>> {
|
||||
let mut rows = self.delegate.get_all_row_details(&self.view_id).await;
|
||||
self.v_filter_rows(&mut rows).await;
|
||||
self.v_sort_rows(&mut rows).await;
|
||||
rows
|
||||
@ -937,7 +937,7 @@ impl DatabaseViewEditor {
|
||||
|
||||
let (_, row_detail) = self.delegate.get_row_detail(&self.view_id, &row_id).await?;
|
||||
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(),
|
||||
title,
|
||||
timestamp,
|
||||
@ -1000,7 +1000,7 @@ impl DatabaseViewEditor {
|
||||
|
||||
let (_, row_detail) = self.delegate.get_row_detail(&self.view_id, &row_id).await?;
|
||||
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(),
|
||||
title,
|
||||
timestamp,
|
||||
|
@ -53,7 +53,7 @@ impl FilterDelegate for DatabaseViewFilterDelegateImpl {
|
||||
}
|
||||
|
||||
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>)> {
|
||||
|
@ -97,7 +97,7 @@ impl GroupControllerDelegate for GroupControllerDelegateImpl {
|
||||
}
|
||||
|
||||
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;
|
||||
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>)>;
|
||||
|
||||
/// 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>;
|
||||
|
||||
|
@ -61,7 +61,7 @@ impl SortDelegate for DatabaseViewSortDelegateImpl {
|
||||
|
||||
async fn get_rows(&self, view_id: &str) -> Vec<Arc<RowDetail>> {
|
||||
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;
|
||||
row_details
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
mod field_builder;
|
||||
mod field_operation;
|
||||
pub(crate) mod type_option_transform;
|
||||
pub mod type_options;
|
||||
|
||||
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::rows::Cell;
|
||||
use flowy_error::FlowyResult;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::entities::{ChecklistCellDataPB, ChecklistFilterPB, SelectOptionPB};
|
||||
use crate::services::cell::{CellDataChangeset, CellDataDecoder};
|
||||
use crate::services::field::checklist_type_option::{ChecklistCellChangeset, ChecklistCellData};
|
||||
use crate::services::field::{
|
||||
SelectOption, TypeOption, TypeOptionCellData, TypeOptionCellDataCompare,
|
||||
TypeOptionCellDataFilter, TypeOptionCellDataSerde, TypeOptionTransform, SELECTION_IDS_SEPARATOR,
|
||||
TypeOption, TypeOptionCellData, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
||||
TypeOptionCellDataSerde, TypeOptionTransform, SELECTION_IDS_SEPARATOR,
|
||||
};
|
||||
use crate::services::sort::SortCondition;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
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_database::entity::SelectOption;
|
||||
use collab_database::rows::{new_cell_builder, Cell};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
|
@ -1,8 +1,8 @@
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::Cell;
|
||||
|
||||
use crate::entities::{ChecklistFilterConditionPB, ChecklistFilterPB};
|
||||
use crate::services::field::SelectOption;
|
||||
use crate::services::filter::PreFillCellsWithFilter;
|
||||
|
||||
impl ChecklistFilterPB {
|
||||
|
@ -1,18 +1,17 @@
|
||||
use collab::util::AnyMapExt;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder};
|
||||
use collab_database::rows::Cell;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::{FieldType, SelectOptionCellDataPB, SelectOptionFilterPB};
|
||||
use crate::services::cell::CellDataChangeset;
|
||||
use crate::services::field::{
|
||||
default_order, SelectOption, SelectOptionCellChangeset, SelectOptionIds,
|
||||
SelectTypeOptionSharedAction, TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
||||
TypeOptionCellDataSerde,
|
||||
default_order, SelectOptionCellChangeset, SelectOptionIds, SelectTypeOptionSharedAction,
|
||||
TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter, TypeOptionCellDataSerde,
|
||||
};
|
||||
use crate::services::sort::SortCondition;
|
||||
|
||||
@ -176,39 +175,10 @@ impl TypeOptionCellDataCompare for MultiSelectTypeOption {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::cell::CellDataChangeset;
|
||||
use crate::services::field::type_options::selection_type_option::*;
|
||||
use crate::services::field::MultiSelectTypeOption;
|
||||
use crate::services::field::{CheckboxTypeOption, TypeOptionTransform};
|
||||
|
||||
#[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);
|
||||
}
|
||||
use collab_database::entity::SelectOption;
|
||||
|
||||
#[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::rows::Cell;
|
||||
|
||||
use crate::entities::{SelectOptionFilterConditionPB, SelectOptionFilterPB};
|
||||
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;
|
||||
|
||||
impl SelectOptionFilterPB {
|
||||
@ -132,7 +133,7 @@ impl PreFillCellsWithFilter for SelectOptionFilterPB {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::{SelectOptionFilterConditionPB, SelectOptionFilterPB};
|
||||
use crate::services::field::SelectOption;
|
||||
use collab_database::entity::SelectOption;
|
||||
|
||||
#[test]
|
||||
fn select_option_filter_is_empty_test() {
|
||||
|
@ -1,50 +1,6 @@
|
||||
use crate::entities::SelectOptionCellDataPB;
|
||||
use crate::services::field::SelectOptionIds;
|
||||
use collab_database::database::gen_option_id;
|
||||
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,
|
||||
}
|
||||
|
||||
use collab_database::entity::SelectOption;
|
||||
#[derive(Debug)]
|
||||
pub struct SelectOptionCellData {
|
||||
pub select_options: Vec<SelectOption>,
|
||||
|
@ -1,18 +1,19 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use collab_database::database::Database;
|
||||
use collab_database::entity::{SelectOption, SelectOptionColor};
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::Cell;
|
||||
|
||||
use flowy_error::{internal_error, ErrorCode, FlowyResult};
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::entities::{CheckboxCellDataPB, FieldType, SelectOptionCellDataPB};
|
||||
use crate::services::cell::{CellDataDecoder, CellProtobufBlobParser};
|
||||
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformHelper;
|
||||
use crate::services::field::{
|
||||
make_selected_options, MultiSelectTypeOption, SelectOption, SelectOptionCellData,
|
||||
SelectOptionColor, SelectOptionIds, SingleSelectTypeOption, TypeOption, TypeOptionCellDataSerde,
|
||||
TypeOptionTransform, SELECTION_IDS_SEPARATOR,
|
||||
make_selected_options, MultiSelectTypeOption, SelectOptionCellData, SelectOptionIds,
|
||||
SingleSelectTypeOption, StringCellData, TypeOption, TypeOptionCellDataSerde, TypeOptionTransform,
|
||||
SELECTION_IDS_SEPARATOR,
|
||||
};
|
||||
|
||||
/// 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>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> TypeOptionTransform for T
|
||||
where
|
||||
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds> + CellDataDecoder,
|
||||
{
|
||||
fn transform_type_option(
|
||||
async fn transform_type_option(
|
||||
&mut self,
|
||||
_old_type_option_field_type: FieldType,
|
||||
_old_type_option_data: TypeOptionData,
|
||||
view_id: &str,
|
||||
field_id: &str,
|
||||
old_type_option_field_type: FieldType,
|
||||
old_type_option_data: TypeOptionData,
|
||||
database: &Database,
|
||||
) {
|
||||
SelectOptionTypeOptionTransformHelper::transform_type_option(
|
||||
self,
|
||||
&_old_type_option_field_type,
|
||||
_old_type_option_data,
|
||||
);
|
||||
view_id,
|
||||
field_id,
|
||||
&old_type_option_field_type,
|
||||
old_type_option_data,
|
||||
database,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +110,15 @@ where
|
||||
_field: &Field,
|
||||
) -> Option<<Self as TypeOption>::CellData> {
|
||||
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 => {
|
||||
let cell_content = CheckboxCellDataPB::from(cell).to_string();
|
||||
let mut transformed_ids = Vec::new();
|
||||
@ -110,7 +128,6 @@ where
|
||||
}
|
||||
Some(SelectOptionIds::from(transformed_ids))
|
||||
},
|
||||
FieldType::RichText => Some(SelectOptionIds::from(cell)),
|
||||
FieldType::SingleSelect | FieldType::MultiSelect => Some(SelectOptionIds::from(cell)),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::entities::{FieldType, SelectOptionCellDataPB, SelectOptionFilterPB};
|
||||
use crate::services::cell::CellDataChangeset;
|
||||
use crate::services::field::{
|
||||
default_order, SelectOption, TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
||||
default_order, TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter,
|
||||
TypeOptionCellDataSerde,
|
||||
};
|
||||
use crate::services::field::{
|
||||
@ -9,6 +9,7 @@ use crate::services::field::{
|
||||
};
|
||||
use crate::services::sort::SortCondition;
|
||||
use collab::util::AnyMapExt;
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::{TypeOptionData, TypeOptionDataBuilder};
|
||||
use collab_database::rows::Cell;
|
||||
use flowy_error::FlowyResult;
|
||||
@ -149,40 +150,9 @@ impl TypeOptionCellDataCompare for SingleSelectTypeOption {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::cell::CellDataChangeset;
|
||||
use crate::services::field::type_options::*;
|
||||
|
||||
#[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);
|
||||
}
|
||||
use collab_database::entity::SelectOption;
|
||||
|
||||
#[test]
|
||||
fn single_select_insert_multi_option_test() {
|
||||
|
@ -1,9 +1,13 @@
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::cell::CellDataDecoder;
|
||||
use crate::services::field::{
|
||||
MultiSelectTypeOption, SelectOption, SelectOptionColor, SelectOptionIds,
|
||||
SelectTypeOptionSharedAction, SingleSelectTypeOption, TypeOption, CHECK, UNCHECK,
|
||||
MultiSelectTypeOption, RichTextTypeOption, SelectOptionIds, SelectTypeOptionSharedAction,
|
||||
SingleSelectTypeOption, TypeOption, CHECK, UNCHECK,
|
||||
};
|
||||
use collab_database::database::Database;
|
||||
use collab_database::entity::{SelectOption, SelectOptionColor};
|
||||
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
|
||||
pub(crate) struct SelectOptionTypeOptionTransformHelper();
|
||||
@ -14,14 +18,37 @@ impl SelectOptionTypeOptionTransformHelper {
|
||||
///
|
||||
/// * `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,
|
||||
view_id: &str,
|
||||
field_id: &str,
|
||||
old_field_type: &FieldType,
|
||||
old_type_option_data: TypeOptionData,
|
||||
database: &Database,
|
||||
) where
|
||||
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds>,
|
||||
{
|
||||
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 => {
|
||||
// add Yes and No options if it does not exist.
|
||||
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::field::FieldBuilder;
|
||||
use crate::services::field::*;
|
||||
use collab_database::entity::SelectOption;
|
||||
|
||||
// Test parser the cell data which field's type is FieldType::Date to cell data
|
||||
// which field's type is FieldType::Text
|
||||
|
@ -147,6 +147,11 @@ impl TypeOptionCellDataCompare for RichTextTypeOption {
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct StringCellData(pub String);
|
||||
impl StringCellData {
|
||||
pub fn into_inner(self) -> String {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl std::ops::Deref for StringCellData {
|
||||
type Target = String;
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bytes::Bytes;
|
||||
use collab_database::database::Database;
|
||||
use collab_database::fields::TypeOptionData;
|
||||
use collab_database::rows::Cell;
|
||||
use protobuf::ProtobufError;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::Debug;
|
||||
|
||||
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
|
||||
/// 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.
|
||||
@ -104,10 +106,13 @@ pub trait TypeOptionTransform: 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`.
|
||||
///
|
||||
fn transform_type_option(
|
||||
async fn transform_type_option(
|
||||
&mut self,
|
||||
_view_id: &str,
|
||||
_field_id: &str,
|
||||
_old_type_option_field_type: FieldType,
|
||||
_old_type_option_data: TypeOptionData,
|
||||
_database: &Database,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,8 @@ use std::collections::hash_map::DefaultHasher;
|
||||
use std::collections::HashMap;
|
||||
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 flowy_error::FlowyResult;
|
||||
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;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CellDataCacheKey(u64);
|
||||
impl CellDataCacheKey {
|
||||
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> {
|
||||
let key = self.get_cell_data_cache_key(cell, field);
|
||||
|
||||
let cell_data_cache = self.cell_data_cache.as_ref()?;
|
||||
|
||||
let cell = cell_data_cache.get::<T::CellData>(key.as_ref())?;
|
||||
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(
|
||||
from_field_type: FieldType,
|
||||
to_field_type: FieldType,
|
||||
) -> bool {
|
||||
matches!(
|
||||
(from_field_type, to_field_type),
|
||||
// Checkbox
|
||||
(FieldType::Checkbox, FieldType::SingleSelect)
|
||||
| (FieldType::Checkbox, FieldType::MultiSelect)
|
||||
// SingleSelect or MultiSelect
|
||||
| (FieldType::SingleSelect, FieldType::MultiSelect)
|
||||
| (FieldType::MultiSelect, FieldType::SingleSelect)
|
||||
// Text
|
||||
| (FieldType::RichText, FieldType::SingleSelect)
|
||||
| (FieldType::RichText, FieldType::MultiSelect)
|
||||
| (FieldType::RichText, FieldType::URL)
|
||||
| (_, 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 struct RowSingleCellData {
|
||||
|
@ -1,13 +1,13 @@
|
||||
use collab::preclude::encoding::serde::from_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 flowy_error::FlowyResult;
|
||||
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::field::{
|
||||
TypeOption, TypeOptionCellDataCompare, TypeOptionCellDataFilter, TypeOptionCellDataSerde,
|
||||
@ -64,6 +64,17 @@ impl CellDataDecoder for URLTypeOption {
|
||||
fn decode_cell(&self, cell: &Cell) -> FlowyResult<<Self as TypeOption>::CellData> {
|
||||
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 {
|
||||
cell_data.data
|
||||
|
@ -360,7 +360,8 @@ impl FilterController {
|
||||
if is_visible {
|
||||
if let Some((index, _row)) = self.delegate.get_row(&self.view_id, &row_id).await {
|
||||
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 {
|
||||
@ -397,7 +398,7 @@ impl FilterController {
|
||||
&filters,
|
||||
) {
|
||||
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))
|
||||
} else {
|
||||
invisible_rows.push(row_detail.row.id.clone());
|
||||
|
@ -115,7 +115,7 @@ where
|
||||
if !no_status_group_rows.is_empty() {
|
||||
changeset
|
||||
.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());
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ impl GroupCustomize for CheckboxGroupController {
|
||||
if is_not_contained {
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||
group.add_row(row_detail.clone());
|
||||
}
|
||||
}
|
||||
@ -86,7 +86,7 @@ impl GroupCustomize for CheckboxGroupController {
|
||||
if is_not_contained {
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(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 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);
|
||||
}
|
||||
|
||||
@ -130,7 +133,7 @@ impl GroupCustomize for DateGroupController {
|
||||
if !group.contains_row(&row_detail.row.id) {
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||
group.add_row(row_detail.clone());
|
||||
}
|
||||
} else if group.contains_row(&row_detail.row.id) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
@ -7,8 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::entities::{FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
||||
use crate::services::cell::insert_select_option_cell;
|
||||
use crate::services::field::{
|
||||
MultiSelectTypeOption, SelectOption, SelectOptionCellDataParser, SelectTypeOptionSharedAction,
|
||||
TypeOption,
|
||||
MultiSelectTypeOption, SelectOptionCellDataParser, SelectTypeOptionSharedAction, TypeOption,
|
||||
};
|
||||
use crate::services::group::action::GroupCustomize;
|
||||
use crate::services::group::controller::BaseGroupController;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
@ -7,8 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::entities::{FieldType, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
||||
use crate::services::cell::insert_select_option_cell;
|
||||
use crate::services::field::{
|
||||
SelectOption, SelectOptionCellDataParser, SelectTypeOptionSharedAction, SingleSelectTypeOption,
|
||||
TypeOption,
|
||||
SelectOptionCellDataParser, SelectTypeOptionSharedAction, SingleSelectTypeOption, TypeOption,
|
||||
};
|
||||
use crate::services::group::action::GroupCustomize;
|
||||
use crate::services::group::controller::BaseGroupController;
|
||||
|
@ -1,4 +1,5 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Cell, Row, RowDetail};
|
||||
|
||||
@ -8,7 +9,7 @@ use crate::entities::{
|
||||
use crate::services::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};
|
||||
|
||||
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) {
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||
group.add_row(row_detail.clone());
|
||||
}
|
||||
} 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 group = Group::new(cell_data.data);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -98,7 +101,7 @@ impl GroupCustomize for URLGroupController {
|
||||
if !group.contains_row(&row_detail.row.id) {
|
||||
changeset
|
||||
.inserted_rows
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
|
||||
.push(InsertedRowPB::new(RowMetaPB::from(row_detail.clone())));
|
||||
group.add_row(row_detail.clone());
|
||||
}
|
||||
} 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::entity::{CreateDatabaseParams, CreateViewParams};
|
||||
use collab_database::entity::{
|
||||
CreateDatabaseParams, CreateViewParams, SelectOption, SelectOptionColor,
|
||||
};
|
||||
use collab_database::rows::CreateRowParams;
|
||||
use collab_database::views::{DatabaseLayout, LayoutSettings};
|
||||
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::cell::{insert_select_option_cell, insert_text_cell};
|
||||
use crate::services::field::{
|
||||
FieldBuilder, SelectOption, SelectOptionColor, SingleSelectTypeOption,
|
||||
};
|
||||
use crate::services::field::{FieldBuilder, SingleSelectTypeOption};
|
||||
use crate::services::field_settings::default_field_settings_for_fields;
|
||||
use crate::services::setting::{BoardLayoutSetting, CalendarLayoutSetting};
|
||||
|
||||
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::database::gen_database_view_id;
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{RowDetail, RowId};
|
||||
use lib_infra::box_any::BoxAny;
|
||||
@ -16,8 +17,7 @@ use flowy_database2::services::field::checklist_type_option::{
|
||||
ChecklistCellChangeset, ChecklistTypeOption,
|
||||
};
|
||||
use flowy_database2::services::field::{
|
||||
CheckboxTypeOption, MultiSelectTypeOption, SelectOption, SelectOptionCellChangeset,
|
||||
SingleSelectTypeOption,
|
||||
CheckboxTypeOption, MultiSelectTypeOption, SelectOptionCellChangeset, SingleSelectTypeOption,
|
||||
};
|
||||
use flowy_database2::services::share::csv::{CSVFormat, ImportResult};
|
||||
use flowy_error::FlowyResult;
|
||||
@ -86,7 +86,7 @@ impl DatabaseEditorTest {
|
||||
.map(Arc::new)
|
||||
.collect();
|
||||
let rows = editor
|
||||
.get_row_details(&test.child_view.id)
|
||||
.get_all_row_details(&test.child_view.id)
|
||||
.await
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
@ -109,7 +109,11 @@ impl DatabaseEditorTest {
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -16,6 +16,7 @@ pub enum FieldScript {
|
||||
field: Field,
|
||||
},
|
||||
SwitchToField {
|
||||
view_id: String,
|
||||
field_id: String,
|
||||
new_field_type: FieldType,
|
||||
},
|
||||
@ -80,13 +81,14 @@ impl DatabaseFieldTest {
|
||||
assert_eq!(self.field_count, fields.len());
|
||||
},
|
||||
FieldScript::SwitchToField {
|
||||
view_id,
|
||||
field_id,
|
||||
new_field_type,
|
||||
} => {
|
||||
//
|
||||
self
|
||||
.editor
|
||||
.switch_to_field_type(&field_id, new_field_type)
|
||||
.switch_to_field_type(&view_id, &field_id, new_field_type)
|
||||
.await
|
||||
.unwrap();
|
||||
},
|
||||
@ -121,7 +123,11 @@ impl DatabaseFieldTest {
|
||||
} => {
|
||||
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 cell = row_detail.row.cells.get(&field_id).unwrap().clone();
|
||||
|
@ -1,7 +1,7 @@
|
||||
use collab_database::database::gen_option_id;
|
||||
|
||||
use collab_database::entity::SelectOption;
|
||||
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::FieldScript::*;
|
||||
@ -122,6 +122,7 @@ async fn grid_delete_field() {
|
||||
async fn grid_switch_from_select_option_to_checkbox_test() {
|
||||
let mut test = DatabaseFieldTest::new().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
|
||||
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(),
|
||||
},
|
||||
SwitchToField {
|
||||
view_id: view_id.clone(),
|
||||
field_id: field.id.clone(),
|
||||
new_field_type: FieldType::Checkbox,
|
||||
},
|
||||
@ -163,6 +165,7 @@ async fn grid_switch_from_checkbox_to_select_option_test() {
|
||||
let scripts = vec![
|
||||
// switch to single-select field type
|
||||
SwitchToField {
|
||||
view_id: test.view_id(),
|
||||
field_id: checkbox_field.id.clone(),
|
||||
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 script_switch_field = vec![SwitchToField {
|
||||
view_id: test.view_id(),
|
||||
field_id: field_rev.id.clone(),
|
||||
new_field_type: FieldType::RichText,
|
||||
}];
|
||||
@ -229,6 +233,7 @@ async fn grid_switch_from_checkbox_to_text_test() {
|
||||
|
||||
let scripts = vec![
|
||||
SwitchToField {
|
||||
view_id: test.view_id(),
|
||||
field_id: field_rev.id.clone(),
|
||||
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 scripts = vec![
|
||||
SwitchToField {
|
||||
view_id: test.view_id(),
|
||||
field_id: field.id.clone(),
|
||||
new_field_type: FieldType::RichText,
|
||||
},
|
||||
@ -282,6 +288,7 @@ async fn grid_switch_from_number_to_text_test() {
|
||||
|
||||
let scripts = vec![
|
||||
SwitchToField {
|
||||
view_id: test.view_id(),
|
||||
field_id: field.id.clone(),
|
||||
new_field_type: FieldType::RichText,
|
||||
},
|
||||
@ -308,6 +315,7 @@ async fn grid_switch_from_checklist_to_text_test() {
|
||||
|
||||
let scripts = vec![
|
||||
SwitchToField {
|
||||
view_id: test.view_id(),
|
||||
field_id: field_rev.id.clone(),
|
||||
new_field_type: FieldType::RichText,
|
||||
},
|
||||
|
@ -1,9 +1,10 @@
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::views::OrderObjectPosition;
|
||||
|
||||
use flowy_database2::entities::{CreateFieldParams, FieldType};
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -301,7 +301,7 @@ impl DatabaseFilterTest {
|
||||
}
|
||||
},
|
||||
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);
|
||||
},
|
||||
FilterScript::Wait { millisecond } => {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use collab_database::entity::SelectOption;
|
||||
use collab_database::fields::Field;
|
||||
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,
|
||||
};
|
||||
use flowy_database2::services::field::{
|
||||
edit_single_select_type_option, SelectOption, SelectTypeOptionSharedAction,
|
||||
SingleSelectTypeOption,
|
||||
edit_single_select_type_option, SelectTypeOptionSharedAction, SingleSelectTypeOption,
|
||||
};
|
||||
|
||||
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::GroupScript::*;
|
||||
use collab_database::entity::SelectOption;
|
||||
|
||||
#[tokio::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::entity::DatabaseView;
|
||||
use collab_database::entity::{DatabaseView, SelectOption, SelectOptionColor};
|
||||
use collab_database::views::{DatabaseLayout, LayoutSetting, LayoutSettings};
|
||||
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::{
|
||||
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::setting::BoardLayoutSetting;
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 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::{
|
||||
ChecklistTypeOption, DateFormat, DateTypeOption, FieldBuilder, MultiSelectTypeOption,
|
||||
NumberFormat, NumberTypeOption, RelationTypeOption, SelectOption, SelectOptionColor,
|
||||
SingleSelectTypeOption, TimeFormat, TimeTypeOption, TimestampTypeOption,
|
||||
NumberFormat, NumberTypeOption, RelationTypeOption, SingleSelectTypeOption, TimeFormat,
|
||||
TimeTypeOption, TimestampTypeOption,
|
||||
};
|
||||
use flowy_database2::services::field_settings::default_field_settings_for_fields;
|
||||
|
||||
|
@ -86,7 +86,11 @@ impl DatabasePreFillRowCellTest {
|
||||
.await
|
||||
.unwrap(),
|
||||
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());
|
||||
},
|
||||
PreFillRowCellTestScript::AssertCellExistence {
|
||||
@ -94,7 +98,11 @@ impl DatabasePreFillRowCellTest {
|
||||
row_index,
|
||||
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 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 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 cell = row_detail
|
||||
@ -125,7 +137,11 @@ impl DatabasePreFillRowCellTest {
|
||||
row_index,
|
||||
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 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 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[1].field_type, 1);
|
||||
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 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[1].field_type, 1);
|
||||
assert_eq!(fields[2].field_type, 2);
|
||||
|
@ -117,7 +117,11 @@ impl DatabaseSortTest {
|
||||
},
|
||||
SortScript::AssertCellContentOrder { field_id, orders } => {
|
||||
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();
|
||||
for row_detail in rows {
|
||||
if let Some(cell) = row_detail.row.cells.get(&field_id) {
|
||||
|
Loading…
Reference in New Issue
Block a user