From 5492464fc28f06038026a2bfa6391f4b287a4796 Mon Sep 17 00:00:00 2001
From: Paul Vaneveld
Date: Thu, 11 Jul 2024 16:02:22 +0200
Subject: [PATCH] fix: several
* add serialize functions
* adjust model to match actual api request
* add an example
---
.../resources/storyblok_component/resource.tf | 122 +++++++++++++-----
internal/component_model.go | 85 +++++++++---
internal/component_resource.go | 21 ++-
3 files changed, 177 insertions(+), 51 deletions(-)
diff --git a/examples/resources/storyblok_component/resource.tf b/examples/resources/storyblok_component/resource.tf
index 183c3b4..ee30012 100644
--- a/examples/resources/storyblok_component/resource.tf
+++ b/examples/resources/storyblok_component/resource.tf
@@ -24,62 +24,126 @@ resource "storyblok_component" "banner" {
// advanced example
resource "storyblok_component" "advanced_component" {
- name = "advanced-component"
- space_id = ""
- is_root = true
+ name = "advanced-component"
+ space_id = ""
+ is_root = true
is_nestable = false
schema = {
title = {
- type = "text"
- position = 1
- required = true // The field is required. Default is false.
- max_length = 200 // Set the max length of the input string
+ type = "text"
+ position = 1
+ required = true // The field is required. Default is false.
+ max_length = 200 // Set the max length of the input string
description = "Title of the component" // Description shown in the editor interface
}
introduction = {
- type = "rich_text"
- position = 2
+ type = "rich_text"
+ position = 2
rich_markdown = true // Enable rich markdown view by default
- description = "Introduction text with rich text editor"
+ description = "Introduction text with rich text editor"
}
image = {
- type = "image"
- position = 3
- asset_folder_id = 1 // Default asset folder numeric id to store uploaded image of that field
- add_https = true // Prepends https: to stop usage of relative protocol
- image_crop = true // Activate force crop for images
+ type = "image"
+ position = 3
+ asset_folder_id = 1 // Default asset folder numeric id to store uploaded image of that field
+ add_https = true // Prepends https: to stop usage of relative protocol
+ image_crop = true // Activate force crop for images
}
release_date = {
- type = "date"
- position = 4
+ type = "date"
+ position = 4
disable_time = true // Disables time selection from date picker
- description = "Release date of the content"
+ description = "Release date of the content"
}
tags = {
- type = "multi_option"
- position = 5
+ type = "multi_option"
+ position = 5
datasource_slug = "tags" // Define selectable datasources string
- description = "Tags for the component"
+ description = "Tags for the component"
}
rating = {
- type = "number"
- position = 6
- description = "Rating of the content"
+ type = "number"
+ position = 6
+ description = "Rating of the content"
default_value = "3" // Default value for the field
}
content = {
- type = "bloks"
- position = 7
+ type = "bloks"
+ position = 7
component_whitelist = ["text", "image", "video"] // Array of component/content type names
- maximum = 10 // Maximum amount of added bloks in this blok field
- description = "Content blocks"
+ maximum = 10 // Maximum amount of added bloks in this blok field
+ description = "Content blocks"
}
}
-}
\ No newline at end of file
+}
+
+// conditional content
+resource "storyblok_component" "conditional_settings_new" {
+ name = "conditional settings component"
+ space_id = ""
+ is_root = false
+ is_nestable = true
+
+
+ schema = {
+ content = {
+ position = 0
+ translatable = true
+ display_name = "Content"
+ required = true
+ type = "text"
+ }
+
+ more_content = {
+ position = 1
+ translatable = true
+ display_name = "more content"
+ required = true
+ type = "text"
+ }
+
+ conditionalContent = {
+ position = 2
+ display_name = "conditinal content"
+ required = true
+ type = "text"
+
+ conditional_settings = [
+ {
+ modifications = [
+ {
+ required = false
+ }
+ ]
+
+ // make "conditional content" optional of either:
+ // 1. content is empty
+ // 2. more content equals "test"
+ rule_match = "any"
+ rule_conditions = [
+ {
+ validation = "empty"
+ validated_object = {
+ field_key = "content"
+ }
+ },
+ {
+ value = "test"
+ validation = "equals"
+ validated_object = {
+ field_key = "more_content"
+ }
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
diff --git a/internal/component_model.go b/internal/component_model.go
index 3f994a0..cf2d472 100644
--- a/internal/component_model.go
+++ b/internal/component_model.go
@@ -83,9 +83,13 @@ type conditionalSettingsModel struct {
}
type ruleConditionModel struct {
- Validation types.String `tfsdk:"validation"`
- Value types.String `tfsdk:"value"`
- FieldKey types.String `tfsdk:"field_key"`
+ Validation types.String `tfsdk:"validation"`
+ Value types.String `tfsdk:"value"`
+ ValidatedObject validatedObjectModel `tfsdk:"validated_object"`
+}
+
+type validatedObjectModel struct {
+ FieldKey types.String `tfsdk:"field_key"`
}
type modificationModel struct {
@@ -169,7 +173,7 @@ func toFieldInput(item fieldModel) sbmgmt.FieldInput {
AssetFolderId: item.AssetFolderId.ValueInt64Pointer(),
CanSync: item.CanSync.ValueBoolPointer(),
ComponentWhitelist: utils.ConvertToPointerStringSlice(item.ComponentWhitelist),
- ConditionalSettings: deserializeConditionalSettingsModel(item.ConditionalSettings),
+ ConditionalSettings: deserializeConditionalSettings(item.ConditionalSettings),
CustomizeToolbar: item.CustomizeToolbar.ValueBoolPointer(),
DatasourceSlug: item.DatasourceSlug.ValueStringPointer(),
DefaultValue: item.DefaultValue.ValueStringPointer(),
@@ -285,6 +289,7 @@ func toFieldModel(field sbmgmt.FieldInput) fieldModel {
Tooltip: types.BoolPointerValue(field.Tooltip),
Translatable: types.BoolPointerValue(field.Translatable),
UseUuid: types.BoolPointerValue(field.UseUuid),
+ ConditionalSettings: serializeConditionalSettings(field.ConditionalSettings),
}
}
@@ -388,7 +393,62 @@ func deserializeOptionsModel(options []optionModel) *[]sbmgmt.FieldOption {
return &optionModels
}
-func deserializeConditionalSettingsModel(conditionalSettings []conditionalSettingsModel) *[]sbmgmt.ConditionalSettings {
+func serializeConditionalSettings(conditionalSettings *[]sbmgmt.ConditionalSettings) []conditionalSettingsModel {
+ if conditionalSettings == nil {
+ return nil
+ }
+
+ serializedConditionalSettings := make([]conditionalSettingsModel, len(*conditionalSettings))
+
+ for i, conditionalSetting := range *conditionalSettings {
+ serializedConditionalSettings[i] = conditionalSettingsModel{
+ RuleMatch: types.StringPointerValue((*string)(conditionalSetting.RuleMatch)),
+ Modifications: serializeModifications(conditionalSetting.Modifications),
+ RuleConditions: serializeRuleConditions(conditionalSetting.RuleConditions),
+ }
+ }
+
+ return serializedConditionalSettings
+}
+
+func serializeModifications(modifications *[]sbmgmt.Modification) []modificationModel {
+ if modifications == nil {
+ return nil
+ }
+
+ serializedModifications := make([]modificationModel, len(*modifications))
+
+ for i, modification := range *modifications {
+ serializedModifications[i] = modificationModel{
+ Required: types.BoolPointerValue(modification.Required),
+ Display: types.StringPointerValue((*string)(modification.Display)),
+ }
+ }
+
+ return serializedModifications
+}
+func serializeRuleConditions(ruleConditions *[]sbmgmt.RuleCondition) []ruleConditionModel {
+
+ if ruleConditions == nil {
+ return nil
+ }
+
+ serializedRuleConditions := make([]ruleConditionModel, len(*ruleConditions))
+
+ for i, ruleCondition := range *ruleConditions {
+ serializedRuleConditions[i] = ruleConditionModel{
+ Value: types.StringPointerValue(ruleCondition.Value),
+ Validation: types.StringPointerValue((*string)(ruleCondition.Validation)),
+ ValidatedObject: validatedObjectModel{
+ FieldKey: types.StringPointerValue(ruleCondition.ValidatedObject.FieldKey),
+ },
+ }
+ }
+
+ return serializedRuleConditions
+}
+
+func deserializeConditionalSettings(conditionalSettings []conditionalSettingsModel) *[]sbmgmt.ConditionalSettings {
if conditionalSettings == nil {
return nil
}
@@ -411,14 +471,9 @@ func deserializeConditionalSettingsModificationsModel(conditionalSettingsModific
deserializedModifications := make([]sbmgmt.Modification, len(conditionalSettingsModifications))
for i, modification := range conditionalSettingsModifications {
- if !modification.Display.IsNull() {
- deserializedModifications[i] = sbmgmt.Modification{
- Display: (*sbmgmt.ModificationDisplay)(modification.Display.ValueStringPointer()),
- }
- } else {
- deserializedModifications[i] = sbmgmt.Modification{
- Required: modification.Required.ValueBoolPointer(),
- }
+ deserializedModifications[i] = sbmgmt.Modification{
+ Required: modification.Required.ValueBoolPointer(),
+ Display: (*sbmgmt.ModificationDisplay)(modification.Display.ValueStringPointer()),
}
}
@@ -434,9 +489,9 @@ func deserializeRuleConditions(ruleConditions []ruleConditionModel) *[]sbmgmt.Ru
for i, ruleCondition := range ruleConditions {
deserializedRuleConditions[i] = sbmgmt.RuleCondition{
Validation: (*sbmgmt.RuleConditionValidation)(ruleCondition.Validation.ValueStringPointer()),
- Value: ruleCondition.Validation.ValueStringPointer(),
+ Value: ruleCondition.Value.ValueStringPointer(),
ValidatedObject: &sbmgmt.ValidatedObject{
- FieldKey: ruleCondition.FieldKey.ValueStringPointer(),
+ FieldKey: ruleCondition.ValidatedObject.FieldKey.ValueStringPointer(),
FieldAttr: &validatedObjectFieldAttrValue,
Type: &validatedValidatedObjectType,
},
diff --git a/internal/component_resource.go b/internal/component_resource.go
index 2b4403f..4722d6e 100644
--- a/internal/component_resource.go
+++ b/internal/component_resource.go
@@ -13,6 +13,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
@@ -174,7 +175,7 @@ func (r *componentResource) Schema(_ context.Context, _ resource.SchemaRequest,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"modifications": schema.ListNestedAttribute{
- Optional: false,
+ Required: true,
Description: "List of modifications to be applied to the field. Only 1 modification can be applied at a time (display OR required)",
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
@@ -192,24 +193,30 @@ func (r *componentResource) Schema(_ context.Context, _ resource.SchemaRequest,
},
"rule_match": schema.StringAttribute{
Description: "Define if all or any of the conditions should be met to apply the modifications",
- Optional: false,
+ Required: true,
Validators: []validator.String{stringvalidator.OneOf("any", "all")},
},
"rule_conditions": schema.ListNestedAttribute{
Description: "Conditional rules to be applied to the target field",
- Optional: false,
+ Required: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"validation": schema.StringAttribute{
- Optional: false,
+ Required: true,
Validators: []validator.String{stringvalidator.OneOf("empty", "not_empty", "equals", "not_equals")},
},
"value": schema.StringAttribute{
Optional: true,
- Default: nil,
+ Computed: true,
+ Default: stringdefault.StaticString("empty"),
},
- "field_key": schema.StringAttribute{
- Optional: false,
+ "validated_object": schema.SingleNestedAttribute{
+ Required: true,
+ Attributes: map[string]schema.Attribute{
+ "field_key": schema.StringAttribute{
+ Required: true,
+ },
+ },
},
},
},