diff --git a/app/web/src/components/AttributesPanel/TreeFormItem.vue b/app/web/src/components/AttributesPanel/TreeFormItem.vue index b0d11c6600..49061efd83 100644 --- a/app/web/src/components/AttributesPanel/TreeFormItem.vue +++ b/app/web/src/components/AttributesPanel/TreeFormItem.vue @@ -401,7 +401,10 @@ name="nested-arrow-right" size="none" /> +
@@ -944,6 +947,7 @@ export type TreeFormProp = { widgetKind: PropertyEditorPropWidgetKind; isHidden: boolean; isReadonly: boolean; + documentation?: string; }; export type TreeFormData = { @@ -1058,6 +1062,7 @@ const widgetOptions = computed( () => (fullPropDef.value.widgetKind as any).options, ); const propName = computed(() => fullPropDef.value.name); +const propDocumentation = computed(() => fullPropDef.value.documentation); const propLabelParts = computed(() => { if (isChildOfArray.value) return [`${propName.value}[${props.treeDef.arrayIndex}]`]; diff --git a/lib/dal/src/pkg/import.rs b/lib/dal/src/pkg/import.rs index ae51c57228..0a58d28905 100644 --- a/lib/dal/src/pkg/import.rs +++ b/lib/dal/src/pkg/import.rs @@ -1628,6 +1628,7 @@ async fn create_dal_prop( kind, data.hidden, data.doc_link.as_ref().map(|l| l.to_string()), + data.documentation.clone(), Some(((&data.widget_kind).into(), data.widget_options.to_owned())), data.validation_format.clone(), parent_info.prop_id, @@ -1640,6 +1641,7 @@ async fn create_dal_prop( kind, data.hidden, data.doc_link.as_ref().map(|l| l.to_string()), + data.documentation.clone(), Some(((&data.widget_kind).into(), data.widget_options.to_owned())), data.validation_format.clone(), schema_variant_id, diff --git a/lib/dal/src/prop.rs b/lib/dal/src/prop.rs index d96af9e289..359a84b0e4 100644 --- a/lib/dal/src/prop.rs +++ b/lib/dal/src/prop.rs @@ -404,6 +404,7 @@ impl Prop { None, None, None, + None, parent_prop_id, ) .await @@ -420,6 +421,7 @@ impl Prop { kind: PropKind, hidden: bool, doc_link: Option, + documentation: Option, widget_kind_and_options: Option<(WidgetKind, Option)>, validation_format: Option, parent_prop_id: PropId, @@ -430,6 +432,7 @@ impl Prop { kind, hidden, doc_link, + documentation, widget_kind_and_options, validation_format, ) @@ -449,6 +452,7 @@ impl Prop { kind: PropKind, hidden: bool, doc_link: Option, + documentation: Option, widget_kind_and_options: Option<(WidgetKind, Option)>, validation_format: Option, schema_variant_id: SchemaVariantId, @@ -459,6 +463,7 @@ impl Prop { kind, hidden, doc_link, + documentation, widget_kind_and_options, validation_format, ) @@ -481,12 +486,14 @@ impl Prop { /// /// A corresponding [`AttributePrototype`] and [`AttributeValue`] will be created when the /// provided [`SchemaVariant`] is [`finalized`](SchemaVariant::finalize). + #[allow(clippy::too_many_arguments)] async fn new_inner( ctx: &DalContext, name: impl Into, kind: PropKind, hidden: bool, doc_link: Option, + documentation: Option, widget_kind_and_options: Option<(WidgetKind, Option)>, validation_format: Option, ) -> PropResult { @@ -513,7 +520,7 @@ impl Prop { widget_kind, widget_options, doc_link, - documentation: None, + documentation, hidden, refers_to_prop_id: None, diff_func_id: None, diff --git a/lib/dal/src/schema/variant/root_prop.rs b/lib/dal/src/schema/variant/root_prop.rs index eaa8ec1364..bbb0124abd 100644 --- a/lib/dal/src/schema/variant/root_prop.rs +++ b/lib/dal/src/schema/variant/root_prop.rs @@ -123,6 +123,7 @@ impl RootProp { None, None, None, + None, schema_variant_id, ) .await?; @@ -154,6 +155,7 @@ impl RootProp { None, None, None, + None, root_prop_id, ) .await?; @@ -191,6 +193,7 @@ impl RootProp { None, None, None, + None, root_prop_id, ) .await?; @@ -203,6 +206,7 @@ impl RootProp { None, None, None, + None, leaf_prop.id(), ) .await?; @@ -231,6 +235,7 @@ impl RootProp { PropKind::String, false, None, + None, Some(( WidgetKind::Select, Some(serde_json::json!([ @@ -264,6 +269,7 @@ impl RootProp { PropKind::String, false, None, + None, Some((WidgetKind::Color, None)), None, si_prop.id(), @@ -287,6 +293,7 @@ impl RootProp { None, None, None, + None, root_prop_id, ) .await?; @@ -300,6 +307,7 @@ impl RootProp { None, None, None, + None, resource_prop.id(), ) .await?; @@ -313,6 +321,7 @@ impl RootProp { None, None, None, + None, resource_prop.id(), ) .await?; @@ -326,6 +335,7 @@ impl RootProp { None, None, None, + None, resource_prop.id(), ) .await?; @@ -339,6 +349,7 @@ impl RootProp { None, None, None, + None, resource_prop.id(), ) .await?; @@ -358,6 +369,7 @@ impl RootProp { None, None, None, + None, root_prop_id, ) .await?; @@ -377,6 +389,7 @@ impl RootProp { None, None, None, + None, code_map_item_prop_id, ) .await?; @@ -389,6 +402,7 @@ impl RootProp { None, None, None, + None, code_map_item_prop_id, ) .await?; @@ -411,6 +425,7 @@ impl RootProp { None, None, None, + None, qualification_map_item_prop_id, ) .await?; @@ -423,6 +438,7 @@ impl RootProp { None, None, None, + None, qualification_map_item_prop_id, ) .await?; diff --git a/lib/dal/tests/integration_test/prop.rs b/lib/dal/tests/integration_test/prop.rs index 7d3ee57e2a..574d695689 100644 --- a/lib/dal/tests/integration_test/prop.rs +++ b/lib/dal/tests/integration_test/prop.rs @@ -1,5 +1,9 @@ -use dal::{prop::PropPath, DalContext, Prop, Schema, SchemaVariant}; -use dal_test::test; +use dal::{ + prop::PropPath, property_editor::schema::PropertyEditorSchema, + schema::variant::authoring::VariantAuthoringClient, ComponentType, DalContext, Prop, Schema, + SchemaVariant, +}; +use dal_test::{helpers::ChangeSetTestHelpers, test}; use pretty_assertions_sorted::assert_eq; #[test] @@ -152,3 +156,196 @@ async fn ordered_child_props(ctx: &DalContext) { ordered_child_prop_names // actual ); } + +#[test] +async fn prop_documentation(ctx: &mut DalContext) { + let name = "Toto Wolff"; + let description = None; + let link = None; + let category = "Mercedes AMG Petronas"; + let color = "#00A19B"; + + // Create an asset with a corresponding asset func. After that, commit. + let schema_variant_id = { + let schema_variant = VariantAuthoringClient::create_schema_and_variant( + ctx, + name, + description.clone(), + link.clone(), + category, + color, + ) + .await + .expect("unable to create schema and variant"); + schema_variant.id() + }; + let asset_func = "function main() { + const asset = new AssetBuilder(); + + const alpha_source_prop = new PropBuilder() + .setName(\"alpha_source_prop\") + .setKind(\"string\") + .setWidget(new PropWidgetDefinitionBuilder().setKind(\"text\").build()) + .build(); + asset.addProp(alpha_source_prop); + + const alpha_destination_prop = new PropBuilder() + .setName(\"alpha_destination_prop\") + .setKind(\"string\") + .setWidget(new PropWidgetDefinitionBuilder().setKind(\"text\").build()) + .build(); + asset.addProp(alpha_destination_prop); + + const beta_source_prop = new PropBuilder() + .setName(\"beta_source_prop\") + .setKind(\"string\") + .setDocumentation(\"sweet docs yo\") + .setWidget(new PropWidgetDefinitionBuilder().setKind(\"text\").build()) + .build(); + asset.addProp(beta_source_prop); + + const beta_destination_output_socket = new SocketDefinitionBuilder() + .setName(\"beta_destination_output_socket\") + .setArity(\"one\") + .build(); + asset.addOutputSocket(beta_destination_output_socket); + + return asset.build(); + }"; + VariantAuthoringClient::save_variant_content( + ctx, + schema_variant_id, + name, + name, + category, + description.clone(), + link.clone(), + color, + ComponentType::Component, + Some(asset_func), + ) + .await + .expect("could not save content"); + ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) + .await + .expect("could not commit"); + + // Once it's all ready, regenerate and commit. + let schema_variant_id = VariantAuthoringClient::regenerate_variant(ctx, schema_variant_id) + .await + .expect("could not regenerate variant"); + ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) + .await + .expect("could not commit"); + + // Assemble property editor schema and ensure Prop Documentation is there. + let property_editor_schema = PropertyEditorSchema::assemble(ctx, schema_variant_id) + .await + .expect("could not assemble property editor schema"); + + let prop = property_editor_schema + .props + .values() + .find(|schema| schema.name == "beta_source_prop") + .expect("could not find prop"); + + assert_eq!( + prop.documentation.as_ref().expect("has documentation"), + "sweet docs yo" + ); + + // now let's add documentation for the other prop, regenerate, and make sure everything works + + let asset_func = "function main() { + const asset = new AssetBuilder(); + + const alpha_source_prop = new PropBuilder() + .setName(\"alpha_source_prop\") + .setKind(\"string\") + .setWidget(new PropWidgetDefinitionBuilder().setKind(\"text\").build()) + .build(); + asset.addProp(alpha_source_prop); + + const alpha_destination_prop = new PropBuilder() + .setName(\"alpha_destination_prop\") + .setKind(\"string\") + .setDocumentation(\"more cool docs!\") + .setWidget(new PropWidgetDefinitionBuilder().setKind(\"text\").build()) + .build(); + asset.addProp(alpha_destination_prop); + + const beta_source_prop = new PropBuilder() + .setName(\"beta_source_prop\") + .setKind(\"string\") + .setDocumentation(\"sweet docs yo\") + .setWidget(new PropWidgetDefinitionBuilder().setKind(\"text\").build()) + .build(); + asset.addProp(beta_source_prop); + + const beta_destination_output_socket = new SocketDefinitionBuilder() + .setName(\"beta_destination_output_socket\") + .setArity(\"one\") + .build(); + asset.addOutputSocket(beta_destination_output_socket); + + return asset.build(); + }"; + VariantAuthoringClient::save_variant_content( + ctx, + schema_variant_id, + name, + name, + category, + description, + link, + color, + ComponentType::Component, + Some(asset_func), + ) + .await + .expect("could not save content"); + ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) + .await + .expect("could not commit"); + + // Once it's all ready, regenerate and commit. + let schema_variant_id = VariantAuthoringClient::regenerate_variant(ctx, schema_variant_id) + .await + .expect("could not regenerate variant"); + ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) + .await + .expect("could not commit"); + + // Assemble property editor schema and ensure both Prop Documentation is there. + let property_editor_schema = PropertyEditorSchema::assemble(ctx, schema_variant_id) + .await + .expect("could not assemble property editor schema"); + + let first_prop = property_editor_schema + .props + .values() + .find(|schema| schema.name == "beta_source_prop") + .expect("could not find prop"); + + assert_eq!( + first_prop + .documentation + .as_ref() + .expect("has documentation"), + "sweet docs yo" + ); + + let second_prop = property_editor_schema + .props + .values() + .find(|schema| schema.name == "alpha_destination_prop") + .expect("could not find prop"); + + assert_eq!( + second_prop + .documentation + .as_ref() + .expect("has documentation"), + "more cool docs!" + ); +}