diff --git a/libs/shared-entity/src/dto/workspace_dto.rs b/libs/shared-entity/src/dto/workspace_dto.rs index fd335e73..84ca4708 100644 --- a/libs/shared-entity/src/dto/workspace_dto.rs +++ b/libs/shared-entity/src/dto/workspace_dto.rs @@ -368,10 +368,11 @@ pub struct AFDatabaseRowDetail { pub cells: HashMap>, } -#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct AFDatabaseField { pub id: String, pub name: String, pub field_type: String, + pub type_option: HashMap, pub is_primary: bool, } diff --git a/src/biz/collab/ops.rs b/src/biz/collab/ops.rs index 171d9063..3a41b80d 100644 --- a/src/biz/collab/ops.rs +++ b/src/biz/collab/ops.rs @@ -503,10 +503,12 @@ pub async fn get_database_fields( let all_fields = db_body.fields.get_all_fields(&db_collab.transact()); let mut acc = Vec::with_capacity(all_fields.len()); for field in all_fields { + let field_type = FieldType::from(field.field_type); acc.push(AFDatabaseField { id: field.id, name: field.name, - field_type: format!("{:?}", FieldType::from(field.field_type)), + field_type: format!("{:?}", field_type), + type_option: type_options_serde(&field.type_options, &field_type), is_primary: field.is_primary, }); } @@ -805,3 +807,31 @@ pub fn collab_from_doc_state(doc_state: Vec, object_id: &str) -> Result HashMap { + let type_option = match type_options.get(&field_type.type_id()) { + Some(type_option) => type_option, + None => return HashMap::new(), + }; + + let mut result = HashMap::with_capacity(type_option.len()); + for (key, value) in type_option { + match field_type { + FieldType::SingleSelect | FieldType::MultiSelect => { + if let yrs::Any::String(arc_str) = value { + if let Ok(serde_value) = serde_json::from_str::(&arc_str) { + result.insert(key.clone(), serde_value); + } + } + }, + _ => { + result.insert(key.clone(), serde_json::to_value(value).unwrap_or_default()); + }, + } + } + + result +} diff --git a/tests/workspace/workspace_crud.rs b/tests/workspace/workspace_crud.rs index 91dbe50d..c094a7a8 100644 --- a/tests/workspace/workspace_crud.rs +++ b/tests/workspace/workspace_crud.rs @@ -1,6 +1,9 @@ +use std::collections::HashMap; + use client_api_test::generate_unique_registered_user_client; use collab_entity::CollabType; use database_entity::dto::QueryCollabParams; +use serde_json::json; use shared_entity::dto::workspace_dto::AFDatabaseField; use shared_entity::dto::workspace_dto::CreateWorkspaceParam; use shared_entity::dto::workspace_dto::PatchWorkspaceParam; @@ -30,42 +33,94 @@ async fn workspace_list_database() { .get_database_fields(&workspace_id, &todos_db.id) .await .unwrap(); - db_fields.sort(); + // convert to hashset to check for equeality + let actual = db_fields.sort_by(|a, b| a.id.cmp(&b.id)); let expected = vec![ AFDatabaseField { - id: "3AE6iK".to_string(), - name: "Last modified".to_string(), - field_type: "LastEditedTime".to_string(), - is_primary: false, - }, - AFDatabaseField { - id: "KinVda".to_string(), - name: "Tasks".to_string(), - field_type: "Checklist".to_string(), + id: "wdX8DG".to_string(), + name: "Multiselect".to_string(), + field_type: "MultiSelect".to_string(), + type_option: { + let mut options = HashMap::new(); + options.insert( + "content".to_string(), + json!({ + "disable_color": false, + "options": [ + {"color": "Purple", "id": "4PDn", "name": "get things done"}, + {"color": "Blue", "id": "Bpyg", "name": "self-host"}, + {"color": "Aqua", "id": "GOQj", "name": "open source"}, + {"color": "Green", "id": "BD-T", "name": "looks great"}, + {"color": "Lime", "id": "6UxM", "name": "fast"}, + {"color": "Yellow", "id": "g2Uq", "name": "Claude 3"}, + {"color": "Orange", "id": "Tt-J", "name": "GPT-4o"}, + {"color": "LightPink", "id": "5QDY", "name": "Q&A"}, + {"color": "Pink", "id": "XYUx", "name": "news"}, + {"color": "Purple", "id": "hoZx", "name": "social"}, + ], + }), + ); + options + }, is_primary: false, }, AFDatabaseField { id: "SqwRg1".to_string(), name: "Status".to_string(), field_type: "SingleSelect".to_string(), + type_option: { + let mut options = HashMap::new(); + options.insert( + "content".to_string(), + json!({ + "disable_color": false, + "options": [ + {"color": "Purple", "id": "CEZD", "name": "To Do"}, + {"color": "Orange", "id": "TznH", "name": "Doing"}, + {"color": "Yellow", "id": "__n6", "name": "✅ Done"}, + ], + }), + ); + options + }, is_primary: false, }, AFDatabaseField { id: "phVRgL".to_string(), name: "Description".to_string(), field_type: "RichText".to_string(), + type_option: { + let mut options = HashMap::new(); + options.insert("data".to_string(), json!("")); + options + }, is_primary: true, }, AFDatabaseField { - id: "wdX8DG".to_string(), - name: "Multiselect".to_string(), - field_type: "MultiSelect".to_string(), + id: "KinVda".to_string(), + name: "Tasks".to_string(), + field_type: "Checklist".to_string(), + type_option: HashMap::new(), is_primary: false, }, - ]; - - assert_eq!(db_fields, expected, "{:#?}", db_fields); + AFDatabaseField { + id: "3AE6iK".to_string(), + name: "Last modified".to_string(), + field_type: "LastEditedTime".to_string(), + type_option: { + let mut options = HashMap::new(); + options.insert("date_format".to_string(), json!(3)); + options.insert("field_type".to_string(), json!(8)); + options.insert("include_time".to_string(), json!(true)); + options.insert("time_format".to_string(), json!(1)); + options + }, + is_primary: false, + }, + ] + .sort_by(|a, b| a.id.cmp(&b.id)); + assert_eq!(actual, expected, "{:#?}", db_fields); } { let db_row_ids = c