瀏覽代碼

chore: per-view field settings (#3199)

* chore: field-setting entities-events-notifications

* chore: update field settings

* chore: add tests

* chore: add docs

* chore: use an enum for field visibility

* chore: clippy warnings

* fix: deps fields

* chore: collab merge main

* chore: collab ref

* test: fix tests

* fix: tauri bump collab rev
Richard Shiue 1 年之前
父節點
當前提交
f0e4f3db61
共有 29 個文件被更改,包括 737 次插入61 次删除
  1. 9 9
      frontend/appflowy_tauri/src-tauri/Cargo.toml
  2. 41 20
      frontend/rust-lib/Cargo.lock
  3. 8 8
      frontend/rust-lib/Cargo.toml
  4. 2 2
      frontend/rust-lib/flowy-database2/Cargo.toml
  5. 7 0
      frontend/rust-lib/flowy-database2/src/entities/field_entities.rs
  6. 118 0
      frontend/rust-lib/flowy-database2/src/entities/field_settings_entities.rs
  7. 19 0
      frontend/rust-lib/flowy-database2/src/entities/macros.rs
  8. 2 0
      frontend/rust-lib/flowy-database2/src/entities/mod.rs
  9. 34 0
      frontend/rust-lib/flowy-database2/src/event_handler.rs
  10. 12 0
      frontend/rust-lib/flowy-database2/src/event_map.rs
  11. 11 2
      frontend/rust-lib/flowy-database2/src/manager.rs
  12. 3 0
      frontend/rust-lib/flowy-database2/src/notification.rs
  13. 109 9
      frontend/rust-lib/flowy-database2/src/services/database/database_editor.rs
  14. 5 1
      frontend/rust-lib/flowy-database2/src/services/database_view/layout_deps.rs
  15. 43 3
      frontend/rust-lib/flowy-database2/src/services/database_view/view_editor.rs
  16. 47 0
      frontend/rust-lib/flowy-database2/src/services/field_settings/entities.rs
  17. 35 0
      frontend/rust-lib/flowy-database2/src/services/field_settings/field_settings.rs
  18. 42 0
      frontend/rust-lib/flowy-database2/src/services/field_settings/field_settings_builder.rs
  19. 7 0
      frontend/rust-lib/flowy-database2/src/services/field_settings/mod.rs
  20. 1 0
      frontend/rust-lib/flowy-database2/src/services/mod.rs
  21. 2 0
      frontend/rust-lib/flowy-database2/src/services/share/csv/import.rs
  22. 4 0
      frontend/rust-lib/flowy-database2/src/template.rs
  23. 2 0
      frontend/rust-lib/flowy-database2/tests/database/field_settings_test/mod.rs
  24. 104 0
      frontend/rust-lib/flowy-database2/tests/database/field_settings_test/script.rs
  25. 55 0
      frontend/rust-lib/flowy-database2/tests/database/field_settings_test/test.rs
  26. 3 4
      frontend/rust-lib/flowy-database2/tests/database/mock_data/board_mock_data.rs
  27. 4 1
      frontend/rust-lib/flowy-database2/tests/database/mock_data/calendar_mock_data.rs
  28. 7 2
      frontend/rust-lib/flowy-database2/tests/database/mock_data/grid_mock_data.rs
  29. 1 0
      frontend/rust-lib/flowy-database2/tests/database/mod.rs

+ 9 - 9
frontend/appflowy_tauri/src-tauri/Cargo.toml

@@ -34,15 +34,15 @@ default = ["custom-protocol"]
 custom-protocol = ["tauri/custom-protocol"]
 
 [patch.crates-io]
-collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-define = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
+collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-persistence = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-define = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
 
 #collab = { path = "../../../../AppFlowy-Collab/collab" }
 #collab-folder = { path = "../../../../AppFlowy-Collab/collab-folder" }

+ 41 - 20
frontend/rust-lib/Cargo.lock

@@ -120,7 +120,7 @@ checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
 [[package]]
 name = "appflowy-integrate"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "anyhow",
  "collab",
@@ -611,7 +611,7 @@ dependencies = [
 [[package]]
 name = "collab"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "anyhow",
  "bytes",
@@ -629,7 +629,7 @@ dependencies = [
 [[package]]
 name = "collab-client-ws"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "bytes",
  "collab-sync",
@@ -647,7 +647,7 @@ dependencies = [
 [[package]]
 name = "collab-database"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -664,6 +664,8 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_repr",
+ "strum",
+ "strum_macros 0.25.2",
  "thiserror",
  "tokio",
  "tokio-stream",
@@ -674,7 +676,7 @@ dependencies = [
 [[package]]
 name = "collab-define"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "uuid",
 ]
@@ -682,7 +684,7 @@ dependencies = [
 [[package]]
 name = "collab-derive"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -694,7 +696,7 @@ dependencies = [
 [[package]]
 name = "collab-document"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "anyhow",
  "collab",
@@ -713,7 +715,7 @@ dependencies = [
 [[package]]
 name = "collab-folder"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "anyhow",
  "chrono",
@@ -733,7 +735,7 @@ dependencies = [
 [[package]]
 name = "collab-persistence"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "bincode",
  "chrono",
@@ -753,7 +755,7 @@ dependencies = [
 [[package]]
 name = "collab-plugins"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -782,7 +784,7 @@ dependencies = [
 [[package]]
 name = "collab-sync"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "bytes",
  "collab",
@@ -804,7 +806,7 @@ dependencies = [
 [[package]]
 name = "collab-user"
 version = "0.1.0"
-source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=cff1b9#cff1b99f4ed51f65dab73492eac4da8e7907f079"
+source = "git+https://github.com/AppFlowy-IO/AppFlowy-Collab?rev=b1f6737#b1f67375e39c67e32c502b2968749bedf61d6a46"
 dependencies = [
  "anyhow",
  "collab",
@@ -1351,7 +1353,7 @@ dependencies = [
  "flowy-sqlite",
  "lib-dispatch",
  "protobuf",
- "strum_macros",
+ "strum_macros 0.21.1",
 ]
 
 [[package]]
@@ -1438,7 +1440,7 @@ dependencies = [
  "serde_json",
  "serde_repr",
  "strum",
- "strum_macros",
+ "strum_macros 0.25.2",
  "tokio",
  "tracing",
  "url",
@@ -1492,7 +1494,7 @@ dependencies = [
  "protobuf",
  "serde",
  "serde_json",
- "strum_macros",
+ "strum_macros 0.21.1",
  "tempfile",
  "tokio",
  "tokio-stream",
@@ -1571,7 +1573,7 @@ dependencies = [
  "nanoid",
  "parking_lot 0.12.1",
  "protobuf",
- "strum_macros",
+ "strum_macros 0.21.1",
  "tokio",
  "tokio-stream",
  "tracing",
@@ -1771,7 +1773,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_repr",
- "strum_macros",
+ "strum_macros 0.21.1",
  "tokio",
  "tracing",
  "unicode-segmentation",
@@ -2088,6 +2090,12 @@ dependencies = [
  "unicode-segmentation",
 ]
 
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
 [[package]]
 name = "hermit-abi"
 version = "0.2.6"
@@ -4210,9 +4218,9 @@ dependencies = [
 
 [[package]]
 name = "strum"
-version = "0.21.0"
+version = "0.25.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2"
+checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
 
 [[package]]
 name = "strum_macros"
@@ -4220,12 +4228,25 @@ version = "0.21.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec"
 dependencies = [
- "heck",
+ "heck 0.3.3",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "strum_macros"
+version = "0.25.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059"
+dependencies = [
+ "heck 0.4.1",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.27",
+]
+
 [[package]]
 name = "subtle"
 version = "2.4.1"

+ 8 - 8
frontend/rust-lib/Cargo.toml

@@ -39,14 +39,14 @@ opt-level = 3
 incremental = false
 
 [patch.crates-io]
-collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
-collab-define = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "cff1b9" }
+collab = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-folder = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-document = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-database = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+appflowy-integrate = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-plugins = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-user = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
+collab-define = { git = "https://github.com/AppFlowy-IO/AppFlowy-Collab", rev = "b1f6737" }
 
 #collab = { path = "../AppFlowy-Collab/collab" }
 #collab-folder = { path = "../AppFlowy-Collab/collab-folder" }

+ 2 - 2
frontend/rust-lib/flowy-database2/Cargo.toml

@@ -42,8 +42,8 @@ async-trait = "0.1"
 chrono-tz = "0.8.2"
 csv = "1.1.6"
 
-strum = "0.21"
-strum_macros = "0.21"
+strum = "0.25"
+strum_macros = "0.25"
 
 [dev-dependencies]
 flowy-test = { path = "../flowy-test", default-features = false }

+ 7 - 0
frontend/rust-lib/flowy-database2/src/entities/field_entities.rs

@@ -311,6 +311,13 @@ impl std::convert::From<String> for RepeatedFieldIdPB {
   }
 }
 
+impl From<Vec<String>> for RepeatedFieldIdPB {
+  fn from(value: Vec<String>) -> Self {
+    let field_ids = value.into_iter().map(FieldIdPB::from).collect();
+    RepeatedFieldIdPB { items: field_ids }
+  }
+}
+
 /// [TypeOptionChangesetPB] is used to update the type-option data.
 #[derive(ProtoBuf, Default)]
 pub struct TypeOptionChangesetPB {

+ 118 - 0
frontend/rust-lib/flowy-database2/src/entities/field_settings_entities.rs

@@ -0,0 +1,118 @@
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+use flowy_error::ErrorCode;
+use std::ops::Deref;
+
+use crate::entities::parser::NotEmptyStr;
+use crate::entities::RepeatedFieldIdPB;
+use crate::impl_into_field_visibility;
+use crate::services::field_settings::{FieldSettings, FieldSettingsChangesetParams};
+
+/// Defines the field settings for a field in a view.
+#[derive(Debug, Default, Clone, ProtoBuf)]
+pub struct FieldSettingsPB {
+  #[pb(index = 1)]
+  pub field_id: String,
+
+  #[pb(index = 2)]
+  pub visibility: FieldVisibility,
+}
+
+impl From<FieldSettings> for FieldSettingsPB {
+  fn from(value: FieldSettings) -> Self {
+    Self {
+      field_id: value.field_id,
+      visibility: value.visibility,
+    }
+  }
+}
+
+#[repr(u8)]
+#[derive(Debug, Default, Clone, ProtoBuf_Enum, PartialEq)]
+pub enum FieldVisibility {
+  #[default]
+  AlwaysShown = 0,
+  HideWhenEmpty = 1,
+  AlwaysHidden = 2,
+}
+
+impl_into_field_visibility!(i64);
+impl_into_field_visibility!(u8);
+
+impl From<FieldVisibility> for i64 {
+  fn from(value: FieldVisibility) -> Self {
+    (value as u8) as i64
+  }
+}
+
+#[derive(Debug, Default, Clone, ProtoBuf)]
+pub struct FieldIdsPB {
+  #[pb(index = 1)]
+  pub view_id: String,
+
+  #[pb(index = 2)]
+  pub field_ids: RepeatedFieldIdPB,
+}
+
+/// Defines a set of fields in a database view, identified by their `field_ids`
+pub struct FieldIdsParams {
+  pub view_id: String,
+  pub field_ids: Vec<String>,
+}
+
+impl TryInto<(String, Vec<String>)> for FieldIdsPB {
+  type Error = ErrorCode;
+
+  fn try_into(self) -> Result<(String, Vec<String>), Self::Error> {
+    let view_id = NotEmptyStr::parse(self.view_id)
+      .map_err(|_| ErrorCode::ViewIdIsInvalid)?
+      .0;
+    let field_ids = self
+      .field_ids
+      .deref()
+      .iter()
+      .map(|field_id| field_id.field_id.clone())
+      .collect();
+
+    Ok((view_id, field_ids))
+  }
+}
+
+#[derive(Debug, Default, Clone, ProtoBuf)]
+pub struct RepeatedFieldSettingsPB {
+  #[pb(index = 1)]
+  pub items: Vec<FieldSettingsPB>,
+}
+
+#[derive(Debug, Default, Clone, ProtoBuf)]
+pub struct FieldSettingsChangesetPB {
+  #[pb(index = 1)]
+  pub view_id: String,
+
+  #[pb(index = 2)]
+  pub field_id: String,
+
+  #[pb(index = 3, one_of)]
+  pub visibility: Option<FieldVisibility>,
+}
+
+impl From<FieldSettingsChangesetParams> for FieldSettingsChangesetPB {
+  fn from(value: FieldSettingsChangesetParams) -> Self {
+    Self {
+      view_id: value.view_id,
+      field_id: value.field_id,
+      visibility: value.visibility,
+    }
+  }
+}
+
+impl TryFrom<FieldSettingsChangesetPB> for FieldSettingsChangesetParams {
+  type Error = ErrorCode;
+
+  fn try_from(value: FieldSettingsChangesetPB) -> Result<Self, Self::Error> {
+    Ok(FieldSettingsChangesetParams {
+      view_id: value.view_id,
+      field_id: value.field_id,
+      visibility: value.visibility,
+    })
+  }
+}

+ 19 - 0
frontend/rust-lib/flowy-database2/src/entities/macros.rs

@@ -23,3 +23,22 @@ macro_rules! impl_into_field_type {
     }
   };
 }
+
+#[macro_export]
+macro_rules! impl_into_field_visibility {
+  ($target: ident) => {
+    impl std::convert::From<$target> for FieldVisibility {
+      fn from(ty: $target) -> Self {
+        match ty {
+          0 => FieldVisibility::AlwaysShown,
+          1 => FieldVisibility::HideWhenEmpty,
+          2 => FieldVisibility::AlwaysHidden,
+          _ => {
+            tracing::error!("🔴Can't parser FieldVisibility from value: {}", ty);
+            FieldVisibility::AlwaysShown
+          },
+        }
+      }
+    }
+  };
+}

+ 2 - 0
frontend/rust-lib/flowy-database2/src/entities/mod.rs

@@ -2,6 +2,7 @@ mod calendar_entities;
 mod cell_entities;
 mod database_entities;
 mod field_entities;
+mod field_settings_entities;
 pub mod filter_entities;
 mod group_entities;
 pub mod parser;
@@ -19,6 +20,7 @@ pub use calendar_entities::*;
 pub use cell_entities::*;
 pub use database_entities::*;
 pub use field_entities::*;
+pub use field_settings_entities::*;
 pub use filter_entities::*;
 pub use group_entities::*;
 pub use row_entities::*;

+ 34 - 0
frontend/rust-lib/flowy-database2/src/event_handler.rs

@@ -14,6 +14,7 @@ use crate::services::field::checklist_type_option::ChecklistCellChangeset;
 use crate::services::field::{
   type_option_data_from_pb_or_default, DateCellChangeset, SelectOptionCellChangeset,
 };
+use crate::services::field_settings::FieldSettingsChangesetParams;
 use crate::services::group::{GroupChangeset, GroupSettingChangeset};
 use crate::services::share::csv::CSVFormat;
 
@@ -891,3 +892,36 @@ pub(crate) async fn get_snapshots_handler(
   let snapshots = manager.get_database_snapshots(&view_id, 10).await?;
   data_result_ok(RepeatedDatabaseSnapshotPB { items: snapshots })
 }
+
+#[tracing::instrument(level = "debug", skip_all, err)]
+pub(crate) async fn get_field_settings_handler(
+  data: AFPluginData<FieldIdsPB>,
+  manager: AFPluginState<Weak<DatabaseManager>>,
+) -> DataResult<RepeatedFieldSettingsPB, FlowyError> {
+  let manager = upgrade_manager(manager)?;
+  let (view_id, field_ids) = data.into_inner().try_into()?;
+  let database_editor = manager.get_database_with_view_id(&view_id).await?;
+  let field_settings = database_editor
+    .get_field_settings(&view_id, field_ids)
+    .await?
+    .into_iter()
+    .map(FieldSettingsPB::from)
+    .collect::<Vec<FieldSettingsPB>>();
+  data_result_ok(RepeatedFieldSettingsPB {
+    items: field_settings,
+  })
+}
+
+#[tracing::instrument(level = "debug", skip_all, err)]
+pub(crate) async fn update_field_settings_handler(
+  data: AFPluginData<FieldSettingsChangesetPB>,
+  manager: AFPluginState<Weak<DatabaseManager>>,
+) -> FlowyResult<()> {
+  let manager = upgrade_manager(manager)?;
+  let params: FieldSettingsChangesetParams = data.into_inner().try_into()?;
+  let database_editor = manager.get_database_with_view_id(&params.view_id).await?;
+  database_editor
+    .update_field_settings_with_changeset(params)
+    .await?;
+  Ok(())
+}

+ 12 - 0
frontend/rust-lib/flowy-database2/src/event_map.rs

@@ -72,8 +72,12 @@ pub fn init(database_manager: Weak<DatabaseManager>) -> AFPlugin {
         .event(DatabaseEvent::SetLayoutSetting, set_layout_setting_handler)
         .event(DatabaseEvent::GetLayoutSetting, get_layout_setting_handler)
         .event(DatabaseEvent::CreateDatabaseView, create_database_view)
+        // Export
         .event(DatabaseEvent::ExportCSV, export_csv_handler)
         .event(DatabaseEvent::GetDatabaseSnapshots, get_snapshots_handler)
+        // Field settings
+        .event(DatabaseEvent::GetFieldSettings, get_field_settings_handler)
+        .event(DatabaseEvent::UpdateFieldSettings, update_field_settings_handler)
 }
 
 /// [DatabaseEvent] defines events that are used to interact with the Grid. You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/protobuf)
@@ -315,4 +319,12 @@ pub enum DatabaseEvent {
   /// Returns all the snapshots of the database view.
   #[event(input = "DatabaseViewIdPB", output = "RepeatedDatabaseSnapshotPB")]
   GetDatabaseSnapshots = 150,
+
+  /// Returns the field settings for the provided fields in the given view
+  #[event(input = "FieldIdsPB", output = "RepeatedFieldSettingsPB")]
+  GetFieldSettings = 160,
+
+  /// Updates the field settings for a field in the given view
+  #[event(input = "FieldSettingsChangesetPB")]
+  UpdateFieldSettings = 161,
 }

+ 11 - 2
frontend/rust-lib/flowy-database2/src/manager.rs

@@ -25,6 +25,9 @@ use crate::entities::{
 use crate::notification::{send_notification, DatabaseNotification};
 use crate::services::database::DatabaseEditor;
 use crate::services::database_view::DatabaseLayoutDepsResolver;
+use crate::services::field_settings::{
+  default_field_settings_by_layout, default_field_settings_by_layout_map,
+};
 use crate::services::share::csv::{CSVFormat, CSVImporter, ImportResult};
 
 pub trait DatabaseUser: Send + Sync {
@@ -249,12 +252,18 @@ impl DatabaseManager {
     database_view_id: String,
   ) -> FlowyResult<()> {
     let wdb = self.get_workspace_database().await?;
-    let mut params = CreateViewParams::new(database_id.clone(), database_view_id, name, layout);
+    let mut params = CreateViewParams::new(
+      database_id.clone(),
+      database_view_id,
+      name,
+      layout,
+      default_field_settings_by_layout(layout),
+    );
     if let Some(database) = wdb.get_database(&database_id).await {
       let (field, layout_setting) = DatabaseLayoutDepsResolver::new(database, layout)
         .resolve_deps_when_create_database_linked_view();
       if let Some(field) = field {
-        params = params.with_deps_fields(vec![field]);
+        params = params.with_deps_fields(vec![field], default_field_settings_by_layout_map())
       }
       if let Some(layout_setting) = layout_setting {
         params = params.with_layout_setting(layout_setting);

+ 3 - 0
frontend/rust-lib/flowy-database2/src/notification.rs

@@ -50,6 +50,8 @@ pub enum DatabaseNotification {
   DidMoveDatabaseViewToTrash = 84,
   DidUpdateDatabaseSyncUpdate = 85,
   DidUpdateDatabaseSnapshotState = 86,
+  // Trigger when the field setting is changed
+  DidUpdateFieldSettings = 87,
 }
 
 impl std::convert::From<DatabaseNotification> for i32 {
@@ -81,6 +83,7 @@ impl std::convert::From<i32> for DatabaseNotification {
       82 => DatabaseNotification::DidUpdateDatabaseLayout,
       83 => DatabaseNotification::DidDeleteDatabaseView,
       84 => DatabaseNotification::DidMoveDatabaseViewToTrash,
+      87 => DatabaseNotification::DidUpdateFieldSettings,
       _ => DatabaseNotification::Unknown,
     }
   }

+ 109 - 9
frontend/rust-lib/flowy-database2/src/services/database/database_editor.rs

@@ -27,6 +27,10 @@ use crate::services::field::{
   type_option_data_from_pb_or_default, type_option_to_pb, DateCellData, SelectOptionCellChangeset,
   SelectOptionIds, TypeOptionCellDataHandler, TypeOptionCellExt,
 };
+use crate::services::field_settings::{
+  default_field_settings_by_layout, default_field_settings_by_layout_map, FieldSettings,
+  FieldSettingsChangesetParams,
+};
 use crate::services::filter::Filter;
 use crate::services::group::{
   default_group_setting, GroupSetting, GroupSettingChangeset, RowChangeset,
@@ -474,15 +478,17 @@ impl DatabaseEditor {
       None => default_type_option_data_from_type(field_type),
       Some(type_option_data) => type_option_data_from_pb_or_default(type_option_data, field_type),
     };
-    let (index, field) =
-      self
-        .database
-        .lock()
-        .create_field_with_mut(view_id, name, field_type.into(), |field| {
-          field
-            .type_options
-            .insert(field_type.to_string(), type_option_data.clone());
-        });
+    let (index, field) = self.database.lock().create_field_with_mut(
+      view_id,
+      name,
+      field_type.into(),
+      |field| {
+        field
+          .type_options
+          .insert(field_type.to_string(), type_option_data.clone());
+      },
+      default_field_settings_by_layout_map(),
+    );
 
     let _ = self
       .notify_did_insert_database_field(field.clone(), index)
@@ -1101,6 +1107,35 @@ impl DatabaseEditor {
     Ok(csv)
   }
 
+  pub async fn get_field_settings(
+    &self,
+    view_id: &str,
+    field_ids: Vec<String>,
+  ) -> Result<Vec<FieldSettings>, anyhow::Error> {
+    let view = self.database_views.get_view_editor(view_id).await?;
+    view.v_get_field_settings(field_ids).await
+  }
+
+  pub async fn get_all_field_settings(
+    &self,
+    view_id: &str,
+  ) -> Result<Vec<FieldSettings>, anyhow::Error> {
+    let view = self.database_views.get_view_editor(view_id).await?;
+    view.v_get_all_field_settings().await
+  }
+
+  pub async fn update_field_settings_with_changeset(
+    &self,
+    params: FieldSettingsChangesetParams,
+  ) -> FlowyResult<()> {
+    let view = self.database_views.get_view_editor(&params.view_id).await?;
+    view
+      .v_update_field_settings(&params.view_id, &params.field_id, params.visibility)
+      .await?;
+
+    Ok(())
+  }
+
   fn get_auto_updated_fields(&self, view_id: &str) -> Vec<Field> {
     self
       .database
@@ -1188,6 +1223,7 @@ impl DatabaseViewData for DatabaseViewDataImpl {
           .type_options
           .insert(field_type.to_string(), type_option_data);
       },
+      default_field_settings_by_layout_map(),
     );
     to_fut(async move { field })
   }
@@ -1353,4 +1389,68 @@ impl DatabaseViewData for DatabaseViewDataImpl {
     TypeOptionCellExt::new_with_cell_data_cache(field, Some(self.cell_cache.clone()))
       .get_type_option_cell_data_handler(field_type)
   }
+
+  fn get_field_settings(
+    &self,
+    view_id: &str,
+    field_ids: Vec<String>,
+  ) -> Result<Vec<FieldSettings>, anyhow::Error> {
+    let field_settings_map = self
+      .database
+      .lock()
+      .get_field_settings(view_id, Some(field_ids));
+
+    let field_settings: Result<Vec<FieldSettings>, anyhow::Error> = field_settings_map
+      .into_iter()
+      .map(|(field_id, field_settings)| FieldSettings::try_from_anymap(field_id, field_settings))
+      .collect();
+
+    field_settings
+  }
+
+  fn get_all_field_settings(&self, view_id: &str) -> Result<Vec<FieldSettings>, anyhow::Error> {
+    let field_settings_map = self.database.lock().get_field_settings(view_id, None);
+
+    let field_settings: Result<Vec<FieldSettings>, anyhow::Error> = field_settings_map
+      .into_iter()
+      .map(|(field_id, field_settings)| FieldSettings::try_from_anymap(field_id, field_settings))
+      .collect();
+
+    field_settings
+  }
+
+  fn update_field_settings(
+    &self,
+    view_id: &str,
+    field_id: &str,
+    visibility: Option<FieldVisibility>,
+  ) {
+    let field_settings = self
+      .get_field_settings(view_id, vec![field_id.to_string()])
+      .ok();
+
+    let new_field_settings = match field_settings {
+      Some(field_settings) => {
+        let mut field_settings = field_settings.first().unwrap().clone();
+        field_settings.visibility = visibility.unwrap_or(field_settings.visibility);
+        field_settings
+      },
+      None => {
+        let layout_ty = self.get_layout_for_view(view_id);
+        let mut field_settings = FieldSettings::try_from_anymap(
+          field_id.to_string(),
+          default_field_settings_by_layout(layout_ty),
+        )
+        .unwrap();
+        field_settings.visibility = visibility.unwrap_or(field_settings.visibility);
+        field_settings
+      },
+    };
+
+    self.database.lock().update_field_settings(
+      view_id,
+      Some(vec![field_id.to_string()]),
+      new_field_settings,
+    )
+  }
 }

+ 5 - 1
frontend/rust-lib/flowy-database2/src/services/database_view/layout_deps.rs

@@ -5,6 +5,7 @@ use std::sync::Arc;
 
 use crate::entities::FieldType;
 use crate::services::field::{DateTypeOption, SingleSelectTypeOption};
+use crate::services::field_settings::default_field_settings_by_layout_map;
 use crate::services::setting::CalendarLayoutSetting;
 
 /// When creating a database, we need to resolve the dependencies of the views.
@@ -83,7 +84,10 @@ impl DatabaseLayoutDepsResolver {
             tracing::trace!("Create a new date field after layout type change");
             let field = self.create_date_field();
             let field_id = field.id.clone();
-            self.database.lock().create_field(field);
+            self
+              .database
+              .lock()
+              .create_field(field, default_field_settings_by_layout_map());
             field_id
           },
           Some(date_field) => date_field.id,

+ 43 - 3
frontend/rust-lib/flowy-database2/src/services/database_view/view_editor.rs

@@ -14,9 +14,9 @@ use lib_infra::future::Fut;
 
 use crate::entities::{
   CalendarEventPB, DatabaseLayoutMetaPB, DatabaseLayoutSettingPB, DeleteFilterParams,
-  DeleteGroupParams, DeleteSortParams, FieldType, GroupChangesPB, GroupPB, GroupRowsNotificationPB,
-  InsertedRowPB, LayoutSettingParams, RowMetaPB, RowsChangePB, SortChangesetNotificationPB, SortPB,
-  UpdateFilterParams, UpdateSortParams,
+  DeleteGroupParams, DeleteSortParams, FieldType, FieldVisibility, GroupChangesPB, GroupPB,
+  GroupRowsNotificationPB, InsertedRowPB, LayoutSettingParams, RowMetaPB, RowsChangePB,
+  SortChangesetNotificationPB, SortPB, UpdateFilterParams, UpdateSortParams,
 };
 use crate::notification::{send_notification, DatabaseNotification};
 use crate::services::cell::CellCache;
@@ -32,6 +32,7 @@ use crate::services::database_view::{
   DatabaseViewChangedNotifier, DatabaseViewChangedReceiverRunner,
 };
 use crate::services::field::TypeOptionCellDataHandler;
+use crate::services::field_settings::FieldSettings;
 use crate::services::filter::{
   Filter, FilterChangeset, FilterController, FilterType, UpdatedFilterType,
 };
@@ -123,6 +124,21 @@ pub trait DatabaseViewData: Send + Sync + 'static {
     field: &Field,
     field_type: &FieldType,
   ) -> Option<Box<dyn TypeOptionCellDataHandler>>;
+
+  fn get_field_settings(
+    &self,
+    view_id: &str,
+    field_ids: Vec<String>,
+  ) -> Result<Vec<FieldSettings>, anyhow::Error>;
+
+  fn get_all_field_settings(&self, view_id: &str) -> Result<Vec<FieldSettings>, anyhow::Error>;
+
+  fn update_field_settings(
+    &self,
+    view_id: &str,
+    field_id: &str,
+    visibility: Option<FieldVisibility>,
+  );
 }
 
 pub struct DatabaseViewEditor {
@@ -892,6 +908,30 @@ impl DatabaseViewEditor {
       .send();
   }
 
+  pub async fn v_get_field_settings(
+    &self,
+    field_ids: Vec<String>,
+  ) -> Result<Vec<FieldSettings>, anyhow::Error> {
+    self.delegate.get_field_settings(&self.view_id, field_ids)
+  }
+
+  pub async fn v_get_all_field_settings(&self) -> Result<Vec<FieldSettings>, anyhow::Error> {
+    self.delegate.get_all_field_settings(&self.view_id)
+  }
+
+  pub async fn v_update_field_settings(
+    &self,
+    view_id: &str,
+    field_id: &str,
+    visibility: Option<FieldVisibility>,
+  ) -> FlowyResult<()> {
+    self
+      .delegate
+      .update_field_settings(view_id, field_id, visibility);
+
+    Ok(())
+  }
+
   async fn mut_group_controller<F, T>(&self, f: F) -> Option<T>
   where
     F: FnOnce(&mut Box<dyn GroupController>, Arc<Field>) -> FlowyResult<T>,

+ 47 - 0
frontend/rust-lib/flowy-database2/src/services/field_settings/entities.rs

@@ -0,0 +1,47 @@
+use anyhow::bail;
+use collab::core::any_map::AnyMapExtension;
+use collab_database::views::{FieldSettingsMap, FieldSettingsMapBuilder};
+
+use crate::entities::FieldVisibility;
+
+/// Stores the field settings for a single field
+#[derive(Debug, Clone)]
+pub struct FieldSettings {
+  pub field_id: String,
+  pub visibility: FieldVisibility,
+}
+
+pub const VISIBILITY: &str = "visibility";
+
+impl FieldSettings {
+  pub fn try_from_anymap(
+    field_id: String,
+    field_settings: FieldSettingsMap,
+  ) -> Result<Self, anyhow::Error> {
+    let visibility = match field_settings.get_i64_value(VISIBILITY) {
+      Some(visbility) => visbility.into(),
+      _ => bail!("Invalid field settings data"),
+    };
+
+    Ok(Self {
+      field_id,
+      visibility,
+    })
+  }
+}
+
+impl From<FieldSettings> for FieldSettingsMap {
+  fn from(field_settings: FieldSettings) -> Self {
+    FieldSettingsMapBuilder::new()
+      .insert_i64_value(VISIBILITY, field_settings.visibility.into())
+      .build()
+  }
+}
+
+/// Contains the changeset to a field's settings.
+/// A `Some` value for constitutes a change in that particular setting
+pub struct FieldSettingsChangesetParams {
+  pub view_id: String,
+  pub field_id: String,
+  pub visibility: Option<FieldVisibility>,
+}

+ 35 - 0
frontend/rust-lib/flowy-database2/src/services/field_settings/field_settings.rs

@@ -0,0 +1,35 @@
+use std::collections::HashMap;
+
+use strum::IntoEnumIterator;
+
+use collab_database::views::{DatabaseLayout, FieldSettingsMap, FieldSettingsMapBuilder};
+
+use crate::{entities::FieldVisibility, services::field_settings::VISIBILITY};
+
+/// Creates a map of the database layout and the default field settings for fields
+/// in a view of that database layout
+pub fn default_field_settings_by_layout_map() -> HashMap<DatabaseLayout, FieldSettingsMap> {
+  let mut template = HashMap::new();
+  for layout_ty in DatabaseLayout::iter() {
+    template.insert(layout_ty, default_field_settings_by_layout(layout_ty));
+  }
+
+  template
+}
+
+/// Returns the default FieldSettingsMap for the given database layout
+pub fn default_field_settings_by_layout(layout_ty: DatabaseLayout) -> FieldSettingsMap {
+  let visibility = default_visibility(layout_ty);
+  FieldSettingsMapBuilder::new()
+    .insert_i64_value(VISIBILITY, visibility.into())
+    .build()
+}
+
+/// Returns the default visibility of a field for the given database layout
+pub fn default_visibility(layout_ty: DatabaseLayout) -> FieldVisibility {
+  match layout_ty {
+    DatabaseLayout::Grid => FieldVisibility::AlwaysShown,
+    DatabaseLayout::Board => FieldVisibility::HideWhenEmpty,
+    DatabaseLayout::Calendar => FieldVisibility::HideWhenEmpty,
+  }
+}

+ 42 - 0
frontend/rust-lib/flowy-database2/src/services/field_settings/field_settings_builder.rs

@@ -0,0 +1,42 @@
+use collab_database::views::DatabaseLayout;
+
+use crate::entities::FieldVisibility;
+
+use crate::services::field_settings::{default_visibility, FieldSettings};
+
+/// Helper struct to create a new field setting
+pub struct FieldSettingsBuilder {
+  field_settings: FieldSettings,
+}
+
+impl FieldSettingsBuilder {
+  pub fn new(field_id: &str) -> Self {
+    let field_settings = FieldSettings {
+      field_id: field_id.to_string(),
+      visibility: FieldVisibility::AlwaysShown,
+    };
+    Self { field_settings }
+  }
+
+  pub fn from_layout_type(field_id: &str, layout_ty: DatabaseLayout) -> Self {
+    let field_settings = FieldSettings {
+      field_id: field_id.to_string(),
+      visibility: default_visibility(layout_ty),
+    };
+    Self { field_settings }
+  }
+
+  pub fn field_id(mut self, field_id: &str) -> Self {
+    self.field_settings.field_id = field_id.to_string();
+    self
+  }
+
+  pub fn visibility(mut self, visibility: FieldVisibility) -> Self {
+    self.field_settings.visibility = visibility;
+    self
+  }
+
+  pub fn build(self) -> FieldSettings {
+    self.field_settings
+  }
+}

+ 7 - 0
frontend/rust-lib/flowy-database2/src/services/field_settings/mod.rs

@@ -0,0 +1,7 @@
+mod entities;
+mod field_settings;
+mod field_settings_builder;
+
+pub use entities::*;
+pub use field_settings::*;
+pub use field_settings_builder::*;

+ 1 - 0
frontend/rust-lib/flowy-database2/src/services/mod.rs

@@ -2,6 +2,7 @@ pub mod cell;
 pub mod database;
 pub mod database_view;
 pub mod field;
+pub mod field_settings;
 pub mod filter;
 pub mod group;
 pub mod setting;

+ 2 - 0
frontend/rust-lib/flowy-database2/src/services/share/csv/import.rs

@@ -9,6 +9,7 @@ use flowy_error::{FlowyError, FlowyResult};
 
 use crate::entities::FieldType;
 use crate::services::field::{default_type_option_data_from_type, CELL_DATA};
+use crate::services::field_settings::default_field_settings_by_layout;
 use crate::services::share::csv::CSVFormat;
 
 #[derive(Default)]
@@ -134,6 +135,7 @@ fn database_from_fields_and_rows(
     sorts: vec![],
     created_rows,
     fields,
+    field_settings: default_field_settings_by_layout(DatabaseLayout::Grid),
   }
 }
 

+ 4 - 0
frontend/rust-lib/flowy-database2/src/template.rs

@@ -7,6 +7,7 @@ use crate::services::cell::{insert_select_option_cell, insert_text_cell};
 use crate::services::field::{
   FieldBuilder, SelectOption, SelectOptionColor, SingleSelectTypeOption,
 };
+use crate::services::field_settings::default_field_settings_by_layout;
 use crate::services::setting::CalendarLayoutSetting;
 
 pub fn make_default_grid(view_id: &str, name: &str) -> CreateDatabaseParams {
@@ -41,6 +42,7 @@ pub fn make_default_grid(view_id: &str, name: &str) -> CreateDatabaseParams {
       CreateRowParams::new(gen_row_id()),
     ],
     fields: vec![text_field, single_select, checkbox_field],
+    field_settings: default_field_settings_by_layout(DatabaseLayout::Grid),
   }
 }
 
@@ -92,6 +94,7 @@ pub fn make_default_board(view_id: &str, name: &str) -> CreateDatabaseParams {
     sorts: vec![],
     created_rows: rows,
     fields: vec![text_field, single_select],
+    field_settings: default_field_settings_by_layout(DatabaseLayout::Board),
   }
 }
 
@@ -133,5 +136,6 @@ pub fn make_default_calendar(view_id: &str, name: &str) -> CreateDatabaseParams
     sorts: vec![],
     created_rows: vec![],
     fields: vec![text_field, date_field, multi_select_field],
+    field_settings: default_field_settings_by_layout(DatabaseLayout::Calendar),
   }
 }

+ 2 - 0
frontend/rust-lib/flowy-database2/tests/database/field_settings_test/mod.rs

@@ -0,0 +1,2 @@
+mod script;
+mod test;

+ 104 - 0
frontend/rust-lib/flowy-database2/tests/database/field_settings_test/script.rs

@@ -0,0 +1,104 @@
+use flowy_database2::entities::FieldVisibility;
+use flowy_database2::services::field_settings::FieldSettingsChangesetParams;
+
+use crate::database::database_editor::DatabaseEditorTest;
+
+pub enum FieldSettingsScript {
+  AssertFieldSettings {
+    field_id: String,
+    visibility: FieldVisibility,
+  },
+  AssertAllFieldSettings {
+    visibility: FieldVisibility,
+  },
+  UpdateFieldSettings {
+    field_id: String,
+    visibility: Option<FieldVisibility>,
+  },
+}
+
+pub struct FieldSettingsTest {
+  inner: DatabaseEditorTest,
+}
+
+impl FieldSettingsTest {
+  pub async fn new_grid() -> Self {
+    let inner = DatabaseEditorTest::new_grid().await;
+    Self { inner }
+  }
+
+  pub async fn new_board() -> Self {
+    let inner = DatabaseEditorTest::new_board().await;
+    Self { inner }
+  }
+
+  pub async fn new_calendar() -> Self {
+    let inner = DatabaseEditorTest::new_calendar().await;
+    Self { inner }
+  }
+
+  pub async fn run_scripts(&mut self, scripts: Vec<FieldSettingsScript>) {
+    for script in scripts {
+      self.run_script(script).await;
+    }
+  }
+
+  pub async fn run_script(&mut self, script: FieldSettingsScript) {
+    match script {
+      FieldSettingsScript::AssertFieldSettings {
+        field_id,
+        visibility,
+      } => {
+        let field_settings = self
+          .editor
+          .get_field_settings(&self.view_id, vec![field_id])
+          .await
+          .unwrap()
+          .first()
+          .unwrap()
+          .to_owned();
+
+        assert_eq!(field_settings.visibility, visibility)
+      },
+      FieldSettingsScript::AssertAllFieldSettings { visibility } => {
+        let field_settings = self
+          .editor
+          .get_all_field_settings(&self.view_id)
+          .await
+          .unwrap();
+
+        for field_settings in field_settings.into_iter() {
+          assert_eq!(field_settings.visibility, visibility)
+        }
+      },
+      FieldSettingsScript::UpdateFieldSettings {
+        field_id,
+        visibility,
+      } => {
+        let params = FieldSettingsChangesetParams {
+          view_id: self.view_id.clone(),
+          field_id,
+          visibility,
+        };
+        let _ = self
+          .editor
+          .update_field_settings_with_changeset(params)
+          .await;
+      },
+    }
+  }
+}
+
+impl std::ops::Deref for FieldSettingsTest {
+  type Target = DatabaseEditorTest;
+
+  fn deref(&self) -> &Self::Target {
+    &self.inner
+  }
+}
+
+impl std::ops::DerefMut for FieldSettingsTest {
+  fn deref_mut(&mut self) -> &mut Self::Target {
+    &mut self.inner
+  }
+}

+ 55 - 0
frontend/rust-lib/flowy-database2/tests/database/field_settings_test/test.rs

@@ -0,0 +1,55 @@
+use collab_database::views::DatabaseLayout;
+use flowy_database2::entities::FieldType;
+use flowy_database2::entities::FieldVisibility;
+use flowy_database2::services::field_settings::default_visibility;
+
+use crate::database::field_settings_test::script::FieldSettingsScript::*;
+use crate::database::field_settings_test::script::FieldSettingsTest;
+
+/// Check default field settings for grid, kanban and calendar
+#[tokio::test]
+async fn get_default_field_settings() {
+  let mut test = FieldSettingsTest::new_grid().await;
+  let visibility = default_visibility(DatabaseLayout::Grid);
+  let scripts = vec![AssertAllFieldSettings { visibility }];
+  test.run_scripts(scripts).await;
+
+  let mut test = FieldSettingsTest::new_board().await;
+  let visibility = default_visibility(DatabaseLayout::Board);
+  let scripts = vec![AssertAllFieldSettings { visibility }];
+  test.run_scripts(scripts).await;
+
+  let mut test = FieldSettingsTest::new_calendar().await;
+  let visibility = default_visibility(DatabaseLayout::Calendar);
+  let scripts = vec![AssertAllFieldSettings { visibility }];
+  test.run_scripts(scripts).await;
+}
+
+/// Update field settings for a field
+#[tokio::test]
+async fn update_field_settings_test() {
+  let mut test = FieldSettingsTest::new_grid().await;
+  let checkbox_field = test.get_first_field(FieldType::Checkbox);
+  let text_field = test.get_first_field(FieldType::RichText);
+  let visibility = default_visibility(DatabaseLayout::Grid);
+  let new_visibility = FieldVisibility::AlwaysHidden;
+
+  let scripts = vec![
+    AssertAllFieldSettings {
+      visibility: visibility.clone(),
+    },
+    UpdateFieldSettings {
+      field_id: checkbox_field.id.clone(),
+      visibility: Some(new_visibility.clone()),
+    },
+    AssertFieldSettings {
+      field_id: checkbox_field.id,
+      visibility: new_visibility,
+    },
+    AssertFieldSettings {
+      field_id: text_field.id,
+      visibility,
+    },
+  ];
+  test.run_scripts(scripts).await;
+}

+ 3 - 4
frontend/rust-lib/flowy-database2/tests/database/mock_data/board_mock_data.rs

@@ -1,9 +1,6 @@
-// #![allow(clippy::all)]
-// #![allow(dead_code)]
-// #![allow(unused_imports)]
-
 use collab_database::database::{gen_database_id, gen_database_view_id, gen_row_id, DatabaseData};
 use collab_database::views::{DatabaseLayout, DatabaseView};
+use flowy_database2::services::field_settings::default_field_settings_by_layout;
 use strum::IntoEnumIterator;
 
 use flowy_database2::entities::FieldType;
@@ -21,6 +18,7 @@ pub fn make_test_board() -> DatabaseData {
   let mut fields = vec![];
   let mut rows = vec![];
   // Iterate through the FieldType to create the corresponding Field.
+  let field_settings = default_field_settings_by_layout(DatabaseLayout::Board);
   for field_type in FieldType::iter() {
     match field_type {
       FieldType::RichText => {
@@ -238,6 +236,7 @@ pub fn make_test_board() -> DatabaseData {
     field_orders: vec![],
     created_at: 0,
     modified_at: 0,
+    field_settings,
   };
   DatabaseData { view, fields, rows }
 }

+ 4 - 1
frontend/rust-lib/flowy-database2/tests/database/mock_data/calendar_mock_data.rs

@@ -1,5 +1,6 @@
 use collab_database::database::{gen_database_id, gen_database_view_id, gen_row_id, DatabaseData};
 use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting, LayoutSettings};
+use flowy_database2::services::field_settings::default_field_settings_by_layout;
 use strum::IntoEnumIterator;
 
 use flowy_database2::entities::FieldType;
@@ -12,6 +13,8 @@ use crate::database::database_editor::TestRowBuilder;
 pub fn make_test_calendar() -> DatabaseData {
   let mut fields = vec![];
   let mut rows = vec![];
+  let field_settings = default_field_settings_by_layout(DatabaseLayout::Calendar);
+
   // text
   let text_field = FieldBuilder::from_field_type(FieldType::RichText)
     .name("Name")
@@ -25,7 +28,6 @@ pub fn make_test_calendar() -> DatabaseData {
     .name("Date")
     .visibility(true)
     .build();
-
   let date_field_id = date_field.id.clone();
   fields.push(date_field);
 
@@ -120,6 +122,7 @@ pub fn make_test_calendar() -> DatabaseData {
     field_orders: vec![],
     created_at: 0,
     modified_at: 0,
+    field_settings,
   };
 
   DatabaseData { view, fields, rows }

+ 7 - 2
frontend/rust-lib/flowy-database2/tests/database/mock_data/grid_mock_data.rs

@@ -1,5 +1,6 @@
 use collab_database::database::{gen_database_id, gen_database_view_id, gen_row_id, DatabaseData};
 use collab_database::views::{DatabaseLayout, DatabaseView};
+use flowy_database2::services::field_settings::default_field_settings_by_layout;
 use strum::IntoEnumIterator;
 
 use flowy_database2::entities::FieldType;
@@ -15,6 +16,7 @@ use crate::database::mock_data::{COMPLETED, FACEBOOK, GOOGLE, PAUSED, PLANNED, T
 pub fn make_test_grid() -> DatabaseData {
   let mut fields = vec![];
   let mut rows = vec![];
+  let field_settings = default_field_settings_by_layout(DatabaseLayout::Grid);
   // Iterate through the FieldType to create the corresponding Field.
   for field_type in FieldType::iter() {
     match field_type {
@@ -238,10 +240,11 @@ pub fn make_test_grid() -> DatabaseData {
   }
 
   let view = DatabaseView {
-    id: gen_database_view_id(),
-    database_id: gen_database_id(),
+    id: gen_database_id(),
+    database_id: gen_database_view_id(),
     name: "".to_string(),
     layout: DatabaseLayout::Grid,
+    field_settings,
     ..Default::default()
   };
 
@@ -251,6 +254,7 @@ pub fn make_test_grid() -> DatabaseData {
 pub fn make_no_date_test_grid() -> DatabaseData {
   let mut fields = vec![];
   let mut rows = vec![];
+  let field_settings = default_field_settings_by_layout(DatabaseLayout::Grid);
   // Iterate through the FieldType to create the corresponding Field.
   for field_type in FieldType::iter() {
     match field_type {
@@ -319,6 +323,7 @@ pub fn make_no_date_test_grid() -> DatabaseData {
     database_id: gen_database_id(),
     name: "".to_string(),
     layout: DatabaseLayout::Grid,
+    field_settings,
     ..Default::default()
   };
 

+ 1 - 0
frontend/rust-lib/flowy-database2/tests/database/mod.rs

@@ -1,6 +1,7 @@
 mod block_test;
 mod cell_test;
 mod database_editor;
+mod field_settings_test;
 mod field_test;
 mod filter_test;
 mod group_test;