mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: group with not support field test (#1890)
This commit is contained in:
parent
bf8e36a08b
commit
4a81fed6e4
4
frontend/.vscode/launch.json
vendored
4
frontend/.vscode/launch.json
vendored
@ -12,8 +12,8 @@
|
||||
"type": "dart",
|
||||
"preLaunchTask": "AF: Build Appflowy Core",
|
||||
"env": {
|
||||
"RUST_LOG": "trace",
|
||||
// "RUST_LOG": "debug"
|
||||
// "RUST_LOG": "trace",
|
||||
"RUST_LOG": "debug"
|
||||
},
|
||||
"cwd": "${workspaceRoot}/appflowy_flutter"
|
||||
},
|
||||
|
@ -18,7 +18,7 @@ on_error_task = "catch"
|
||||
run_task = { name = ["restore-crate-type"] }
|
||||
|
||||
[env]
|
||||
RUST_LOG = "debug"
|
||||
RUST_LOG = "info"
|
||||
CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
|
||||
CARGO_MAKE_CRATE_FS_NAME = "dart_ffi"
|
||||
CARGO_MAKE_CRATE_NAME = "dart-ffi"
|
||||
@ -48,7 +48,6 @@ TAURI_BACKEND_SERVICE_PATH = "appflowy_tauri/src/services/backend"
|
||||
# Test default config
|
||||
TEST_CRATE_TYPE = "cdylib"
|
||||
TEST_LIB_EXT = "dylib"
|
||||
TEST_RUST_LOG = "info"
|
||||
TEST_BUILD_FLAG = "debug"
|
||||
TEST_COMPILE_TARGET = "x86_64-apple-darwin"
|
||||
|
||||
|
@ -53,7 +53,7 @@ class DatabaseBackendService {
|
||||
});
|
||||
}
|
||||
|
||||
Future<Either<Unit, FlowyError>> closeGrid() {
|
||||
Future<Either<Unit, FlowyError>> closeView() {
|
||||
final request = ViewIdPB(value: viewId);
|
||||
return FolderEventCloseView(request).send();
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ class BoardDataController {
|
||||
|
||||
Future<void> dispose() async {
|
||||
await _viewCache.dispose();
|
||||
await _databaseFFIService.closeGrid();
|
||||
await _databaseFFIService.closeView();
|
||||
await fieldController.dispose();
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ class CalendarDataController {
|
||||
|
||||
Future<void> dispose() async {
|
||||
await _viewCache.dispose();
|
||||
await _databaseBackendSvc.closeGrid();
|
||||
await _databaseBackendSvc.closeView();
|
||||
await fieldController.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ class DatabaseController {
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
await _databaseBackendSvc.closeGrid();
|
||||
await _databaseBackendSvc.closeView();
|
||||
await fieldController.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ void main() {
|
||||
await boardResponseFuture();
|
||||
});
|
||||
|
||||
group('Group with not support grouping field:', () {
|
||||
group('Group with not support grouping field', () {
|
||||
blocTest<FieldEditorBloc, FieldEditorState>(
|
||||
"switch to text field",
|
||||
build: () => editorBloc,
|
||||
|
2
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
2
frontend/appflowy_tauri/src-tauri/Cargo.lock
generated
@ -1225,6 +1225,8 @@ dependencies = [
|
||||
"lib-ws",
|
||||
"parking_lot",
|
||||
"revision-model",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"user-model",
|
||||
|
@ -14,7 +14,7 @@ class CellIdentifier {
|
||||
class CellBackendService {
|
||||
static updateCell = async (cellId: CellIdentifier, data: string) => {
|
||||
const payload = CellChangesetPB.fromObject({
|
||||
database_id: cellId.viewId,
|
||||
view_id: cellId.viewId,
|
||||
field_id: cellId.fieldId,
|
||||
row_id: cellId.rowId,
|
||||
type_cell_data: data,
|
||||
@ -24,7 +24,7 @@ class CellBackendService {
|
||||
|
||||
getCell = async (cellId: CellIdentifier) => {
|
||||
const payload = CellIdPB.fromObject({
|
||||
database_id: cellId.viewId,
|
||||
view_id: cellId.viewId,
|
||||
field_id: cellId.fieldId,
|
||||
row_id: cellId.rowId,
|
||||
});
|
||||
|
@ -39,7 +39,7 @@ export class DateCellDataPersistence extends CellDataPersistence<CalendarData> {
|
||||
|
||||
function _makeCellPath(cellIdentifier: CellIdentifier): CellIdPB {
|
||||
return CellIdPB.fromObject({
|
||||
database_id: cellIdentifier.viewId,
|
||||
view_id: cellIdentifier.viewId,
|
||||
field_id: cellIdentifier.fieldId,
|
||||
row_id: cellIdentifier.rowId,
|
||||
});
|
||||
|
@ -28,7 +28,7 @@ export class FieldBackendService {
|
||||
visibility?: boolean;
|
||||
width?: number;
|
||||
}) => {
|
||||
const payload = FieldChangesetPB.fromObject({ database_id: this.viewId, field_id: this.fieldId });
|
||||
const payload = FieldChangesetPB.fromObject({ view_id: this.viewId, field_id: this.fieldId });
|
||||
|
||||
if (data.name !== undefined) {
|
||||
payload.name = data.name;
|
||||
|
@ -3,8 +3,8 @@ import { ChangeNotifier } from '../../../../utils/change_notifier';
|
||||
import { FieldInfo } from '../field/controller';
|
||||
import { CellCache, CellCacheKey } from '../cell/cache';
|
||||
import {
|
||||
ViewRowsChangesetPB,
|
||||
ViewRowsVisibilityChangesetPB,
|
||||
RowsChangesetPB,
|
||||
RowsVisibilityChangesetPB,
|
||||
} from '../../../../../services/backend/models/flowy-database/view_entities';
|
||||
import { CellIdentifier } from '../cell/backend_service';
|
||||
import { ReorderSingleRowPB } from '../../../../../services/backend/models/flowy-database/sort_entities';
|
||||
@ -49,13 +49,13 @@ export class RowCache {
|
||||
});
|
||||
};
|
||||
|
||||
applyRowsChanged = (changeset: ViewRowsChangesetPB) => {
|
||||
applyRowsChanged = (changeset: RowsChangesetPB) => {
|
||||
this._deleteRows(changeset.deleted_rows);
|
||||
this._insertRows(changeset.inserted_rows);
|
||||
this._updateRows(changeset.updated_rows);
|
||||
};
|
||||
|
||||
applyRowsVisibility = (changeset: ViewRowsVisibilityChangesetPB) => {
|
||||
applyRowsVisibility = (changeset: RowsVisibilityChangesetPB) => {
|
||||
this._hideRows(changeset.invisible_rows);
|
||||
this._displayRows(changeset.visible_rows);
|
||||
};
|
||||
|
@ -5,15 +5,15 @@ import {
|
||||
ReorderSingleRowPB,
|
||||
} from '../../../../../services/backend/events/flowy-database';
|
||||
import {
|
||||
ViewRowsChangesetPB,
|
||||
ViewRowsVisibilityChangesetPB,
|
||||
RowsChangesetPB,
|
||||
RowsVisibilityChangesetPB,
|
||||
} from '../../../../../services/backend/models/flowy-database/view_entities';
|
||||
import { FlowyError } from '../../../../../services/backend/models/flowy-error/errors';
|
||||
import { ChangeNotifier } from '../../../../utils/change_notifier';
|
||||
import { DatabaseNotificationObserver } from '../notifications/observer';
|
||||
|
||||
export type RowsVisibilityNotifyValue = Result<ViewRowsVisibilityChangesetPB, FlowyError>;
|
||||
export type RowsNotifyValue = Result<ViewRowsChangesetPB, FlowyError>;
|
||||
export type RowsVisibilityNotifyValue = Result<RowsVisibilityChangesetPB, FlowyError>;
|
||||
export type RowsNotifyValue = Result<RowsChangesetPB, FlowyError>;
|
||||
export type ReorderRowsNotifyValue = Result<string[], FlowyError>;
|
||||
export type ReorderSingleRowNotifyValue = Result<ReorderSingleRowPB, FlowyError>;
|
||||
|
||||
@ -43,10 +43,10 @@ export class DatabaseViewRowsObserver {
|
||||
parserHandler: (notification, payload) => {
|
||||
switch (notification) {
|
||||
case DatabaseNotification.DidUpdateViewRowsVisibility:
|
||||
this._rowsVisibilityNotifier.notify(Ok(ViewRowsVisibilityChangesetPB.deserializeBinary(payload)));
|
||||
this._rowsVisibilityNotifier.notify(Ok(RowsVisibilityChangesetPB.deserializeBinary(payload)));
|
||||
break;
|
||||
case DatabaseNotification.DidUpdateViewRows:
|
||||
this._rowsNotifier.notify(Ok(ViewRowsChangesetPB.deserializeBinary(payload)));
|
||||
this._rowsNotifier.notify(Ok(RowsChangesetPB.deserializeBinary(payload)));
|
||||
break;
|
||||
case DatabaseNotification.DidReorderRows:
|
||||
this._reorderRowsNotifier.notify(Ok(ReorderAllRowsPB.deserializeBinary(payload).row_orders));
|
||||
|
@ -41,7 +41,6 @@ export class AppBackendService {
|
||||
belong_to_id: this.appId,
|
||||
name: params.name,
|
||||
desc: params.desc || '',
|
||||
data_format: params.dataFormatType,
|
||||
layout: params.layoutType,
|
||||
initial_data: encoder.encode(params.initialData || ''),
|
||||
});
|
||||
|
@ -109,18 +109,18 @@ impl DatabaseRevisionPad {
|
||||
&mut self,
|
||||
field_id: &str,
|
||||
) -> SyncResult<Option<DatabaseRevisionChangeset>> {
|
||||
self.modify_database(|grid_meta| {
|
||||
match grid_meta
|
||||
self.modify_database(|database| {
|
||||
match database
|
||||
.fields
|
||||
.iter()
|
||||
.position(|field| field.id == field_id)
|
||||
{
|
||||
None => Ok(None),
|
||||
Some(index) => {
|
||||
if grid_meta.fields[index].is_primary {
|
||||
if database.fields[index].is_primary {
|
||||
Err(SyncError::can_not_delete_primary_field())
|
||||
} else {
|
||||
grid_meta.fields.remove(index);
|
||||
database.fields.remove(index);
|
||||
Ok(Some(()))
|
||||
}
|
||||
},
|
||||
|
@ -572,7 +572,7 @@ impl FieldType {
|
||||
}
|
||||
|
||||
pub fn can_be_group(&self) -> bool {
|
||||
self.is_select_option() || self.is_checkbox()
|
||||
self.is_select_option() || self.is_checkbox() || self.is_url()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ pub(crate) async fn delete_field_handler(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(data, manager), err)]
|
||||
#[tracing::instrument(level = "debug", skip(data, manager), err)]
|
||||
pub(crate) async fn switch_to_field_handler(
|
||||
data: AFPluginData<UpdateFieldTypePayloadPB>,
|
||||
manager: AFPluginState<Arc<DatabaseManager>>,
|
||||
|
@ -40,7 +40,7 @@ pub trait DatabaseUser: Send + Sync {
|
||||
}
|
||||
|
||||
pub struct DatabaseManager {
|
||||
database_editors: RwLock<HashMap<String, Arc<DatabaseEditor>>>,
|
||||
editors_by_database_id: RwLock<HashMap<String, Arc<DatabaseEditor>>>,
|
||||
database_user: Arc<dyn DatabaseUser>,
|
||||
block_indexer: Arc<BlockRowIndexer>,
|
||||
database_ref_indexer: Arc<DatabaseRefIndexer>,
|
||||
@ -58,7 +58,7 @@ impl DatabaseManager {
|
||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||
database_db: Arc<dyn DatabaseDBConnection>,
|
||||
) -> Self {
|
||||
let database_editors = RwLock::new(HashMap::new());
|
||||
let editors_by_database_id = RwLock::new(HashMap::new());
|
||||
let kv_persistence = Arc::new(DatabaseKVPersistence::new(database_db.clone()));
|
||||
let block_indexer = Arc::new(BlockRowIndexer::new(database_db.clone()));
|
||||
let database_ref_indexer = Arc::new(DatabaseRefIndexer::new(database_db.clone()));
|
||||
@ -68,7 +68,7 @@ impl DatabaseManager {
|
||||
database_ref_indexer.clone(),
|
||||
);
|
||||
Self {
|
||||
database_editors,
|
||||
editors_by_database_id,
|
||||
database_user,
|
||||
kv_persistence,
|
||||
block_indexer,
|
||||
@ -141,7 +141,6 @@ impl DatabaseManager {
|
||||
.await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all, fields(view_id), err)]
|
||||
pub async fn close_database_view<T: AsRef<str>>(&self, view_id: T) -> FlowyResult<()> {
|
||||
let view_id = view_id.as_ref();
|
||||
let database_info = self.database_ref_indexer.get_database_with_view(view_id)?;
|
||||
@ -149,7 +148,7 @@ impl DatabaseManager {
|
||||
|
||||
let mut should_remove_editor = false;
|
||||
if let Some(database_editor) = self
|
||||
.database_editors
|
||||
.editors_by_database_id
|
||||
.write()
|
||||
.await
|
||||
.get(&database_info.database_id)
|
||||
@ -162,8 +161,9 @@ impl DatabaseManager {
|
||||
}
|
||||
|
||||
if should_remove_editor {
|
||||
tracing::debug!("Close database base editor: {}", database_info.database_id);
|
||||
self
|
||||
.database_editors
|
||||
.editors_by_database_id
|
||||
.write()
|
||||
.await
|
||||
.remove(&database_info.database_id);
|
||||
@ -173,15 +173,19 @@ impl DatabaseManager {
|
||||
|
||||
// #[tracing::instrument(level = "debug", skip(self), err)]
|
||||
pub async fn get_database_editor(&self, view_id: &str) -> FlowyResult<Arc<DatabaseEditor>> {
|
||||
let read_guard = self.database_editors.read().await;
|
||||
let editor = read_guard.get(view_id);
|
||||
match editor {
|
||||
let database_info = self.database_ref_indexer.get_database_with_view(view_id)?;
|
||||
let database_editor = self
|
||||
.editors_by_database_id
|
||||
.read()
|
||||
.await
|
||||
.get(&database_info.database_id)
|
||||
.cloned();
|
||||
match database_editor {
|
||||
None => {
|
||||
// Drop the read_guard ASAP in case of the following read/write lock
|
||||
drop(read_guard);
|
||||
self.open_database_view(view_id).await
|
||||
},
|
||||
Some(editor) => Ok(editor.clone()),
|
||||
Some(editor) => Ok(editor),
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,7 +204,7 @@ impl DatabaseManager {
|
||||
database_id: &str,
|
||||
view_id: &str,
|
||||
) -> FlowyResult<Arc<DatabaseEditor>> {
|
||||
if let Some(database_editor) = self.database_editors.read().await.get(database_id) {
|
||||
if let Some(database_editor) = self.editors_by_database_id.read().await.get(database_id) {
|
||||
let user_id = self.database_user.user_id()?;
|
||||
let (view_pad, view_rev_manager) =
|
||||
make_database_view_revision_pad(view_id, self.database_user.clone()).await?;
|
||||
@ -217,10 +221,10 @@ impl DatabaseManager {
|
||||
return Ok(database_editor.clone());
|
||||
}
|
||||
// Lock the database_editors
|
||||
let mut database_editors = self.database_editors.write().await;
|
||||
let mut editors_by_database_id = self.editors_by_database_id.write().await;
|
||||
let db_pool = self.database_user.db_pool()?;
|
||||
let editor = self.make_database_rev_editor(view_id, db_pool).await?;
|
||||
database_editors.insert(database_id.to_string(), editor.clone());
|
||||
editors_by_database_id.insert(database_id.to_string(), editor.clone());
|
||||
Ok(editor)
|
||||
}
|
||||
|
||||
|
@ -129,15 +129,14 @@ impl DatabaseBlockEditor {
|
||||
if let Ok(pad) = self.pad.try_read() {
|
||||
Ok(pad.get_row_rev(row_id))
|
||||
} else {
|
||||
tracing::error!("Required grid block read lock failed, retrying");
|
||||
let retry = GetRowDataRetryAction {
|
||||
row_id: row_id.to_owned(),
|
||||
pad: self.pad.clone(),
|
||||
};
|
||||
match spawn_retry(3, 300, retry).await {
|
||||
Ok(value) => Ok(value),
|
||||
Err(err) => {
|
||||
tracing::error!("Read row revision failed with: {}", err);
|
||||
Err(_) => {
|
||||
tracing::error!("Required database block read lock failed");
|
||||
Ok(None)
|
||||
},
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ impl DatabaseEditor {
|
||||
self.database_views.open(view_editor).await
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "close database editor view", level = "trace", skip_all)]
|
||||
#[tracing::instrument(name = "Close database editor view", level = "debug", skip_all)]
|
||||
pub async fn close_view_editor(&self, view_id: &str) {
|
||||
self.rev_manager.generate_snapshot().await;
|
||||
self.database_views.close(view_id).await;
|
||||
@ -175,7 +175,7 @@ impl DatabaseEditor {
|
||||
|
||||
self
|
||||
.database_views
|
||||
.did_update_view_field_type_option(view_id, field_id, old_field_rev)
|
||||
.did_update_field_type_option(view_id, field_id, old_field_rev)
|
||||
.await?;
|
||||
self.notify_did_update_database_field(field_id).await?;
|
||||
Ok(())
|
||||
@ -275,7 +275,7 @@ impl DatabaseEditor {
|
||||
if is_changed {
|
||||
match self
|
||||
.database_views
|
||||
.did_update_view_field_type_option(view_id, field_id, old_field_rev)
|
||||
.did_update_field_type_option(view_id, field_id, old_field_rev)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {},
|
||||
@ -600,7 +600,7 @@ impl DatabaseEditor {
|
||||
field_id: &str,
|
||||
) -> FlowyResult<Vec<RowSingleCellData>> {
|
||||
let view_editor = self.database_views.get_view_editor(view_id).await?;
|
||||
view_editor.get_cells_for_field(field_id).await
|
||||
view_editor.v_get_cells_for_field(field_id).await
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
|
@ -222,20 +222,20 @@ impl DatabaseViewEditor {
|
||||
.send();
|
||||
}
|
||||
|
||||
pub async fn sort_rows(&self, rows: &mut Vec<Arc<RowRevision>>) {
|
||||
pub async fn v_sort_rows(&self, rows: &mut Vec<Arc<RowRevision>>) {
|
||||
self.sort_controller.write().await.sort_rows(rows).await
|
||||
}
|
||||
|
||||
pub async fn filter_rows(&self, _block_id: &str, rows: &mut Vec<Arc<RowRevision>>) {
|
||||
pub async fn v_filter_rows(&self, _block_id: &str, rows: &mut Vec<Arc<RowRevision>>) {
|
||||
self.filter_controller.filter_row_revs(rows).await;
|
||||
}
|
||||
|
||||
pub async fn duplicate_view_data(&self) -> FlowyResult<String> {
|
||||
pub async fn v_duplicate_data(&self) -> FlowyResult<String> {
|
||||
let json_str = self.pad.read().await.json_str()?;
|
||||
Ok(json_str)
|
||||
}
|
||||
|
||||
pub async fn will_create_view_row(&self, row_rev: &mut RowRevision, params: &CreateRowParams) {
|
||||
pub async fn v_will_create_row(&self, row_rev: &mut RowRevision, params: &CreateRowParams) {
|
||||
if params.group_id.is_none() {
|
||||
return;
|
||||
}
|
||||
@ -248,7 +248,7 @@ impl DatabaseViewEditor {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn did_create_view_row(&self, row_pb: &RowPB, params: &CreateRowParams) {
|
||||
pub async fn v_did_create_row(&self, row_pb: &RowPB, params: &CreateRowParams) {
|
||||
// Send the group notification if the current view has groups
|
||||
match params.group_id.as_ref() {
|
||||
None => {},
|
||||
@ -275,7 +275,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
pub async fn did_delete_view_row(&self, row_rev: &RowRevision) {
|
||||
pub async fn v_did_delete_row(&self, row_rev: &RowRevision) {
|
||||
// Send the group notification if the current view has groups;
|
||||
let result = self
|
||||
.mut_group_controller(|group_controller, field_rev| {
|
||||
@ -291,7 +291,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn did_update_view_row(
|
||||
pub async fn v_did_update_row(
|
||||
&self,
|
||||
old_row_rev: Option<Arc<RowRevision>>,
|
||||
row_rev: &RowRevision,
|
||||
@ -339,7 +339,7 @@ impl DatabaseViewEditor {
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn move_view_group_row(
|
||||
pub async fn v_move_group_row(
|
||||
&self,
|
||||
row_rev: &RowRevision,
|
||||
row_changeset: &mut RowChangeset,
|
||||
@ -377,7 +377,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
/// Only call once after grid view editor initialized
|
||||
#[tracing::instrument(level = "trace", skip(self))]
|
||||
pub async fn load_view_groups(&self) -> FlowyResult<Vec<GroupPB>> {
|
||||
pub async fn v_load_groups(&self) -> FlowyResult<Vec<GroupPB>> {
|
||||
let groups = self
|
||||
.group_controller
|
||||
.read()
|
||||
@ -391,7 +391,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn move_view_group(&self, params: MoveGroupParams) -> FlowyResult<()> {
|
||||
pub async fn v_move_group(&self, params: MoveGroupParams) -> FlowyResult<()> {
|
||||
self
|
||||
.group_controller
|
||||
.write()
|
||||
@ -430,7 +430,7 @@ impl DatabaseViewEditor {
|
||||
|
||||
/// Initialize new group when grouping by a new field
|
||||
///
|
||||
pub async fn initialize_new_group(&self, params: InsertGroupParams) -> FlowyResult<()> {
|
||||
pub async fn v_initialize_new_group(&self, params: InsertGroupParams) -> FlowyResult<()> {
|
||||
if let Some(field_rev) = self.delegate.get_field_rev(¶ms.field_id).await {
|
||||
self
|
||||
.modify(|pad| {
|
||||
@ -445,13 +445,13 @@ impl DatabaseViewEditor {
|
||||
.await?;
|
||||
}
|
||||
if self.group_controller.read().await.field_id() != params.field_id {
|
||||
self.group_by_view_field(¶ms.field_id).await?;
|
||||
self.v_update_group_setting(¶ms.field_id).await?;
|
||||
self.notify_did_update_setting().await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_view_group(&self, params: DeleteGroupParams) -> FlowyResult<()> {
|
||||
pub async fn v_delete_group(&self, params: DeleteGroupParams) -> FlowyResult<()> {
|
||||
self
|
||||
.modify(|pad| {
|
||||
let changeset =
|
||||
@ -461,18 +461,18 @@ impl DatabaseViewEditor {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_view_setting(&self) -> DatabaseViewSettingPB {
|
||||
pub async fn v_get_setting(&self) -> DatabaseViewSettingPB {
|
||||
let field_revs = self.delegate.get_field_revs(None).await;
|
||||
make_database_view_setting(&*self.pad.read().await, &field_revs)
|
||||
}
|
||||
|
||||
pub async fn get_all_view_sorts(&self) -> Vec<Arc<SortRevision>> {
|
||||
pub async fn v_get_all_sorts(&self) -> Vec<Arc<SortRevision>> {
|
||||
let field_revs = self.delegate.get_field_revs(None).await;
|
||||
self.pad.read().await.get_all_sorts(&field_revs)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn insert_view_sort(&self, params: AlterSortParams) -> FlowyResult<SortRevision> {
|
||||
pub async fn v_insert_sort(&self, params: AlterSortParams) -> FlowyResult<SortRevision> {
|
||||
let sort_type = SortType::from(¶ms);
|
||||
let is_exist = params.sort_id.is_some();
|
||||
let sort_id = match params.sort_id {
|
||||
@ -514,7 +514,7 @@ impl DatabaseViewEditor {
|
||||
Ok(sort_rev)
|
||||
}
|
||||
|
||||
pub async fn delete_view_sort(&self, params: DeleteSortParams) -> FlowyResult<()> {
|
||||
pub async fn v_delete_sort(&self, params: DeleteSortParams) -> FlowyResult<()> {
|
||||
let notification = self
|
||||
.sort_controller
|
||||
.write()
|
||||
@ -537,8 +537,8 @@ impl DatabaseViewEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_all_view_sorts(&self) -> FlowyResult<()> {
|
||||
let all_sorts = self.get_all_view_sorts().await;
|
||||
pub async fn v_delete_all_sorts(&self) -> FlowyResult<()> {
|
||||
let all_sorts = self.v_get_all_sorts().await;
|
||||
self.sort_controller.write().await.delete_all_sorts().await;
|
||||
self
|
||||
.modify(|pad| {
|
||||
@ -556,12 +556,12 @@ impl DatabaseViewEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_all_view_filters(&self) -> Vec<Arc<FilterRevision>> {
|
||||
pub async fn v_get_all_filters(&self) -> Vec<Arc<FilterRevision>> {
|
||||
let field_revs = self.delegate.get_field_revs(None).await;
|
||||
self.pad.read().await.get_all_filters(&field_revs)
|
||||
}
|
||||
|
||||
pub async fn get_view_filters(&self, filter_type: &FilterType) -> Vec<Arc<FilterRevision>> {
|
||||
pub async fn v_get_filters(&self, filter_type: &FilterType) -> Vec<Arc<FilterRevision>> {
|
||||
let field_type_rev: FieldTypeRevision = filter_type.field_type.clone().into();
|
||||
self
|
||||
.pad
|
||||
@ -571,7 +571,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn insert_view_filter(&self, params: AlterFilterParams) -> FlowyResult<()> {
|
||||
pub async fn v_insert_filter(&self, params: AlterFilterParams) -> FlowyResult<()> {
|
||||
let filter_type = FilterType::from(¶ms);
|
||||
let is_exist = params.filter_id.is_some();
|
||||
let filter_id = match params.filter_id {
|
||||
@ -624,7 +624,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn delete_view_filter(&self, params: DeleteFilterParams) -> FlowyResult<()> {
|
||||
pub async fn v_delete_filter(&self, params: DeleteFilterParams) -> FlowyResult<()> {
|
||||
let filter_type = params.filter_type;
|
||||
let changeset = self
|
||||
.filter_controller
|
||||
@ -649,7 +649,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
/// Returns the current calendar settings
|
||||
pub async fn get_calendar_settings(&self) -> FlowyResult<CalendarSettingsParams> {
|
||||
pub async fn v_get_calendar_settings(&self) -> FlowyResult<CalendarSettingsParams> {
|
||||
let settings = self
|
||||
.pad
|
||||
.read()
|
||||
@ -660,7 +660,10 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
/// Update the calendar settings and send the notification to refresh the UI
|
||||
pub async fn update_calendar_settings(&self, params: CalendarSettingsParams) -> FlowyResult<()> {
|
||||
pub async fn v_update_calendar_settings(
|
||||
&self,
|
||||
params: CalendarSettingsParams,
|
||||
) -> FlowyResult<()> {
|
||||
// Maybe it needs no send notification to refresh the UI
|
||||
self
|
||||
.modify(|pad| Ok(pad.update_layout_setting(&LayoutRevision::Calendar, ¶ms)?))
|
||||
@ -669,7 +672,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub async fn did_update_view_field_type_option(
|
||||
pub async fn v_did_update_field_type_option(
|
||||
&self,
|
||||
field_id: &str,
|
||||
old_field_rev: Option<Arc<FieldRevision>>,
|
||||
@ -709,7 +712,7 @@ impl DatabaseViewEditor {
|
||||
/// * `field_id`:
|
||||
///
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
pub async fn group_by_view_field(&self, field_id: &str) -> FlowyResult<()> {
|
||||
pub async fn v_update_group_setting(&self, field_id: &str) -> FlowyResult<()> {
|
||||
if let Some(field_rev) = self.delegate.get_field_rev(field_id).await {
|
||||
let row_revs = self.delegate.get_row_revs(None).await;
|
||||
let configuration_reader = GroupConfigurationReaderImpl {
|
||||
@ -750,7 +753,7 @@ impl DatabaseViewEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_cells_for_field(
|
||||
pub(crate) async fn v_get_cells_for_field(
|
||||
&self,
|
||||
field_id: &str,
|
||||
) -> FlowyResult<Vec<RowSingleCellData>> {
|
||||
@ -758,7 +761,7 @@ impl DatabaseViewEditor {
|
||||
}
|
||||
|
||||
async fn notify_did_update_setting(&self) {
|
||||
let setting = self.get_view_setting().await;
|
||||
let setting = self.v_get_setting().await;
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateSettings)
|
||||
.payload(setting)
|
||||
.send();
|
||||
|
@ -84,8 +84,8 @@ impl DatabaseViews {
|
||||
.get_row_revs(Some(vec![block_id.to_owned()]))
|
||||
.await;
|
||||
if let Ok(view_editor) = self.get_view_editor(view_id).await {
|
||||
view_editor.filter_rows(block_id, &mut row_revs).await;
|
||||
view_editor.sort_rows(&mut row_revs).await;
|
||||
view_editor.v_filter_rows(block_id, &mut row_revs).await;
|
||||
view_editor.v_sort_rows(&mut row_revs).await;
|
||||
}
|
||||
|
||||
Ok(row_revs)
|
||||
@ -93,21 +93,21 @@ impl DatabaseViews {
|
||||
|
||||
pub async fn duplicate_database_view(&self, view_id: &str) -> FlowyResult<String> {
|
||||
let editor = self.get_view_editor(view_id).await?;
|
||||
let view_data = editor.duplicate_view_data().await?;
|
||||
let view_data = editor.v_duplicate_data().await?;
|
||||
Ok(view_data)
|
||||
}
|
||||
|
||||
/// When the row was created, we may need to modify the [RowRevision] according to the [CreateRowParams].
|
||||
pub async fn will_create_row(&self, row_rev: &mut RowRevision, params: &CreateRowParams) {
|
||||
for view_editor in self.view_editors.read().await.values() {
|
||||
view_editor.will_create_view_row(row_rev, params).await;
|
||||
view_editor.v_will_create_row(row_rev, params).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Notify the view that the row was created. For the moment, the view is just sending notifications.
|
||||
pub async fn did_create_row(&self, row_pb: &RowPB, params: &CreateRowParams) {
|
||||
for view_editor in self.view_editors.read().await.values() {
|
||||
view_editor.did_create_view_row(row_pb, params).await;
|
||||
view_editor.v_did_create_row(row_pb, params).await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ impl DatabaseViews {
|
||||
Some((_, row_rev)) => {
|
||||
for view_editor in self.view_editors.read().await.values() {
|
||||
view_editor
|
||||
.did_update_view_row(old_row_rev.clone(), &row_rev)
|
||||
.v_did_update_row(old_row_rev.clone(), &row_rev)
|
||||
.await;
|
||||
}
|
||||
},
|
||||
@ -129,24 +129,24 @@ impl DatabaseViews {
|
||||
|
||||
pub async fn group_by_field(&self, view_id: &str, field_id: &str) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
view_editor.group_by_view_field(field_id).await?;
|
||||
view_editor.v_update_group_setting(field_id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn did_delete_row(&self, row_rev: Arc<RowRevision>) {
|
||||
for view_editor in self.view_editors.read().await.values() {
|
||||
view_editor.did_delete_view_row(&row_rev).await;
|
||||
view_editor.v_did_delete_row(&row_rev).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_setting(&self, view_id: &str) -> FlowyResult<DatabaseViewSettingPB> {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
Ok(view_editor.get_view_setting().await)
|
||||
Ok(view_editor.v_get_setting().await)
|
||||
}
|
||||
|
||||
pub async fn get_all_filters(&self, view_id: &str) -> FlowyResult<Vec<Arc<FilterRevision>>> {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
Ok(view_editor.get_all_view_filters().await)
|
||||
Ok(view_editor.v_get_all_filters().await)
|
||||
}
|
||||
|
||||
pub async fn get_filters(
|
||||
@ -155,58 +155,58 @@ impl DatabaseViews {
|
||||
filter_id: &FilterType,
|
||||
) -> FlowyResult<Vec<Arc<FilterRevision>>> {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
Ok(view_editor.get_view_filters(filter_id).await)
|
||||
Ok(view_editor.v_get_filters(filter_id).await)
|
||||
}
|
||||
|
||||
pub async fn create_or_update_filter(&self, params: AlterFilterParams) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(¶ms.view_id).await?;
|
||||
view_editor.insert_view_filter(params).await
|
||||
view_editor.v_insert_filter(params).await
|
||||
}
|
||||
|
||||
pub async fn delete_filter(&self, params: DeleteFilterParams) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(¶ms.view_id).await?;
|
||||
view_editor.delete_view_filter(params).await
|
||||
view_editor.v_delete_filter(params).await
|
||||
}
|
||||
|
||||
pub async fn get_all_sorts(&self, view_id: &str) -> FlowyResult<Vec<Arc<SortRevision>>> {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
Ok(view_editor.get_all_view_sorts().await)
|
||||
Ok(view_editor.v_get_all_sorts().await)
|
||||
}
|
||||
|
||||
pub async fn create_or_update_sort(&self, params: AlterSortParams) -> FlowyResult<SortRevision> {
|
||||
let view_editor = self.get_view_editor(¶ms.view_id).await?;
|
||||
view_editor.insert_view_sort(params).await
|
||||
view_editor.v_insert_sort(params).await
|
||||
}
|
||||
|
||||
pub async fn delete_all_sorts(&self, view_id: &str) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
view_editor.delete_all_view_sorts().await
|
||||
view_editor.v_delete_all_sorts().await
|
||||
}
|
||||
|
||||
pub async fn delete_sort(&self, params: DeleteSortParams) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(¶ms.view_id).await?;
|
||||
view_editor.delete_view_sort(params).await
|
||||
view_editor.v_delete_sort(params).await
|
||||
}
|
||||
|
||||
pub async fn load_groups(&self, view_id: &str) -> FlowyResult<RepeatedGroupPB> {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
let groups = view_editor.load_view_groups().await?;
|
||||
let groups = view_editor.v_load_groups().await?;
|
||||
Ok(RepeatedGroupPB { items: groups })
|
||||
}
|
||||
|
||||
pub async fn insert_or_update_group(&self, params: InsertGroupParams) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(¶ms.view_id).await?;
|
||||
view_editor.initialize_new_group(params).await
|
||||
view_editor.v_initialize_new_group(params).await
|
||||
}
|
||||
|
||||
pub async fn delete_group(&self, params: DeleteGroupParams) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(¶ms.view_id).await?;
|
||||
view_editor.delete_view_group(params).await
|
||||
view_editor.v_delete_group(params).await
|
||||
}
|
||||
|
||||
pub async fn move_group(&self, params: MoveGroupParams) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(¶ms.view_id).await?;
|
||||
view_editor.move_view_group(params).await?;
|
||||
view_editor.v_move_group(params).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -224,7 +224,7 @@ impl DatabaseViews {
|
||||
let mut row_changeset = RowChangeset::new(row_rev.id.clone());
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
view_editor
|
||||
.move_view_group_row(
|
||||
.v_move_group_row(
|
||||
&row_rev,
|
||||
&mut row_changeset,
|
||||
&to_group_id,
|
||||
@ -246,20 +246,22 @@ impl DatabaseViews {
|
||||
///
|
||||
/// * `field_id`: the id of the field in current view
|
||||
///
|
||||
#[tracing::instrument(level = "trace", skip(self), err)]
|
||||
pub async fn did_update_view_field_type_option(
|
||||
#[tracing::instrument(level = "debug", skip(self, old_field_rev), err)]
|
||||
pub async fn did_update_field_type_option(
|
||||
&self,
|
||||
view_id: &str,
|
||||
field_id: &str,
|
||||
old_field_rev: Option<Arc<FieldRevision>>,
|
||||
) -> FlowyResult<()> {
|
||||
let view_editor = self.get_view_editor(view_id).await?;
|
||||
// If the id of the grouping field is equal to the updated field's id, then we need to
|
||||
// update the group setting
|
||||
if view_editor.group_id().await == field_id {
|
||||
view_editor.group_by_view_field(field_id).await?;
|
||||
view_editor.v_update_group_setting(field_id).await?;
|
||||
}
|
||||
|
||||
view_editor
|
||||
.did_update_view_field_type_option(field_id, old_field_rev)
|
||||
.v_did_update_field_type_option(field_id, old_field_rev)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@ -269,6 +271,7 @@ impl DatabaseViews {
|
||||
if let Some(editor) = self.view_editors.read().await.get(view_id) {
|
||||
return Ok(editor);
|
||||
}
|
||||
|
||||
tracing::trace!("{:p} create view:{} editor", self, view_id);
|
||||
let mut view_editors = self.view_editors.write().await;
|
||||
let editor = Arc::new(self.make_view_editor(view_id).await?);
|
||||
|
@ -26,7 +26,17 @@ use std::sync::Arc;
|
||||
/// * `configuration_reader`: a reader used to read the group configuration from disk
|
||||
/// * `configuration_writer`: as writer used to write the group configuration to disk
|
||||
///
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
#[tracing::instrument(
|
||||
level = "debug",
|
||||
skip(
|
||||
row_revs,
|
||||
configuration_reader,
|
||||
configuration_writer,
|
||||
grouping_field_rev
|
||||
),
|
||||
fields(grouping_field_id=%grouping_field_rev.id, grouping_field_type)
|
||||
err
|
||||
)]
|
||||
pub async fn make_group_controller<R, W>(
|
||||
view_id: String,
|
||||
grouping_field_rev: Arc<FieldRevision>,
|
||||
@ -39,6 +49,7 @@ where
|
||||
W: GroupConfigurationWriter,
|
||||
{
|
||||
let grouping_field_type: FieldType = grouping_field_rev.ty.into();
|
||||
tracing::Span::current().record("grouping_field_type", &format!("{}", grouping_field_type));
|
||||
|
||||
let mut group_controller: Box<dyn GroupController>;
|
||||
let configuration_reader = Arc::new(configuration_reader);
|
||||
@ -99,17 +110,31 @@ where
|
||||
Ok(group_controller)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
pub fn find_grouping_field(
|
||||
field_revs: &[Arc<FieldRevision>],
|
||||
_layout: &LayoutRevision,
|
||||
) -> Option<Arc<FieldRevision>> {
|
||||
let mut groupable_field_revs = field_revs
|
||||
.iter()
|
||||
.flat_map(|field_rev| {
|
||||
let field_type: FieldType = field_rev.ty.into();
|
||||
match field_type.can_be_group() {
|
||||
true => Some(field_rev.clone()),
|
||||
false => None,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<Arc<FieldRevision>>>();
|
||||
|
||||
if groupable_field_revs.is_empty() {
|
||||
// If there is not groupable fields then we use the primary field.
|
||||
field_revs
|
||||
.iter()
|
||||
.find(|field_rev| {
|
||||
let field_type: FieldType = field_rev.ty.into();
|
||||
field_type.can_be_group()
|
||||
})
|
||||
.find(|field_rev| field_rev.is_primary)
|
||||
.cloned()
|
||||
} else {
|
||||
Some(groupable_field_revs.remove(0))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a `default` group configuration for the [FieldRevision]
|
||||
|
@ -189,22 +189,35 @@ script = [
|
||||
]
|
||||
script_runner = "@duckscript"
|
||||
|
||||
[tasks.build-test-lib]
|
||||
[tasks.build_test_backend]
|
||||
category = "Build"
|
||||
dependencies = ["env_check"]
|
||||
run_task = { name = [
|
||||
"setup-test-crate-type",
|
||||
"build-test-backend",
|
||||
"compile_test_backend",
|
||||
"copy-to-sandbox-folder",
|
||||
"restore-test-crate-type",
|
||||
] }
|
||||
|
||||
[tasks.build-test-backend]
|
||||
mac_alias = "build-test-backend-default"
|
||||
windows_alias = "build-test-backend-widnows"
|
||||
linux_alias = "build-test-backend-default"
|
||||
[tasks.compile_test_backend]
|
||||
mac_alias = "compile_test_backend_default"
|
||||
windows_alias = "compile_test_backend_widnows"
|
||||
linux_alias = "compile_test_backend_default"
|
||||
|
||||
[tasks.build-test-backend-default]
|
||||
[tasks.compile_test_backend_default]
|
||||
private = true
|
||||
script = [
|
||||
"""
|
||||
cd rust-lib/
|
||||
rustup show
|
||||
echo RUST_LOG=${RUST_LOG} cargo build --package=dart-ffi --target ${TEST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||
RUST_LOG=${RUST_LOG} cargo build --package=dart-ffi --target ${TEST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||
cd ../
|
||||
""",
|
||||
]
|
||||
script_runner = "@shell"
|
||||
|
||||
[tasks.compile_test_backend_widnows]
|
||||
private = true
|
||||
script = [
|
||||
"""
|
||||
@ -217,19 +230,6 @@ script = [
|
||||
]
|
||||
script_runner = "@shell"
|
||||
|
||||
[tasks.build-test-backend-widnows]
|
||||
private = true
|
||||
script = [
|
||||
"""
|
||||
cd rust-lib/
|
||||
rustup show
|
||||
echo cargo build --package=dart-ffi --target ${TEST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||
RUST_LOG=${TEST_RUST_LOG} cargo build --package=dart-ffi --target ${TEST_COMPILE_TARGET} --features "${FLUTTER_DESKTOP_FEATURES}"
|
||||
cd ../
|
||||
""",
|
||||
]
|
||||
script_runner = "@shell"
|
||||
|
||||
[tasks.copy-to-sandbox-folder]
|
||||
mac_alias = "copy-to-sandbox-folder-default"
|
||||
windows_alias = "copy-to-sandbox-folder-windows"
|
||||
|
@ -1,29 +1,29 @@
|
||||
|
||||
[tasks.dart_unit_test]
|
||||
script = '''
|
||||
cargo make --profile test-macos dart_unit_test_inner
|
||||
cargo make --profile test-macos dart_unit_test_impl
|
||||
'''
|
||||
script_runner = "@shell"
|
||||
|
||||
[tasks.dart_unit_test.windows]
|
||||
script = '''
|
||||
cargo make --profile test-windows dart_unit_test_inner
|
||||
cargo make --profile test-windows dart_unit_test_impl
|
||||
'''
|
||||
script_runner = "@shell"
|
||||
|
||||
[tasks.dart_unit_test.linux]
|
||||
script = '''
|
||||
cargo make --profile test-linux dart_unit_test_inner
|
||||
cargo make --profile test-linux dart_unit_test_impl
|
||||
'''
|
||||
script_runner = "@shell"
|
||||
|
||||
[tasks.dart_unit_test_inner]
|
||||
env = { RUST_LOG = "info", TEST_RUST_LOG = "info" }
|
||||
dependencies = ["build-test-lib"]
|
||||
[tasks.dart_unit_test_impl]
|
||||
env = { RUST_LOG = "info" }
|
||||
dependencies = ["build_test_backend"]
|
||||
description = "Run flutter unit tests"
|
||||
script = '''
|
||||
cd appflowy_flutter
|
||||
flutter test --dart-define=RUST_LOG=${TEST_RUST_LOG} -j, --concurrency=1
|
||||
flutter test --dart-define=RUST_LOG=${RUST_LOG} -j, --concurrency=1
|
||||
'''
|
||||
|
||||
[tasks.rust_unit_test]
|
||||
|
@ -115,7 +115,7 @@ pub struct FieldRevision {
|
||||
#[serde(with = "indexmap::serde_seq")]
|
||||
pub type_options: IndexMap<String, String>,
|
||||
|
||||
#[serde(default = "DEFAULT_IS_PRIMARY")]
|
||||
#[serde(default = "DEFAULT_IS_PRIMARY_VALUE")]
|
||||
pub is_primary: bool,
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ impl AsRef<FieldRevision> for FieldRevision {
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_IS_PRIMARY: fn() -> bool = || false;
|
||||
const DEFAULT_IS_PRIMARY_VALUE: fn() -> bool = || false;
|
||||
|
||||
impl FieldRevision {
|
||||
pub fn new<T: Into<FieldTypeRevision>>(
|
||||
|
Loading…
Reference in New Issue
Block a user