From a93b3915449c6ff9f4afb9c11fb15f674985e16b Mon Sep 17 00:00:00 2001 From: Fabien COMTE Date: Wed, 17 May 2023 17:14:26 +0200 Subject: [PATCH 01/10] New resource aws_quicksight_dashboard --- internal/service/quicksight/dashboard.go | 425 ++++++++++ internal/service/quicksight/dashboard_test.go | 575 +++++++++++++ .../service/quicksight/schema/dashboard.go | 755 ++++++++++++++++++ internal/service/quicksight/schema/dataset.go | 109 +++ .../service/quicksight/schema/parameters.go | 291 +++++++ .../service/quicksight/schema/template.go | 31 +- .../quicksight/schema/template_parameter.go | 6 +- .../quicksight/schema/template_sheet.go | 13 +- .../service/quicksight/service_package_gen.go | 7 + internal/service/quicksight/status.go | 16 + internal/service/quicksight/template.go | 20 +- internal/service/quicksight/template_test.go | 52 ++ internal/service/quicksight/wait.go | 62 +- .../docs/r/quicksight_dashboard.html.markdown | 162 ++++ 14 files changed, 2481 insertions(+), 43 deletions(-) create mode 100644 internal/service/quicksight/dashboard.go create mode 100644 internal/service/quicksight/dashboard_test.go create mode 100644 internal/service/quicksight/schema/dashboard.go create mode 100644 internal/service/quicksight/schema/dataset.go create mode 100644 internal/service/quicksight/schema/parameters.go create mode 100644 website/docs/r/quicksight_dashboard.html.markdown diff --git a/internal/service/quicksight/dashboard.go b/internal/service/quicksight/dashboard.go new file mode 100644 index 000000000000..5b68c39aaaba --- /dev/null +++ b/internal/service/quicksight/dashboard.go @@ -0,0 +1,425 @@ +package quicksight + +import ( + "context" + "fmt" + "log" + "strconv" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/quicksight" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + quicksightschema "github.com/hashicorp/terraform-provider-aws/internal/service/quicksight/schema" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKResource("aws_quicksight_dashboard") +// @Tags(identifierAttribute="arn") +func ResourceDashboard() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceDashboardCreate, + ReadWithoutTimeout: resourceDashboardRead, + UpdateWithoutTimeout: resourceDashboardUpdate, + DeleteWithoutTimeout: resourceDashboardDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "aws_account_id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: verify.ValidAccountID, + }, + "created_time": { + Type: schema.TypeString, + Computed: true, + }, + "dashboard_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "dashboard_publish_options": quicksightschema.DashboardPublishOptionsSchema(), + "definition": quicksightschema.DashboardDefinitionSchema(), + "last_updated_time": { + Type: schema.TypeString, + Computed: true, + }, + "last_published_time": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 2048), + }, + "parameters": quicksightschema.ParametersSchema(), + "permissions": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 64, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "actions": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + MaxItems: 16, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "principal": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + }, + }, + }, + "source_entity": quicksightschema.DashboardSourceEntitySchema(), + "source_entity_arn": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + "theme_arn": { + Type: schema.TypeString, + Optional: true, + }, + "version_description": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 512), + }, + "version_number": { + Type: schema.TypeInt, + Computed: true, + }, + }, + CustomizeDiff: customdiff.All( + refreshOutputsDiff, + verify.SetTagsDiff, + ), + } +} + +const ( + ResNameDashboard = "Dashboard" +) + +func resourceDashboardCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).QuickSightConn() + + awsAccountId := meta.(*conns.AWSClient).AccountID + if v, ok := d.GetOk("aws_account_id"); ok { + awsAccountId = v.(string) + } + dashboardId := d.Get("dashboard_id").(string) + + d.SetId(createDashboardId(awsAccountId, dashboardId)) + + input := &quicksight.CreateDashboardInput{ + AwsAccountId: aws.String(awsAccountId), + DashboardId: aws.String(dashboardId), + Name: aws.String(d.Get("name").(string)), + Tags: GetTagsIn(ctx), + } + + if v, ok := d.GetOk("version_description"); ok { + input.VersionDescription = aws.String(v.(string)) + } + + if v, ok := d.GetOk("source_entity"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.SourceEntity = quicksightschema.ExpandDashboardSourceEntity(v.([]interface{})) + } + + if v, ok := d.GetOk("definition"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.Definition = quicksightschema.ExpandDashboardDefinition(d.Get("definition").([]interface{})) + } + + if v, ok := d.GetOk("dashboard_publish_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DashboardPublishOptions = quicksightschema.ExpandDashboardPublishOptions(d.Get("dashboard_publish_options").([]interface{})) + } + + if v, ok := d.GetOk("parameters"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.Parameters = quicksightschema.ExpandParameters(d.Get("parameters").([]interface{})) + } + + if v, ok := d.GetOk("permissions"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.Permissions = expandResourcePermissions(v.([]interface{})) + } + + _, err := conn.CreateDashboardWithContext(ctx, input) + if err != nil { + return create.DiagError(names.QuickSight, create.ErrActionCreating, ResNameDashboard, d.Get("name").(string), err) + } + + if _, err := waitDashboardCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return create.DiagError(names.QuickSight, create.ErrActionWaitingForCreation, ResNameDashboard, d.Id(), err) + } + + return resourceDashboardRead(ctx, d, meta) +} + +func resourceDashboardRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).QuickSightConn() + + awsAccountId, dashboardId, err := ParseDashboardId(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + out, err := FindDashboardByID(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] QuickSight Dashboard (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return create.DiagError(names.QuickSight, create.ErrActionReading, ResNameDashboard, d.Id(), err) + } + + d.Set("arn", out.Arn) + d.Set("aws_account_id", awsAccountId) + d.Set("created_time", out.CreatedTime.Format(time.RFC3339)) + d.Set("last_updated_time", out.LastUpdatedTime.Format(time.RFC3339)) + d.Set("name", out.Name) + d.Set("status", out.Version.Status) + d.Set("source_entity_arn", out.Version.SourceEntityArn) + d.Set("dashboard_id", out.DashboardId) + d.Set("version_description", out.Version.Description) + d.Set("version_number", out.Version.VersionNumber) + + descResp, err := conn.DescribeDashboardDefinitionWithContext(ctx, &quicksight.DescribeDashboardDefinitionInput{ + AwsAccountId: aws.String(awsAccountId), + DashboardId: aws.String(dashboardId), + VersionNumber: out.Version.VersionNumber, + }) + + if err != nil { + return diag.Errorf("error describing QuickSight Dashboard (%s) Definition: %s", d.Id(), err) + } + + if err := d.Set("definition", quicksightschema.FlattenDashboardDefinition(descResp.Definition)); err != nil { + return diag.Errorf("error setting definition: %s", err) + } + + if err := d.Set("dashboard_publish_options", quicksightschema.FlattenDashboardPublishOptions(descResp.DashboardPublishOptions)); err != nil { + return diag.Errorf("error setting dashboard_publish_options: %s", err) + + } + + permsResp, err := conn.DescribeDashboardPermissionsWithContext(ctx, &quicksight.DescribeDashboardPermissionsInput{ + AwsAccountId: aws.String(awsAccountId), + DashboardId: aws.String(dashboardId), + }) + + if err != nil { + return diag.Errorf("error describing QuickSight Dashboard (%s) Permissions: %s", d.Id(), err) + } + + if err := d.Set("permissions", flattenPermissions(permsResp.Permissions)); err != nil { + return diag.Errorf("error setting permissions: %s", err) + } + + return nil +} + +func resourceDashboardUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).QuickSightConn() + + awsAccountId, dashboardId, err := ParseDashboardId(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + if d.HasChangesExcept("permissions", "tags", "tags_all") { + in := &quicksight.UpdateDashboardInput{ + AwsAccountId: aws.String(awsAccountId), + DashboardId: aws.String(dashboardId), + Name: aws.String(d.Get("name").(string)), + VersionDescription: aws.String(d.Get("version_description").(string)), + } + + _, createdFromEntity := d.GetOk("source_entity") + if createdFromEntity { + in.SourceEntity = quicksightschema.ExpandDashboardSourceEntity(d.Get("source_entity").([]interface{})) + } else { + in.Definition = quicksightschema.ExpandDashboardDefinition(d.Get("definition").([]interface{})) + } + + if v, ok := d.GetOk("parameters"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + in.Parameters = quicksightschema.ExpandParameters(d.Get("parameters").([]interface{})) + } + + if v, ok := d.GetOk("dashboard_publish_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + in.DashboardPublishOptions = quicksightschema.ExpandDashboardPublishOptions(d.Get("dashboard_publish_options").([]interface{})) + } + + log.Printf("[DEBUG] Updating QuickSight Dashboard (%s): %#v", d.Id(), in) + out, err := conn.UpdateDashboardWithContext(ctx, in) + if err != nil { + return create.DiagError(names.QuickSight, create.ErrActionUpdating, ResNameDashboard, d.Id(), err) + } + + if _, err := waitDashboardUpdated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + return create.DiagError(names.QuickSight, create.ErrActionWaitingForUpdate, ResNameDashboard, d.Id(), err) + } + + publishVersion := &quicksight.UpdateDashboardPublishedVersionInput{ + AwsAccountId: aws.String(awsAccountId), + DashboardId: aws.String(dashboardId), + VersionNumber: extractVersionFromARN(aws.StringValue(out.VersionArn)), + } + _, err = conn.UpdateDashboardPublishedVersionWithContext(ctx, publishVersion) + if err != nil { + return create.DiagError(names.QuickSight, create.ErrActionUpdating, ResNameDashboard, d.Id(), err) + } + } + + if d.HasChange("permissions") { + oraw, nraw := d.GetChange("permissions") + o := oraw.([]interface{}) + n := nraw.([]interface{}) + + toGrant, toRevoke := DiffPermissions(o, n) + + params := &quicksight.UpdateDashboardPermissionsInput{ + AwsAccountId: aws.String(awsAccountId), + DashboardId: aws.String(dashboardId), + } + + if len(toGrant) > 0 { + params.GrantPermissions = toGrant + } + + if len(toRevoke) > 0 { + params.RevokePermissions = toRevoke + } + + _, err = conn.UpdateDashboardPermissionsWithContext(ctx, params) + + if err != nil { + return diag.Errorf("error updating QuickSight Dashboard (%s) permissions: %s", dashboardId, err) + } + } + + return resourceDashboardRead(ctx, d, meta) +} + +func resourceDashboardDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).QuickSightConn() + + awsAccountId, dashboardId, err := ParseDashboardId(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + log.Printf("[INFO] Deleting QuickSight Dashboard %s", d.Id()) + _, err = conn.DeleteDashboardWithContext(ctx, &quicksight.DeleteDashboardInput{ + AwsAccountId: aws.String(awsAccountId), + DashboardId: aws.String(dashboardId), + }) + + if tfawserr.ErrCodeEquals(err, quicksight.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return create.DiagError(names.QuickSight, create.ErrActionDeleting, ResNameDashboard, d.Id(), err) + } + + return nil +} + +func FindDashboardByID(ctx context.Context, conn *quicksight.QuickSight, id string) (*quicksight.Dashboard, error) { + awsAccountId, dashboardId, err := ParseDashboardId(id) + if err != nil { + return nil, err + } + + descOpts := &quicksight.DescribeDashboardInput{ + AwsAccountId: aws.String(awsAccountId), + DashboardId: aws.String(dashboardId), + } + + out, err := conn.DescribeDashboardWithContext(ctx, descOpts) + + if tfawserr.ErrCodeEquals(err, quicksight.ErrCodeResourceNotFoundException) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: descOpts, + } + } + + if err != nil { + return nil, err + } + + if out == nil || out.Dashboard == nil { + return nil, tfresource.NewEmptyResultError(descOpts) + } + + return out.Dashboard, nil +} + +func ParseDashboardId(id string) (string, string, error) { + parts := strings.SplitN(id, ",", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format of ID (%s), expected AWS_ACCOUNT_ID,DASHBOARD_ID", id) + } + return parts[0], parts[1], nil +} + +func createDashboardId(awsAccountID, dashboardId string) string { + return fmt.Sprintf("%s,%s", awsAccountID, dashboardId) +} + +func extractVersionFromARN(arn string) *int64 { + version, _ := strconv.Atoi(arn[strings.LastIndex(arn, "/")+1:]) + return aws.Int64(int64(version)) +} + +func refreshOutputsDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error { + if diff.HasChanges("name", "definition", "source_entity", "theme_arn", "version_description", "parameters", "dashboard_publish_options") { + if err := diff.SetNewComputed("version_number"); err != nil { + return err + } + } + + return nil +} diff --git a/internal/service/quicksight/dashboard_test.go b/internal/service/quicksight/dashboard_test.go new file mode 100644 index 000000000000..8743464209c3 --- /dev/null +++ b/internal/service/quicksight/dashboard_test.go @@ -0,0 +1,575 @@ +package quicksight_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/quicksight" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + tfquicksight "github.com/hashicorp/terraform-provider-aws/internal/service/quicksight" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccQuickSightDashboard_basic(t *testing.T) { + ctx := acctest.Context(t) + + var dashboard quicksight.Dashboard + resourceName := "aws_quicksight_dashboard.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rId := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDashboardDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDashboardConfig_basic(rId, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDashboardExists(ctx, resourceName, &dashboard), + resource.TestCheckResourceAttr(resourceName, "dashboard_id", rId), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "status", quicksight.ResourceStatusCreationSuccessful), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccQuickSightDashboard_disappears(t *testing.T) { + ctx := acctest.Context(t) + + var dashboard quicksight.Dashboard + resourceName := "aws_quicksight_dashboard.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rId := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDashboardDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDashboardConfig_basic(rId, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDashboardExists(ctx, resourceName, &dashboard), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfquicksight.ResourceDashboard(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckDashboardDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).QuickSightConn() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_quicksight_dashboard" { + continue + } + + output, err := tfquicksight.FindDashboardByID(ctx, conn, rs.Primary.ID) + if err != nil { + if tfawserr.ErrCodeEquals(err, quicksight.ErrCodeResourceNotFoundException) { + return nil + } + return err + } + + if output != nil { + return fmt.Errorf("QuickSight Dashboard (%s) still exists", rs.Primary.ID) + } + } + + return nil + } +} + +func TestAccQuickSightDashboard_sourceEntity(t *testing.T) { + ctx := acctest.Context(t) + + var dashboard quicksight.Dashboard + resourceName := "aws_quicksight_dashboard.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rId := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + sourceName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + sourceId := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDashboardDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDashboardConfig_TemplateSourceEntity(rId, rName, sourceId, sourceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDashboardExists(ctx, resourceName, &dashboard), + resource.TestCheckResourceAttr(resourceName, "dashboard_id", rId), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "status", quicksight.ResourceStatusCreationSuccessful), + acctest.CheckResourceAttrRegionalARN(resourceName, "source_entity.0.source_template.0.arn", "quicksight", fmt.Sprintf("template/%s", sourceId)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"source_entity"}, + }, + }, + }) +} + +func TestAccQuickSightDashboard_updateVersionNumber(t *testing.T) { + ctx := acctest.Context(t) + + var dashboard quicksight.Dashboard + resourceName := "aws_quicksight_dashboard.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rId := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDashboardDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDashboardConfig_basic(rId, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDashboardExists(ctx, resourceName, &dashboard), + resource.TestCheckResourceAttr(resourceName, "dashboard_id", rId), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "status", quicksight.ResourceStatusCreationSuccessful), + resource.TestCheckResourceAttr(resourceName, "version_number", "1"), + ), + }, + { + Config: testAccDashboardConfig_basic(rId, rNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckDashboardExists(ctx, resourceName, &dashboard), + resource.TestCheckResourceAttr(resourceName, "dashboard_id", rId), + resource.TestCheckResourceAttr(resourceName, "name", rNameUpdated), + resource.TestCheckResourceAttr(resourceName, "status", quicksight.ResourceStatusCreationSuccessful), + resource.TestCheckResourceAttr(resourceName, "version_number", "2"), + ), + }, + }, + }) +} + +func TestAccQuickSightDashboard_dashboardSpecificConfig(t *testing.T) { + ctx := acctest.Context(t) + + var dashboard quicksight.Dashboard + resourceName := "aws_quicksight_dashboard.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rId := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDashboardDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDashboardConfig_DashboardSpecificConfig(rId, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDashboardExists(ctx, resourceName, &dashboard), + resource.TestCheckResourceAttr(resourceName, "dashboard_id", rId), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "dashboard_publish_options.0.ad_hoc_filtering_option.0.availability_status", quicksight.StatusDisabled), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"parameters"}, + }, + }, + }) +} + +func testAccCheckDashboardExists(ctx context.Context, name string, dashboard *quicksight.Dashboard) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.QuickSight, create.ErrActionCheckingExistence, tfquicksight.ResNameDashboard, name, errors.New("not found")) + } + + if rs.Primary.ID == "" { + return create.Error(names.QuickSight, create.ErrActionCheckingExistence, tfquicksight.ResNameDashboard, name, errors.New("not set")) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).QuickSightConn() + output, err := tfquicksight.FindDashboardByID(ctx, conn, rs.Primary.ID) + + if err != nil { + return create.Error(names.QuickSight, create.ErrActionCheckingExistence, tfquicksight.ResNameDashboard, rs.Primary.ID, err) + } + + *dashboard = *output + + return nil + } +} + +func testAccCheckDashboardNotRecreated(before, after *quicksight.Dashboard) resource.TestCheckFunc { + return func(s *terraform.State) error { + if creationTimeBefore, creationTimeAfter := aws.TimeValue(before.CreatedTime), aws.TimeValue(after.CreatedTime); creationTimeBefore != creationTimeAfter { + return create.Error(names.QuickSight, create.ErrActionCheckingNotRecreated, tfquicksight.ResNameDashboard, aws.StringValue(before.DashboardId), errors.New("recreated")) + } + + return nil + } +} + +func testAccDashboardConfigBase(rId string, rName string) string { + return acctest.ConfigCompose( + testAccDataSetConfigBase(rId, rName), + fmt.Sprintf(` +resource "aws_quicksight_data_set" "test" { + data_set_id = %[1]q + name = %[2]q + import_mode = "SPICE" + + physical_table_map { + physical_table_map_id = %[1]q + s3_source { + data_source_arn = aws_quicksight_data_source.test.arn + input_columns { + name = "Column1" + type = "STRING" + } + input_columns { + name = "Column2" + type = "STRING" + } + upload_settings {} + } + } + logical_table_map { + logical_table_map_id = %[1]q + alias = "Group1" + source { + physical_table_id = %[1]q + } + data_transforms { + cast_column_type_operation { + column_name = "Column2" + new_column_type = "INTEGER" + } + } + } + + lifecycle { + ignore_changes = [ + physical_table_map + ] + } +} +`, rId, rName)) +} + +func testAccDashboardConfig_basic(rId, rName string) string { + return acctest.ConfigCompose( + testAccDashboardConfigBase(rId, rName), + fmt.Sprintf(` +resource "aws_quicksight_dashboard" "test" { + dashboard_id = %[1]q + name = %[2]q + version_description = "test" + definition { + data_set_identifiers_declarations { + data_set_arn = aws_quicksight_data_set.test.arn + identifier = "1" + } + sheets { + title = "Test" + sheet_id = "Test1" + visuals { + custom_content_visual { + data_set_identifier = "1" + title { + format_text { + plain_text = "Test" + } + } + visual_id = "Test1" + } + } + visuals { + line_chart_visual { + visual_id = "LineChart" + title { + format_text { + plain_text = "Line Chart Test" + } + } + chart_configuration { + field_wells { + line_chart_aggregated_field_wells { + category { + categorical_dimension_field { + field_id = "1" + column { + data_set_identifier = "1" + column_name = "Column1" + } + } + } + values { + categorical_measure_field { + field_id = "2" + column { + data_set_identifier = "1" + column_name = "Column1" + } + aggregation_function = "COUNT" + } + } + } + } + } + } + } + } + } +} +`, rId, rName)) +} + +func testAccDashboardConfig_TemplateSourceEntity(rId, rName, sourceId, sourceName string) string { + return acctest.ConfigCompose( + testAccDashboardConfigBase(rId, rName), + fmt.Sprintf(` +resource "aws_quicksight_template" "test" { + template_id = %[3]q + name = %[4]q + version_description = "test" + definition { + data_set_configuration { + data_set_schema { + column_schema_list { + name = "Column1" + data_type = "STRING" + } + column_schema_list { + name = "Column2" + data_type = "INTEGER" + } + } + placeholder = "1" + } + sheets { + title = "Test" + sheet_id = "Test1" + visuals { + custom_content_visual { + data_set_identifier = "1" + title { + format_text { + plain_text = "Test" + } + } + visual_id = "Test1" + } + } + visuals { + line_chart_visual { + visual_id = "LineChart" + title { + format_text { + plain_text = "Line Chart Test" + } + } + chart_configuration { + field_wells { + line_chart_aggregated_field_wells { + category { + categorical_dimension_field { + field_id = "1" + column { + data_set_identifier = "1" + column_name = "Column1" + } + } + } + values { + categorical_measure_field { + field_id = "2" + column { + data_set_identifier = "1" + column_name = "Column1" + } + aggregation_function = "COUNT" + } + } + } + } + } + } + } + } + } +} + +resource "aws_quicksight_dashboard" "test" { + dashboard_id = %[1]q + name = %[2]q + version_description = "test" + source_entity { + source_template { + arn = aws_quicksight_template.test.arn + data_set_references { + data_set_arn = aws_quicksight_data_set.test.arn + data_set_placeholder = "1" + } + } + } +} +`, rId, rName, sourceId, sourceName)) +} + +func testAccDashboardConfig_DashboardSpecificConfig(rId, rName string) string { + return acctest.ConfigCompose( + testAccDashboardConfigBase(rId, rName), + fmt.Sprintf(` +resource "aws_quicksight_dashboard" "test" { + dashboard_id = %[1]q + name = %[2]q + version_description = "test" + + parameters { + string_parameters { + name = "test" + values = ["value"] + } + } + + dashboard_publish_options { + ad_hoc_filtering_option { + availability_status = "DISABLED" + } + data_point_drill_up_down_option { + availability_status = "ENABLED" + } + data_point_menu_label_option { + availability_status = "ENABLED" + } + data_point_tooltip_option { + availability_status = "ENABLED" + } + export_to_csv_option { + availability_status = "ENABLED" + } + export_with_hidden_fields_option { + availability_status = "DISABLED" + } + sheet_controls_option { + visibility_state = "COLLAPSED" + } + sheet_layout_element_maximization_option { + availability_status = "ENABLED" + } + visual_axis_sort_option { + availability_status = "ENABLED" + } + visual_menu_option { + availability_status = "ENABLED" + } + } + + definition { + data_set_identifiers_declarations { + data_set_arn = aws_quicksight_data_set.test.arn + identifier = "1" + } + + parameters_declarations { + string_parameter_declaration { + name = "test" + parameter_value_type = "SINGLE_VALUED" + default_values { + static_values = ["value"] + } + values_when_unset { + value_when_unset_option = "NULL" + } + } + } + + sheets { + title = "Example" + sheet_id = "Example1" + visuals { + line_chart_visual { + visual_id = "LineChart" + title { + format_text { + plain_text = "Line Chart Example" + } + } + chart_configuration { + field_wells { + line_chart_aggregated_field_wells { + category { + categorical_dimension_field { + field_id = "1" + column { + data_set_identifier = "1" + column_name = "Column1" + } + } + } + values { + categorical_measure_field { + field_id = "2" + column { + data_set_identifier = "1" + column_name = "Column1" + } + aggregation_function = "COUNT" + } + } + } + } + } + } + } + } + } +} +`, rId, rName)) +} diff --git a/internal/service/quicksight/schema/dashboard.go b/internal/service/quicksight/schema/dashboard.go new file mode 100644 index 000000000000..752c530f0180 --- /dev/null +++ b/internal/service/quicksight/schema/dashboard.go @@ -0,0 +1,755 @@ +package schema + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/quicksight" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func DashboardDefinitionSchema() *schema.Schema { + return &schema.Schema{ // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DashboardVersionDefinition.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + ExactlyOneOf: []string{ + "definition", + "source_entity", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "data_set_identifiers_declarations": dataSetIdentifierDeclarationsSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataSetIdentifierDeclaration.html + "analysis_defaults": analysisDefaultSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_AnalysisDefaults.html + "calculated_fields": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_CalculatedField.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 500, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "data_set_identifier": stringSchema(true, validation.StringLenBetween(1, 2048)), + "expression": stringSchema(true, validation.StringLenBetween(1, 4096)), + "name": stringSchema(true, validation.StringLenBetween(1, 128)), + }, + }, + }, + "column_configurations": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ColumnConfiguration.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 200, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "column": columnSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ColumnIdentifier.html + "format_configuration": formatConfigurationSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_FormatConfiguration.html + "role": stringSchema(false, validation.StringInSlice(quicksight.ColumnRole_Values(), false)), + }, + }, + }, + "filter_groups": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_FilterGroup.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 2000, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cross_dataset": stringSchema(true, validation.StringInSlice(quicksight.CrossDatasetTypes_Values(), false)), + "filter_group_id": idSchema(), + "filters": filtersSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_Filter.html + "scope_configuration": filterScopeConfigurationSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_FilterScopeConfiguration.html + "status": stringSchema(false, validation.StringInSlice(quicksight.Status_Values(), false)), + }, + }, + }, + "parameters_declarations": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ParameterDeclaration.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 200, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "date_time_parameter_declaration": dateTimeParameterDeclarationSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DateTimeParameterDeclaration.html + "decimal_parameter_declaration": decimalParameterDeclarationSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DecimalParameterDeclaration.html + "integer_parameter_declaration": integerParameterDeclarationSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_IntegerParameterDeclaration.html + "string_parameter_declaration": stringParameterDeclarationSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_StringParameterDeclaration.html + }, + }, + }, + "sheets": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_SheetDefinition.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 20, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "sheet_id": idSchema(), + "content_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(quicksight.SheetContentType_Values(), false), + }, + "description": stringSchema(false, validation.StringLenBetween(1, 1024)), + "filter_controls": filterControlsSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_FilterControl.html + "layouts": layoutSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_Layout.html + "name": stringSchema(false, validation.StringLenBetween(1, 2048)), + "parameter_controls": parameterControlsSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ParameterControl.html + "sheet_control_layouts": sheetControlLayoutsSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_SheetControlLayout.html + "text_boxes": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_SheetTextBox.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "sheet_text_box_id": idSchema(), + "content": stringSchema(false, validation.StringLenBetween(1, 150000)), + }, + }, + }, + "title": stringSchema(false, validation.StringLenBetween(1, 1024)), + "visuals": visualsSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_Visual.html + }, + }, + }, + }, + }, + } +} + +func DashboardPublishOptionsSchema() *schema.Schema { + return &schema.Schema{ // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DashboardPublishOptions.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ad_hoc_filtering_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_AdHocFilteringOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_status": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.StatusEnabled, + ValidateFunc: validation.StringInSlice(quicksight.Status_Values(), false), + }, + }, + }, + }, + "data_point_drill_up_down_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataPointDrillUpDownOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_status": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.StatusEnabled, + ValidateFunc: validation.StringInSlice(quicksight.Status_Values(), false), + }}, + }, + }, + "data_point_menu_label_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataPointMenuLabelOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_status": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.StatusEnabled, + ValidateFunc: validation.StringInSlice(quicksight.Status_Values(), false), + }}, + }, + }, + "data_point_tooltip_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataPointTooltipOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_status": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.StatusEnabled, + ValidateFunc: validation.StringInSlice(quicksight.Status_Values(), false), + }}, + }, + }, + "export_to_csv_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ExportToCSVOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_status": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.StatusEnabled, + ValidateFunc: validation.StringInSlice(quicksight.Status_Values(), false), + }}, + }, + }, + "export_with_hidden_fields_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ExportWithHiddenFieldsOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_status": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.StatusDisabled, + ValidateFunc: validation.StringInSlice(quicksight.Status_Values(), false), + }}, + }, + }, + "sheet_controls_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_SheetControlsOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "visibility_state": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.DashboardUIStateCollapsed, + ValidateFunc: validation.StringInSlice(quicksight.DashboardUIState_Values(), false), + }, + }, + }, + }, + "sheet_layout_element_maximization_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_SheetLayoutElementMaximizationOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_status": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.StatusEnabled, + ValidateFunc: validation.StringInSlice(quicksight.Status_Values(), false), + }}, + }, + }, + "visual_axis_sort_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_VisualAxisSortOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_status": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.StatusEnabled, + ValidateFunc: validation.StringInSlice(quicksight.Status_Values(), false), + }}, + }, + }, + "visual_menu_option": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_VisualMenuOption.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_status": { + Type: schema.TypeString, + Optional: true, + Default: quicksight.StatusEnabled, + ValidateFunc: validation.StringInSlice(quicksight.Status_Values(), false), + }}, + }, + }, + }, + }, + } +} + +func DashboardSourceEntitySchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + ExactlyOneOf: []string{ + "definition", + "source_entity", + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_template": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "data_set_references": dataSetReferencesSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataSetReference.html + }, + }, + }, + }, + }, + } +} + +func ExpandDashboardSourceEntity(tfList []interface{}) *quicksight.DashboardSourceEntity { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + tfMap, ok := tfList[0].(map[string]interface{}) + if !ok { + return nil + } + + sourceEntity := &quicksight.DashboardSourceEntity{} + + if v, ok := tfMap["source_template"].([]interface{}); ok && len(v) > 0 { + sourceEntity.SourceTemplate = expandDashboardSourceTemplate(v[0].(map[string]interface{})) + } + + return sourceEntity +} + +func expandDashboardSourceTemplate(tfMap map[string]interface{}) *quicksight.DashboardSourceTemplate { + if tfMap == nil { + return nil + } + + sourceTemplate := &quicksight.DashboardSourceTemplate{} + if v, ok := tfMap["arn"].(string); ok && v != "" { + sourceTemplate.Arn = aws.String(v) + } + if v, ok := tfMap["data_set_references"].([]interface{}); ok && len(v) > 0 { + sourceTemplate.DataSetReferences = expandDataSetReferences(v) + } + + return sourceTemplate +} + +func ExpandDashboardDefinition(tfList []interface{}) *quicksight.DashboardVersionDefinition { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + tfMap, ok := tfList[0].(map[string]interface{}) + if !ok { + return nil + } + + definition := &quicksight.DashboardVersionDefinition{} + + if v, ok := tfMap["analysis_defaults"].([]interface{}); ok && len(v) > 0 { + definition.AnalysisDefaults = expandAnalysisDefaults(v) + } + if v, ok := tfMap["calculated_fields"].([]interface{}); ok && len(v) > 0 { + definition.CalculatedFields = expandCalculatedFields(v) + } + if v, ok := tfMap["column_configurations"].([]interface{}); ok && len(v) > 0 { + definition.ColumnConfigurations = expandColumnConfigurations(v) + } + if v, ok := tfMap["data_set_identifiers_declarations"].([]interface{}); ok && len(v) > 0 { + definition.DataSetIdentifierDeclarations = expandDataSetIdentifierDeclarations(v) + } + if v, ok := tfMap["filter_groups"].([]interface{}); ok && len(v) > 0 { + definition.FilterGroups = expandFilterGroups(v) + } + if v, ok := tfMap["parameters_declarations"].([]interface{}); ok && len(v) > 0 { + definition.ParameterDeclarations = expandParameterDeclarations(v) + } + if v, ok := tfMap["sheets"].([]interface{}); ok && len(v) > 0 { + definition.Sheets = expandSheetDefinitions(v) + } + + return definition +} + +func ExpandDashboardPublishOptions(tfList []interface{}) *quicksight.DashboardPublishOptions { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + tfMap, ok := tfList[0].(map[string]interface{}) + if !ok { + return nil + } + + options := &quicksight.DashboardPublishOptions{} + + if v, ok := tfMap["ad_hoc_filtering_option"].([]interface{}); ok && len(v) > 0 { + options.AdHocFilteringOption = expandAdHocFilteringOption(v[0].(map[string]interface{})) + } + if v, ok := tfMap["data_point_drill_up_down_option"].([]interface{}); ok && len(v) > 0 { + options.DataPointDrillUpDownOption = expandDataPointDrillUpDownOption(v[0].(map[string]interface{})) + } + if v, ok := tfMap["data_point_menu_label_option"].([]interface{}); ok && len(v) > 0 { + options.DataPointMenuLabelOption = expandDataPointMenuLabelOption(v[0].(map[string]interface{})) + } + if v, ok := tfMap["data_point_tooltip_option"].([]interface{}); ok && len(v) > 0 { + options.DataPointTooltipOption = expandDataPointTooltipOption(v[0].(map[string]interface{})) + } + if v, ok := tfMap["export_to_csv_option"].([]interface{}); ok && len(v) > 0 { + options.ExportToCSVOption = expandExportToCSVOption(v[0].(map[string]interface{})) + } + if v, ok := tfMap["export_with_hidden_fields_option"].([]interface{}); ok && len(v) > 0 { + options.ExportWithHiddenFieldsOption = expandExportWithHiddenFieldsOption(v[0].(map[string]interface{})) + } + if v, ok := tfMap["sheet_controls_option"].([]interface{}); ok && len(v) > 0 { + options.SheetControlsOption = expandSheetControlsOption(v[0].(map[string]interface{})) + } + if v, ok := tfMap["sheet_layout_element_maximization_option"].([]interface{}); ok && len(v) > 0 { + options.SheetLayoutElementMaximizationOption = expandSheetLayoutElementMaximizationOption(v[0].(map[string]interface{})) + } + if v, ok := tfMap["visual_axis_sort_option"].([]interface{}); ok && len(v) > 0 { + options.VisualAxisSortOption = expandVisualAxisSortOption(v[0].(map[string]interface{})) + } + if v, ok := tfMap["visual_menu_option"].([]interface{}); ok && len(v) > 0 { + options.VisualMenuOption = expandVisualMenuOption(v[0].(map[string]interface{})) + } + + return options +} + +func expandAdHocFilteringOption(tfMap map[string]interface{}) *quicksight.AdHocFilteringOption { + if tfMap == nil { + return nil + } + + options := &quicksight.AdHocFilteringOption{} + if v, ok := tfMap["availability_status"].(string); ok && v != "" { + options.AvailabilityStatus = aws.String(v) + } + + return options +} + +func expandDataPointDrillUpDownOption(tfMap map[string]interface{}) *quicksight.DataPointDrillUpDownOption { + if tfMap == nil { + return nil + } + + options := &quicksight.DataPointDrillUpDownOption{} + if v, ok := tfMap["availability_status"].(string); ok && v != "" { + options.AvailabilityStatus = aws.String(v) + } + + return options +} + +func expandDataPointMenuLabelOption(tfMap map[string]interface{}) *quicksight.DataPointMenuLabelOption { + if tfMap == nil { + return nil + } + + options := &quicksight.DataPointMenuLabelOption{} + if v, ok := tfMap["availability_status"].(string); ok && v != "" { + options.AvailabilityStatus = aws.String(v) + } + + return options +} + +func expandDataPointTooltipOption(tfMap map[string]interface{}) *quicksight.DataPointTooltipOption { + if tfMap == nil { + return nil + } + + options := &quicksight.DataPointTooltipOption{} + if v, ok := tfMap["availability_status"].(string); ok && v != "" { + options.AvailabilityStatus = aws.String(v) + } + + return options +} + +func expandExportToCSVOption(tfMap map[string]interface{}) *quicksight.ExportToCSVOption { + if tfMap == nil { + return nil + } + + options := &quicksight.ExportToCSVOption{} + if v, ok := tfMap["availability_status"].(string); ok && v != "" { + options.AvailabilityStatus = aws.String(v) + } + + return options +} + +func expandExportWithHiddenFieldsOption(tfMap map[string]interface{}) *quicksight.ExportWithHiddenFieldsOption { + if tfMap == nil { + return nil + } + + options := &quicksight.ExportWithHiddenFieldsOption{} + if v, ok := tfMap["availability_status"].(string); ok && v != "" { + options.AvailabilityStatus = aws.String(v) + } + + return options +} + +func expandSheetLayoutElementMaximizationOption(tfMap map[string]interface{}) *quicksight.SheetLayoutElementMaximizationOption { + if tfMap == nil { + return nil + } + + options := &quicksight.SheetLayoutElementMaximizationOption{} + if v, ok := tfMap["availability_status"].(string); ok && v != "" { + options.AvailabilityStatus = aws.String(v) + } + + return options +} + +func expandSheetControlsOption(tfMap map[string]interface{}) *quicksight.SheetControlsOption { + if tfMap == nil { + return nil + } + + options := &quicksight.SheetControlsOption{} + if v, ok := tfMap["visibility_state"].(string); ok && v != "" { + options.VisibilityState = aws.String(v) + } + + return options +} + +func expandVisualAxisSortOption(tfMap map[string]interface{}) *quicksight.VisualAxisSortOption { + if tfMap == nil { + return nil + } + + options := &quicksight.VisualAxisSortOption{} + if v, ok := tfMap["availability_status"].(string); ok && v != "" { + options.AvailabilityStatus = aws.String(v) + } + + return options +} + +func expandVisualMenuOption(tfMap map[string]interface{}) *quicksight.VisualMenuOption { + if tfMap == nil { + return nil + } + + options := &quicksight.VisualMenuOption{} + if v, ok := tfMap["availability_status"].(string); ok && v != "" { + options.AvailabilityStatus = aws.String(v) + } + + return options +} + +func FlattenDashboardDefinition(apiObject *quicksight.DashboardVersionDefinition) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AnalysisDefaults != nil { + tfMap["analysis_defaults"] = flattenAnalysisDefaults(apiObject.AnalysisDefaults) + } + if apiObject.CalculatedFields != nil { + tfMap["calculated_fields"] = flattenCalculatedFields(apiObject.CalculatedFields) + } + if apiObject.ColumnConfigurations != nil { + tfMap["column_configurations"] = flattenColumnConfigurations(apiObject.ColumnConfigurations) + } + if apiObject.DataSetIdentifierDeclarations != nil { + tfMap["data_set_identifiers_declarations"] = flattenDataSetIdentifierDeclarations(apiObject.DataSetIdentifierDeclarations) + } + if apiObject.FilterGroups != nil { + tfMap["filter_groups"] = flattenFilterGroups(apiObject.FilterGroups) + } + if apiObject.ParameterDeclarations != nil { + tfMap["parameters_declarations"] = flattenParameterDeclarations(apiObject.ParameterDeclarations) + } + if apiObject.Sheets != nil { + tfMap["sheets"] = flattenSheetDefinitions(apiObject.Sheets) + } + + return []interface{}{tfMap} +} + +func FlattenDashboardPublishOptions(apiObject *quicksight.DashboardPublishOptions) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AdHocFilteringOption != nil { + tfMap["ad_hoc_filtering_option"] = flattenAdHocFilteringOption(apiObject.AdHocFilteringOption) + } + if apiObject.DataPointDrillUpDownOption != nil { + tfMap["data_point_drill_up_down_option"] = flattenDataPointDrillUpDownOption(apiObject.DataPointDrillUpDownOption) + } + if apiObject.DataPointMenuLabelOption != nil { + tfMap["data_point_menu_label_option"] = flattenDataPointMenuLabelOption(apiObject.DataPointMenuLabelOption) + } + if apiObject.DataPointTooltipOption != nil { + tfMap["data_point_tooltip_option"] = flattenDataPointTooltipOption(apiObject.DataPointTooltipOption) + } + if apiObject.ExportToCSVOption != nil { + tfMap["export_to_csv_option"] = flattenExportToCSVOption(apiObject.ExportToCSVOption) + } + if apiObject.ExportWithHiddenFieldsOption != nil { + tfMap["export_with_hidden_fields_option"] = flattenExportWithHiddenFieldsOption(apiObject.ExportWithHiddenFieldsOption) + } + if apiObject.SheetControlsOption != nil { + tfMap["sheet_controls_option"] = flattenSheetControlsOption(apiObject.SheetControlsOption) + } + if apiObject.SheetLayoutElementMaximizationOption != nil { + tfMap["sheet_layout_element_maximization_option"] = flattenSheetLayoutElementMaximizationOption(apiObject.SheetLayoutElementMaximizationOption) + } + if apiObject.VisualAxisSortOption != nil { + tfMap["visual_axis_sort_option"] = flattenVisualAxisSortOption(apiObject.VisualAxisSortOption) + } + if apiObject.VisualMenuOption != nil { + tfMap["visual_menu_option"] = flattenVisualMenuOption(apiObject.VisualMenuOption) + } + + return []interface{}{tfMap} +} + +func flattenAdHocFilteringOption(apiObject *quicksight.AdHocFilteringOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AvailabilityStatus != nil { + tfMap["availability_status"] = aws.StringValue(apiObject.AvailabilityStatus) + } + + return []interface{}{tfMap} +} + +func flattenDataPointDrillUpDownOption(apiObject *quicksight.DataPointDrillUpDownOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AvailabilityStatus != nil { + tfMap["availability_status"] = aws.StringValue(apiObject.AvailabilityStatus) + } + + return []interface{}{tfMap} +} + +func flattenDataPointMenuLabelOption(apiObject *quicksight.DataPointMenuLabelOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AvailabilityStatus != nil { + tfMap["availability_status"] = aws.StringValue(apiObject.AvailabilityStatus) + } + + return []interface{}{tfMap} +} + +func flattenDataPointTooltipOption(apiObject *quicksight.DataPointTooltipOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AvailabilityStatus != nil { + tfMap["availability_status"] = aws.StringValue(apiObject.AvailabilityStatus) + } + + return []interface{}{tfMap} +} + +func flattenExportToCSVOption(apiObject *quicksight.ExportToCSVOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AvailabilityStatus != nil { + tfMap["availability_status"] = aws.StringValue(apiObject.AvailabilityStatus) + } + + return []interface{}{tfMap} +} + +func flattenExportWithHiddenFieldsOption(apiObject *quicksight.ExportWithHiddenFieldsOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AvailabilityStatus != nil { + tfMap["availability_status"] = aws.StringValue(apiObject.AvailabilityStatus) + } + + return []interface{}{tfMap} +} + +func flattenSheetControlsOption(apiObject *quicksight.SheetControlsOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.VisibilityState != nil { + tfMap["visibility_state"] = aws.StringValue(apiObject.VisibilityState) + } + + return []interface{}{tfMap} +} + +func flattenSheetLayoutElementMaximizationOption(apiObject *quicksight.SheetLayoutElementMaximizationOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AvailabilityStatus != nil { + tfMap["availability_status"] = aws.StringValue(apiObject.AvailabilityStatus) + } + + return []interface{}{tfMap} +} + +func flattenVisualAxisSortOption(apiObject *quicksight.VisualAxisSortOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AvailabilityStatus != nil { + tfMap["availability_status"] = aws.StringValue(apiObject.AvailabilityStatus) + } + + return []interface{}{tfMap} +} + +func flattenVisualMenuOption(apiObject *quicksight.VisualMenuOption) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + if apiObject.AvailabilityStatus != nil { + tfMap["availability_status"] = aws.StringValue(apiObject.AvailabilityStatus) + } + + return []interface{}{tfMap} +} diff --git a/internal/service/quicksight/schema/dataset.go b/internal/service/quicksight/schema/dataset.go new file mode 100644 index 000000000000..6ef5737cbeb7 --- /dev/null +++ b/internal/service/quicksight/schema/dataset.go @@ -0,0 +1,109 @@ +package schema + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/quicksight" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func dataSetIdentifierDeclarationsSchema() *schema.Schema { + return &schema.Schema{ // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataSetIdentifierDeclaration.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 50, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "data_set_arn": stringSchema(false, verify.ValidARN), + "identifier": stringSchema(false, validation.StringLenBetween(1, 2048)), + }, + }, + } +} + +func dataSetReferencesSchema() *schema.Schema { + return &schema.Schema{ // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataSetReference.html + Type: schema.TypeList, + Required: true, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "data_set_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "data_set_placeholder": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + } +} + +func expandDataSetIdentifierDeclarations(tfList []interface{}) []*quicksight.DataSetIdentifierDeclaration { + if len(tfList) == 0 { + return nil + } + + var identifiers []*quicksight.DataSetIdentifierDeclaration + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + if !ok { + continue + } + + identifier := expandDataSetIdentifierDeclaration(tfMap) + if identifier == nil { + continue + } + + identifiers = append(identifiers, identifier) + } + + return identifiers +} + +func expandDataSetIdentifierDeclaration(tfMap map[string]interface{}) *quicksight.DataSetIdentifierDeclaration { + if tfMap == nil { + return nil + } + + identifier := &quicksight.DataSetIdentifierDeclaration{} + + if v, ok := tfMap["data_set_arn"].(string); ok && v != "" { + identifier.DataSetArn = aws.String(v) + } + if v, ok := tfMap["identifier"].(string); ok && v != "" { + identifier.Identifier = aws.String(v) + } + + return identifier +} + +func flattenDataSetIdentifierDeclarations(apiObject []*quicksight.DataSetIdentifierDeclaration) []interface{} { + if len(apiObject) == 0 { + return nil + } + + var tfList []interface{} + for _, identifier := range apiObject { + if identifier == nil { + continue + } + + tfMap := map[string]interface{}{} + if identifier.DataSetArn != nil { + tfMap["data_set_arn"] = aws.StringValue(identifier.DataSetArn) + } + if identifier.Identifier != nil { + tfMap["identifier"] = aws.StringValue(identifier.Identifier) + } + tfList = append(tfList, tfMap) + } + + return tfList +} diff --git a/internal/service/quicksight/schema/parameters.go b/internal/service/quicksight/schema/parameters.go new file mode 100644 index 000000000000..2c5f90363f2b --- /dev/null +++ b/internal/service/quicksight/schema/parameters.go @@ -0,0 +1,291 @@ +package schema + +import ( + "regexp" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/quicksight" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func ParametersSchema() *schema.Schema { + return &schema.Schema{ // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_Parameters.html + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "date_time_parameters": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DateTimeParameter.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": stringSchema(true, validation.StringMatch(regexp.MustCompile(`.*\S.*`), "")), + "values": { + Type: schema.TypeList, + MinItems: 1, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidUTCTimestamp, + }, + }, + }, + }, + }, + "decimal_parameters": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DecimalParameter.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": stringSchema(true, validation.StringMatch(regexp.MustCompile(`.*\S.*`), "")), + "values": { + Type: schema.TypeList, + MinItems: 1, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeFloat, + }, + }, + }, + }, + }, + "integer_parameters": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_IntegerParameter.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": stringSchema(true, validation.StringMatch(regexp.MustCompile(`.*\S.*`), "")), + "values": { + Type: schema.TypeList, + MinItems: 1, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "string_parameters": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_StringParameter.html + Type: schema.TypeList, + MinItems: 1, + MaxItems: 100, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": stringSchema(true, validation.StringMatch(regexp.MustCompile(`.*\S.*`), "")), + "values": { + Type: schema.TypeList, + MinItems: 1, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + } +} + +func ExpandParameters(tfList []interface{}) *quicksight.Parameters { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + tfMap, ok := tfList[0].(map[string]interface{}) + if !ok { + return nil + } + + parameters := &quicksight.Parameters{} + + if v, ok := tfMap["date_time_parameters"].([]interface{}); ok && len(v) > 0 { + parameters.DateTimeParameters = expandDateTimeParameters(v) + } + if v, ok := tfMap["decimal_parameters"].([]interface{}); ok && len(v) > 0 { + parameters.DecimalParameters = expandDecimalParameters(v) + } + if v, ok := tfMap["integer_parameters"].([]interface{}); ok && len(v) > 0 { + parameters.IntegerParameters = expandIntegerParameters(v) + } + if v, ok := tfMap["string_parameters"].([]interface{}); ok && len(v) > 0 { + parameters.StringParameters = expandStringParameters(v) + } + + return parameters +} + +func expandDateTimeParameters(tfList []interface{}) []*quicksight.DateTimeParameter { + if len(tfList) == 0 { + return nil + } + + var parameters []*quicksight.DateTimeParameter + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + if !ok { + continue + } + + parameter := expandDateTimeParameter(tfMap) + if parameter == nil { + continue + } + + parameters = append(parameters, parameter) + } + + return parameters +} + +func expandDateTimeParameter(tfMap map[string]interface{}) *quicksight.DateTimeParameter { + if tfMap == nil { + return nil + } + + parameter := &quicksight.DateTimeParameter{} + + if v, ok := tfMap["name"].(string); ok && v != "" { + parameter.Name = aws.String(v) + } + if v, ok := tfMap["values"].([]interface{}); ok && len(v) > 0 { + parameter.Values = flex.ExpandStringTimeList(v, time.RFC3339) + } + + return parameter +} + +func expandDecimalParameters(tfList []interface{}) []*quicksight.DecimalParameter { + if len(tfList) == 0 { + return nil + } + + var parameters []*quicksight.DecimalParameter + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + if !ok { + continue + } + + parameter := expandDecimalParameter(tfMap) + if parameter == nil { + continue + } + + parameters = append(parameters, parameter) + } + + return parameters +} + +func expandDecimalParameter(tfMap map[string]interface{}) *quicksight.DecimalParameter { + if tfMap == nil { + return nil + } + + parameter := &quicksight.DecimalParameter{} + + if v, ok := tfMap["name"].(string); ok && v != "" { + parameter.Name = aws.String(v) + } + if v, ok := tfMap["values"].([]interface{}); ok && len(v) > 0 { + parameter.Values = flex.ExpandFloat64List(v) + } + + return parameter +} + +func expandIntegerParameters(tfList []interface{}) []*quicksight.IntegerParameter { + if len(tfList) == 0 { + return nil + } + + var parameters []*quicksight.IntegerParameter + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + if !ok { + continue + } + + parameter := expandIntegerParameter(tfMap) + if parameter == nil { + continue + } + + parameters = append(parameters, parameter) + } + + return parameters +} + +func expandIntegerParameter(tfMap map[string]interface{}) *quicksight.IntegerParameter { + if tfMap == nil { + return nil + } + + parameter := &quicksight.IntegerParameter{} + + if v, ok := tfMap["name"].(string); ok && v != "" { + parameter.Name = aws.String(v) + } + if v, ok := tfMap["values"].([]interface{}); ok && len(v) > 0 { + parameter.Values = flex.ExpandInt64List(v) + } + + return parameter +} + +func expandStringParameters(tfList []interface{}) []*quicksight.StringParameter { + if len(tfList) == 0 { + return nil + } + + var parameters []*quicksight.StringParameter + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + if !ok { + continue + } + + parameter := expandStringParameter(tfMap) + if parameter == nil { + continue + } + + parameters = append(parameters, parameter) + } + + return parameters +} + +func expandStringParameter(tfMap map[string]interface{}) *quicksight.StringParameter { + if tfMap == nil { + return nil + } + + parameter := &quicksight.StringParameter{} + + if v, ok := tfMap["name"].(string); ok && v != "" { + parameter.Name = aws.String(v) + } + if v, ok := tfMap["values"].([]interface{}); ok && len(v) > 0 { + parameter.Values = flex.ExpandStringList(v) + } + + return parameter +} diff --git a/internal/service/quicksight/schema/template.go b/internal/service/quicksight/schema/template.go index ed00d3ba7d3c..eabdca532a40 100644 --- a/internal/service/quicksight/schema/template.go +++ b/internal/service/quicksight/schema/template.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/verify" ) -func DefinitionSchema() *schema.Schema { +func TemplateDefinitionSchema() *schema.Schema { return &schema.Schema{ // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_TemplateVersionDefinition.html Type: schema.TypeList, MaxItems: 1, @@ -321,7 +321,7 @@ func rollingDateConfigurationSchema() *schema.Schema { } } -func SourceEntitySchema() *schema.Schema { +func TemplateSourceEntitySchema() *schema.Schema { return &schema.Schema{ Type: schema.TypeList, MaxItems: 1, @@ -344,24 +344,7 @@ func SourceEntitySchema() *schema.Schema { Required: true, ValidateFunc: verify.ValidARN, }, - "data_set_references": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "data_set_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "data_set_placeholder": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, + "data_set_references": dataSetReferencesSchema(), // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataSetReference.html }, }, }, @@ -385,7 +368,7 @@ func SourceEntitySchema() *schema.Schema { } } -func ExpandSourceEntity(tfList []interface{}) *quicksight.TemplateSourceEntity { +func ExpandTemplateSourceEntity(tfList []interface{}) *quicksight.TemplateSourceEntity { if len(tfList) == 0 || tfList[0] == nil { return nil } @@ -400,7 +383,7 @@ func ExpandSourceEntity(tfList []interface{}) *quicksight.TemplateSourceEntity { if v, ok := tfMap["source_analysis"].([]interface{}); ok && len(v) > 0 { sourceEntity.SourceAnalysis = expandSourceAnalysis(v[0].(map[string]interface{})) } else if v, ok := tfMap["source_template"].([]interface{}); ok && len(v) > 0 { - sourceEntity.SourceTemplate = expandSourceTemplate(v[0].(map[string]interface{})) + sourceEntity.SourceTemplate = expandTemplateSourceTemplate(v[0].(map[string]interface{})) } return sourceEntity @@ -461,7 +444,7 @@ func expandDataSetReference(tfMap map[string]interface{}) *quicksight.DataSetRef return dataSetReference } -func expandSourceTemplate(tfMap map[string]interface{}) *quicksight.TemplateSourceTemplate { +func expandTemplateSourceTemplate(tfMap map[string]interface{}) *quicksight.TemplateSourceTemplate { if tfMap == nil { return nil } @@ -474,7 +457,7 @@ func expandSourceTemplate(tfMap map[string]interface{}) *quicksight.TemplateSour return sourceTemplate } -func ExpandDefinition(tfList []interface{}) *quicksight.TemplateVersionDefinition { +func ExpandTemplateDefinition(tfList []interface{}) *quicksight.TemplateVersionDefinition { if len(tfList) == 0 || tfList[0] == nil { return nil } diff --git a/internal/service/quicksight/schema/template_parameter.go b/internal/service/quicksight/schema/template_parameter.go index fd5d27135157..1e002469c958 100644 --- a/internal/service/quicksight/schema/template_parameter.go +++ b/internal/service/quicksight/schema/template_parameter.go @@ -551,7 +551,7 @@ func expandDecimalValueWhenUnsetConfiguration(tfList []interface{}) *quicksight. config := &quicksight.DecimalValueWhenUnsetConfiguration{} - if v, ok := tfMap["custom_value"].(float64); ok { + if v, ok := tfMap["custom_value"].(float64); ok && v != 0.0 { config.CustomValue = aws.Float64(v) } if v, ok := tfMap["value_when_unset_option"].(string); ok && v != "" { @@ -623,7 +623,7 @@ func expandIntegerValueWhenUnsetConfiguration(tfList []interface{}) *quicksight. config := &quicksight.IntegerValueWhenUnsetConfiguration{} - if v, ok := tfMap["custom_value"].(int); ok { + if v, ok := tfMap["custom_value"].(int); ok && v != 0 { config.CustomValue = aws.Int64(int64(v)) } if v, ok := tfMap["value_when_unset_option"].(string); ok && v != "" { @@ -695,7 +695,7 @@ func expandStringValueWhenUnsetConfiguration(tfList []interface{}) *quicksight.S config := &quicksight.StringValueWhenUnsetConfiguration{} - if v, ok := tfMap["custom_value"].(string); ok { + if v, ok := tfMap["custom_value"].(string); ok && v != "" { config.CustomValue = aws.String(v) } if v, ok := tfMap["value_when_unset_option"].(string); ok && v != "" { diff --git a/internal/service/quicksight/schema/template_sheet.go b/internal/service/quicksight/schema/template_sheet.go index ddd8309b0afb..c79b2b71fcc2 100644 --- a/internal/service/quicksight/schema/template_sheet.go +++ b/internal/service/quicksight/schema/template_sheet.go @@ -756,6 +756,9 @@ func expandGridLayoutScreenCanvasSizeOptions(tfList []interface{}) *quicksight.G if v, ok := tfMap["optimized_view_port_width"].(string); ok && v != "" { options.OptimizedViewPortWidth = aws.String(v) } + if v, ok := tfMap["resize_option"].(string); ok && v != "" { + options.ResizeOption = aws.String(v) + } return options } @@ -1270,16 +1273,16 @@ func expandGridLayoutElement(tfMap map[string]interface{}) *quicksight.GridLayou if v, ok := tfMap["element_type"].(string); ok && v != "" { layout.ElementType = aws.String(v) } - if v, ok := tfMap["column_span"].(int); ok { + if v, ok := tfMap["column_span"].(int); ok && v != 0 { layout.ColumnSpan = aws.Int64(int64(v)) } - if v, ok := tfMap["row_span"].(int); ok { + if v, ok := tfMap["row_span"].(int); ok && v != 0 { layout.RowSpan = aws.Int64(int64(v)) } - if v, ok := tfMap["column_index"].(int); ok { + if v, ok := tfMap["column_index"].(int); ok && v != 0 { layout.ColumnIndex = aws.Int64(int64(v)) } - if v, ok := tfMap["row_index"].(int); ok { + if v, ok := tfMap["row_index"].(int); ok && v != 0 { layout.RowIndex = aws.Int64(int64(v)) } @@ -2089,6 +2092,8 @@ func flattenGridLayoutElement(apiObject []*quicksight.GridLayoutElement) []inter } if config.ColumnIndex != nil { tfMap["column_index"] = aws.Int64Value(config.ColumnIndex) + } else { + } if config.RowIndex != nil { tfMap["row_index"] = aws.Int64Value(config.RowIndex) diff --git a/internal/service/quicksight/service_package_gen.go b/internal/service/quicksight/service_package_gen.go index d5b164541a50..37a3da54b442 100644 --- a/internal/service/quicksight/service_package_gen.go +++ b/internal/service/quicksight/service_package_gen.go @@ -81,6 +81,13 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka TypeName: "aws_quicksight_account_subscription", Name: "Account Subscription", }, + { + Factory: ResourceDashboard, + TypeName: "aws_quicksight_dashboard", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: "arn", + }, + }, { Factory: ResourceDataSet, TypeName: "aws_quicksight_data_set", diff --git a/internal/service/quicksight/status.go b/internal/service/quicksight/status.go index 7e8ec69e4925..45082f1577fe 100644 --- a/internal/service/quicksight/status.go +++ b/internal/service/quicksight/status.go @@ -46,3 +46,19 @@ func statusTemplate(ctx context.Context, conn *quicksight.QuickSight, id string) return out, *out.Version.Status, nil } } + +// Fetch Dashboard status +func statusDashboard(ctx context.Context, conn *quicksight.QuickSight, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + out, err := FindDashboardByID(ctx, conn, id) + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return out, *out.Version.Status, nil + } +} diff --git a/internal/service/quicksight/template.go b/internal/service/quicksight/template.go index 36a0583478bd..2bbbc994c356 100644 --- a/internal/service/quicksight/template.go +++ b/internal/service/quicksight/template.go @@ -58,7 +58,7 @@ func ResourceTemplate() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "definition": quicksightschema.DefinitionSchema(), + "definition": quicksightschema.TemplateDefinitionSchema(), "last_updated_time": { Type: schema.TypeString, Computed: true, @@ -90,7 +90,7 @@ func ResourceTemplate() *schema.Resource { }, }, }, - "source_entity": quicksightschema.SourceEntitySchema(), + "source_entity": quicksightschema.TemplateSourceEntitySchema(), "source_entity_arn": { Type: schema.TypeString, Computed: true, @@ -147,11 +147,11 @@ func resourceTemplateCreate(ctx context.Context, d *schema.ResourceData, meta in } if v, ok := d.GetOk("source_entity"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - input.SourceEntity = quicksightschema.ExpandSourceEntity(v.([]interface{})) + input.SourceEntity = quicksightschema.ExpandTemplateSourceEntity(v.([]interface{})) } if v, ok := d.GetOk("definition"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { - input.Definition = quicksightschema.ExpandDefinition(d.Get("definition").([]interface{})) + input.Definition = quicksightschema.ExpandTemplateDefinition(d.Get("definition").([]interface{})) } if v, ok := d.GetOk("permissions"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { @@ -246,13 +246,11 @@ func resourceTemplateUpdate(ctx context.Context, d *schema.ResourceData, meta in Name: aws.String(d.Get("name").(string)), VersionDescription: aws.String(d.Get("version_description").(string)), } - - if d.HasChange("source_entity") { - in.SourceEntity = quicksightschema.ExpandSourceEntity(d.Get("source_entity").([]interface{})) - } - - if d.HasChange("definition") { - in.Definition = quicksightschema.ExpandDefinition(d.Get("definition").([]interface{})) + _, createdFromEntity := d.GetOk("source_entity") + if createdFromEntity { + in.SourceEntity = quicksightschema.ExpandTemplateSourceEntity(d.Get("source_entity").([]interface{})) + } else { + in.Definition = quicksightschema.ExpandTemplateDefinition(d.Get("definition").([]interface{})) } log.Printf("[DEBUG] Updating QuickSight Template (%s): %#v", d.Id(), in) diff --git a/internal/service/quicksight/template_test.go b/internal/service/quicksight/template_test.go index f2a0f01ed34f..655c5b8b6e01 100644 --- a/internal/service/quicksight/template_test.go +++ b/internal/service/quicksight/template_test.go @@ -260,6 +260,58 @@ func TestAccQuickSightTemplate_tags(t *testing.T) { }) } +func TestAccQuickSightTemplate_update(t *testing.T) { + ctx := acctest.Context(t) + + var template quicksight.Template + resourceName := "aws_quicksight_template.copy" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rId := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + sourceName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + sourceId := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, quicksight.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTemplateDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTemplateConfig_TemplateSourceEntity(rId, rName, sourceId, sourceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTemplateExists(ctx, resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "template_id", rId), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "status", quicksight.ResourceStatusCreationSuccessful), + acctest.CheckResourceAttrRegionalARN(resourceName, "source_entity.0.source_template.0.arn", "quicksight", fmt.Sprintf("template/%s", sourceId)), + resource.TestCheckResourceAttr(resourceName, "version_number", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"source_entity"}, + }, + + { + Config: testAccTemplateConfig_TemplateSourceEntity(rId, rNameUpdated, sourceId, sourceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTemplateExists(ctx, resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "template_id", rId), + resource.TestCheckResourceAttr(resourceName, "name", rNameUpdated), + resource.TestCheckResourceAttr(resourceName, "status", quicksight.ResourceStatusCreationSuccessful), + acctest.CheckResourceAttrRegionalARN(resourceName, "source_entity.0.source_template.0.arn", "quicksight", fmt.Sprintf("template/%s", sourceId)), + resource.TestCheckResourceAttr(resourceName, "version_number", "2"), + ), + }, + }, + }) +} + func testAccCheckTemplateDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).QuickSightConn() diff --git a/internal/service/quicksight/wait.go b/internal/service/quicksight/wait.go index 609ee1f11337..e582d00262fa 100644 --- a/internal/service/quicksight/wait.go +++ b/internal/service/quicksight/wait.go @@ -95,7 +95,7 @@ func waitTemplateCreated(ctx context.Context, conn *quicksight.QuickSight, id st func waitTemplateUpdated(ctx context.Context, conn *quicksight.QuickSight, id string, timeout time.Duration) (*quicksight.Template, error) { stateConf := &retry.StateChangeConf{ - Pending: []string{quicksight.ResourceStatusUpdateInProgress}, + Pending: []string{quicksight.ResourceStatusUpdateInProgress, quicksight.ResourceStatusCreationInProgress}, Target: []string{quicksight.ResourceStatusUpdateSuccessful, quicksight.ResourceStatusCreationSuccessful}, Refresh: statusTemplate(ctx, conn, id), Timeout: timeout, @@ -122,3 +122,63 @@ func waitTemplateUpdated(ctx context.Context, conn *quicksight.QuickSight, id st return nil, err } + +func waitDashboardCreated(ctx context.Context, conn *quicksight.QuickSight, id string, timeout time.Duration) (*quicksight.Dashboard, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{quicksight.ResourceStatusCreationInProgress}, + Target: []string{quicksight.ResourceStatusCreationSuccessful}, + Refresh: statusDashboard(ctx, conn, id), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*quicksight.Dashboard); ok { + if status, apiErrors := aws.StringValue(out.Version.Status), out.Version.Errors; status == quicksight.ResourceStatusCreationFailed && apiErrors != nil { + var errors *multierror.Error + + for _, apiError := range apiErrors { + if apiError == nil { + continue + } + errors = multierror.Append(errors, awserr.New(aws.StringValue(apiError.Type), aws.StringValue(apiError.Message), nil)) + } + tfresource.SetLastError(err, errors) + } + + return out, err + } + + return nil, err +} + +func waitDashboardUpdated(ctx context.Context, conn *quicksight.QuickSight, id string, timeout time.Duration) (*quicksight.Dashboard, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{quicksight.ResourceStatusUpdateInProgress, quicksight.ResourceStatusCreationInProgress}, + Target: []string{quicksight.ResourceStatusUpdateSuccessful, quicksight.ResourceStatusCreationSuccessful}, + Refresh: statusDashboard(ctx, conn, id), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*quicksight.Dashboard); ok { + if status, apiErrors := aws.StringValue(out.Version.Status), out.Version.Errors; status == quicksight.ResourceStatusCreationFailed && apiErrors != nil { + var errors *multierror.Error + + for _, apiError := range apiErrors { + if apiError == nil { + continue + } + errors = multierror.Append(errors, awserr.New(aws.StringValue(apiError.Type), aws.StringValue(apiError.Message), nil)) + } + tfresource.SetLastError(err, errors) + } + + return out, err + } + + return nil, err +} diff --git a/website/docs/r/quicksight_dashboard.html.markdown b/website/docs/r/quicksight_dashboard.html.markdown new file mode 100644 index 000000000000..649eaa53c35d --- /dev/null +++ b/website/docs/r/quicksight_dashboard.html.markdown @@ -0,0 +1,162 @@ +--- +subcategory: "QuickSight" +layout: "aws" +page_title: "AWS: aws_quicksight_dashboard" +description: |- + Manages a QuickSight Dashboard. +--- + +# Resource: aws_quicksight_dashboard + +Resource for managing a QuickSight Dashboard. + +## Example Usage + +### From Source Template + +```terraform +resource "aws_quicksight_dashboard" "test" { + dashboard_id = "example-id" + name = "example-name" + version_description = "version" + source_entity { + source_template { + arn = aws_quicksight_template.source.arn + data_set_references { + data_set_arn = aws_quicksight_data_set.dataset.arn + data_set_placeholder = "1" + } + } + } +} +``` + +### With Definition + +```terraform +resource "aws_quicksight_dashboard" "example" { + dashboard_id = "example-id" + name = "example-name" + version_description = "example" + definition { + data_set_identifiers_declarations { + data_set_arn = aws_quicksight_data_set.dataset.arn + identifier = "1" + } + sheets { + title = "Example" + sheet_id = "Example1" + visuals { + line_chart_visual { + visual_id = "LineChart" + title { + format_text { + plain_text = "Line Chart Example" + } + } + chart_configuration { + field_wells { + line_chart_aggregated_field_wells { + category { + categorical_dimension_field { + field_id = "1" + column { + data_set_identifier = "1" + column_name = "Column1" + } + } + } + values { + categorical_measure_field { + field_id = "2" + column { + data_set_identifier = "1" + column_name = "Column1" + } + aggregation_function = "COUNT" + } + } + } + } + } + } + } + } + } +} +``` + +## Argument Reference + +The following arguments are required: + +* `dashboard_id` - (Required, Forces new resource) Identifier for the dashboard. +* `name` - (Required) Display name for the dashboard. +* `version_description` - (Required) A description of the current dashboard version being created/updated. + +The following arguments are optional: + +* `aws_account_id` - (Optional, Forces new resource) AWS account ID. +* `definition` - (Optional) A detailed dashboard definition. Only one of `definition` or `source_entity` should be configured. See [definition](#definition). +* `permissions` - (Optional) A set of resource permissions on the dashboard. Maximum of 64 items. See [permissions](#permissions). +* `source_entity` - (Optional) The entity that you are using as a source when you create the dashboard (template). Only one of `definition` or `source_entity` should be configured. See [source_entity](#source_entity). +* `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +* `theme_arn` - (Optional) The Amazon Resource Name (ARN) of the theme that is being used for this dashboard. The theme ARN must exist in the same AWS account where you create the dashboard. + + +### permissions + +* `actions` - (Required) List of IAM actions to grant or revoke permissions on. +* `principal` - (Required) ARN of the principal. See the [ResourcePermission documentation](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ResourcePermission.html) for the applicable ARN values. + +### source_entity + +* `source_template` - (Optional) The source template. See [source_template](#source_template). + +### data_set_references + +* `data_set_arn` - (Required) Dataset Amazon Resource Name (ARN). +* `data_set_placeholder` - (Required) Dataset placeholder. + +### source_template + +* `arn` - (Required) The Amazon Resource Name (ARN) of the resource. + +### definition + +* `data_set_configuration` - (Required) A list of dataset configurations. These configurations define the required columns for each dataset used within a dashboard. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataSetConfiguration.html). +* `analysis_defaults` - (Optional) The configuration for default analysis settings. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_AnalysisDefaults.html). +* `calculated_fields` - (Optional) A list of calculated field definitions for the dashboard. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_CalculatedField.html). +* `column_configurations` - (Optional) A list of dashboard-level column configurations. Column configurations are used to set default formatting for a column that's used throughout a dashboard. See [AWS API Documentation for complete description](ttps://docs.aws.amazon.com/quicksight/latest/APIReference/API_ColumnConfiguration.html). +* `filter_groups` - (Optional) A list of filter definitions for a dashboard. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_FilterGroup.html). For more information, see [Filtering Data](https://docs.aws.amazon.com/quicksight/latest/user/filtering-visual-data.html) in Amazon QuickSight User Guide. +* `parameters_declarations` - (Optional) A list of parameter declarations for a dashboard. Parameters are named variables that can transfer a value for use by an action or an object. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ParameterDeclaration.html). For more information, see [Parameters in Amazon QuickSight](https://docs.aws.amazon.com/quicksight/latest/user/parameters-in-quicksight.html) in the Amazon QuickSight User Guide. +* `sheets` - (Optional) A list of sheet definitions for a dashboard. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_SheetDefinition.html). + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the dashboard. +* `created_time` - The time that the dashboard was created. +* `id` - A comma-delimited string joining AWS account ID and dashboard ID. +* `last_updated_time` - The time that the dashboard was last updated. +* `source_entity_arn` - Amazon Resource Name (ARN) of a template that was used to create this dashboard. +* `status` - The dashboard creation status. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block). +* `version_number` - The version number of the dashboard version. + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `5m`) +* `update` - (Default `5m`) +* `delete` - (Default `5m`) + +## Import + +A QuickSight Template can be imported using the AWS account ID and dashboard ID separated by a comma (`,`) e.g., + +``` +$ terraform import aws_quicksight_dashboard.example 123456789012,example-id +``` From 536e7594cae6041215cfd02323504aeb1b45f798 Mon Sep 17 00:00:00 2001 From: Fabien COMTE Date: Fri, 19 May 2023 15:40:51 +0200 Subject: [PATCH 02/10] Changelog entry and fixes --- .changelog/31448.txt | 3 + internal/service/quicksight/dashboard_test.go | 205 +++++++++--------- .../quicksight/schema/template_sheet.go | 2 - internal/service/quicksight/template.go | 12 +- .../docs/r/quicksight_dashboard.html.markdown | 80 ++++++- 5 files changed, 180 insertions(+), 122 deletions(-) create mode 100644 .changelog/31448.txt diff --git a/.changelog/31448.txt b/.changelog/31448.txt new file mode 100644 index 000000000000..ecf330a5089f --- /dev/null +++ b/.changelog/31448.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_quicksight_dashboard +``` \ No newline at end of file diff --git a/internal/service/quicksight/dashboard_test.go b/internal/service/quicksight/dashboard_test.go index 8743464209c3..f0f8455c58aa 100644 --- a/internal/service/quicksight/dashboard_test.go +++ b/internal/service/quicksight/dashboard_test.go @@ -312,8 +312,8 @@ resource "aws_quicksight_dashboard" "test" { version_description = "test" definition { data_set_identifiers_declarations { - data_set_arn = aws_quicksight_data_set.test.arn - identifier = "1" + data_set_arn = aws_quicksight_data_set.test.arn + identifier = "1" } sheets { title = "Test" @@ -446,18 +446,18 @@ resource "aws_quicksight_template" "test" { } resource "aws_quicksight_dashboard" "test" { - dashboard_id = %[1]q - name = %[2]q - version_description = "test" - source_entity { - source_template { - arn = aws_quicksight_template.test.arn - data_set_references { - data_set_arn = aws_quicksight_data_set.test.arn - data_set_placeholder = "1" - } - } + dashboard_id = %[1]q + name = %[2]q + version_description = "test" + source_entity { + source_template { + arn = aws_quicksight_template.test.arn + data_set_references { + data_set_arn = aws_quicksight_data_set.test.arn + data_set_placeholder = "1" + } } + } } `, rId, rName, sourceId, sourceName)) } @@ -467,109 +467,104 @@ func testAccDashboardConfig_DashboardSpecificConfig(rId, rName string) string { testAccDashboardConfigBase(rId, rName), fmt.Sprintf(` resource "aws_quicksight_dashboard" "test" { - dashboard_id = %[1]q - name = %[2]q - version_description = "test" - - parameters { - string_parameters { - name = "test" - values = ["value"] - } + dashboard_id = %[1]q + name = %[2]q + version_description = "test" + parameters { + string_parameters { + name = "test" + values = ["value"] } - - dashboard_publish_options { - ad_hoc_filtering_option { - availability_status = "DISABLED" - } - data_point_drill_up_down_option { - availability_status = "ENABLED" - } - data_point_menu_label_option { - availability_status = "ENABLED" - } - data_point_tooltip_option { - availability_status = "ENABLED" - } - export_to_csv_option { - availability_status = "ENABLED" - } - export_with_hidden_fields_option { - availability_status = "DISABLED" - } - sheet_controls_option { - visibility_state = "COLLAPSED" - } - sheet_layout_element_maximization_option { - availability_status = "ENABLED" - } - visual_axis_sort_option { - availability_status = "ENABLED" + } + dashboard_publish_options { + ad_hoc_filtering_option { + availability_status = "DISABLED" + } + data_point_drill_up_down_option { + availability_status = "ENABLED" + } + data_point_menu_label_option { + availability_status = "ENABLED" + } + data_point_tooltip_option { + availability_status = "ENABLED" + } + export_to_csv_option { + availability_status = "ENABLED" + } + export_with_hidden_fields_option { + availability_status = "DISABLED" + } + sheet_controls_option { + visibility_state = "COLLAPSED" + } + sheet_layout_element_maximization_option { + availability_status = "ENABLED" + } + visual_axis_sort_option { + availability_status = "ENABLED" + } + visual_menu_option { + availability_status = "ENABLED" + } + } + definition { + data_set_identifiers_declarations { + data_set_arn = aws_quicksight_data_set.test.arn + identifier = "1" + } + parameters_declarations { + string_parameter_declaration { + name = "test" + parameter_value_type = "SINGLE_VALUED" + default_values { + static_values = ["value"] } - visual_menu_option { - availability_status = "ENABLED" + values_when_unset { + value_when_unset_option = "NULL" } + } } - - definition { - data_set_identifiers_declarations { - data_set_arn = aws_quicksight_data_set.test.arn - identifier = "1" - } - - parameters_declarations { - string_parameter_declaration { - name = "test" - parameter_value_type = "SINGLE_VALUED" - default_values { - static_values = ["value"] - } - values_when_unset { - value_when_unset_option = "NULL" - } + sheets { + title = "Example" + sheet_id = "Example1" + visuals { + line_chart_visual { + visual_id = "LineChart" + title { + format_text { + plain_text = "Line Chart Example" } - } - - sheets { - title = "Example" - sheet_id = "Example1" - visuals { - line_chart_visual { - visual_id = "LineChart" - title { - format_text { - plain_text = "Line Chart Example" - } + } + chart_configuration { + field_wells { + line_chart_aggregated_field_wells { + category { + categorical_dimension_field { + field_id = "1" + column { + data_set_identifier = "1" + column_name = "Column1" } - chart_configuration { - field_wells { - line_chart_aggregated_field_wells { - category { - categorical_dimension_field { - field_id = "1" - column { - data_set_identifier = "1" - column_name = "Column1" - } - } - } - values { - categorical_measure_field { - field_id = "2" - column { - data_set_identifier = "1" - column_name = "Column1" - } - aggregation_function = "COUNT" - } - } - } - } + } + } + values { + categorical_measure_field { + field_id = "2" + column { + data_set_identifier = "1" + column_name = "Column1" } + aggregation_function = "COUNT" + } } + } } + } } + } } + } } `, rId, rName)) } diff --git a/internal/service/quicksight/schema/template_sheet.go b/internal/service/quicksight/schema/template_sheet.go index c79b2b71fcc2..3c10c89a000f 100644 --- a/internal/service/quicksight/schema/template_sheet.go +++ b/internal/service/quicksight/schema/template_sheet.go @@ -2092,8 +2092,6 @@ func flattenGridLayoutElement(apiObject []*quicksight.GridLayoutElement) []inter } if config.ColumnIndex != nil { tfMap["column_index"] = aws.Int64Value(config.ColumnIndex) - } else { - } if config.RowIndex != nil { tfMap["row_index"] = aws.Int64Value(config.RowIndex) diff --git a/internal/service/quicksight/template.go b/internal/service/quicksight/template.go index 2bbbc994c356..cc3d7281252e 100644 --- a/internal/service/quicksight/template.go +++ b/internal/service/quicksight/template.go @@ -246,12 +246,12 @@ func resourceTemplateUpdate(ctx context.Context, d *schema.ResourceData, meta in Name: aws.String(d.Get("name").(string)), VersionDescription: aws.String(d.Get("version_description").(string)), } - _, createdFromEntity := d.GetOk("source_entity") - if createdFromEntity { - in.SourceEntity = quicksightschema.ExpandTemplateSourceEntity(d.Get("source_entity").([]interface{})) - } else { - in.Definition = quicksightschema.ExpandTemplateDefinition(d.Get("definition").([]interface{})) - } + //_, createdFromEntity := d.GetOk("source_entity") + //if createdFromEntity { + in.SourceEntity = quicksightschema.ExpandTemplateSourceEntity(d.Get("source_entity").([]interface{})) + //} else { + in.Definition = quicksightschema.ExpandTemplateDefinition(d.Get("definition").([]interface{})) + //} log.Printf("[DEBUG] Updating QuickSight Template (%s): %#v", d.Id(), in) _, err := conn.UpdateTemplateWithContext(ctx, in) diff --git a/website/docs/r/quicksight_dashboard.html.markdown b/website/docs/r/quicksight_dashboard.html.markdown index 649eaa53c35d..102a8baac975 100644 --- a/website/docs/r/quicksight_dashboard.html.markdown +++ b/website/docs/r/quicksight_dashboard.html.markdown @@ -15,7 +15,7 @@ Resource for managing a QuickSight Dashboard. ### From Source Template ```terraform -resource "aws_quicksight_dashboard" "test" { +resource "aws_quicksight_dashboard" "example" { dashboard_id = "example-id" name = "example-name" version_description = "version" @@ -37,11 +37,11 @@ resource "aws_quicksight_dashboard" "test" { resource "aws_quicksight_dashboard" "example" { dashboard_id = "example-id" name = "example-name" - version_description = "example" + version_description = "version" definition { data_set_identifiers_declarations { - data_set_arn = aws_quicksight_data_set.dataset.arn - identifier = "1" + data_set_arn = aws_quicksight_data_set.dataset.arn + identifier = "1" } sheets { title = "Example" @@ -97,13 +97,14 @@ The following arguments are required: The following arguments are optional: * `aws_account_id` - (Optional, Forces new resource) AWS account ID. +* `dashboard_publish_options` - (Optional) Options for publishing the dashboard. See [dashboard_publish_options](#dashboard_publish_options). * `definition` - (Optional) A detailed dashboard definition. Only one of `definition` or `source_entity` should be configured. See [definition](#definition). +* `parameters` - (Optional) The parameters for the creation of the dashboard, which you want to use to override the default settings. A dashboard can have any type of parameters, and some parameters might accept multiple values. See [parameters](#parameters). * `permissions` - (Optional) A set of resource permissions on the dashboard. Maximum of 64 items. See [permissions](#permissions). * `source_entity` - (Optional) The entity that you are using as a source when you create the dashboard (template). Only one of `definition` or `source_entity` should be configured. See [source_entity](#source_entity). * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. * `theme_arn` - (Optional) The Amazon Resource Name (ARN) of the theme that is being used for this dashboard. The theme ARN must exist in the same AWS account where you create the dashboard. - ### permissions * `actions` - (Required) List of IAM actions to grant or revoke permissions on. @@ -113,18 +114,79 @@ The following arguments are optional: * `source_template` - (Optional) The source template. See [source_template](#source_template). +### source_template + +* `arn` - (Required) The Amazon Resource Name (ARN) of the resource. +* `data_set_references` - (Required) List of dataset references. See [data_set_references](#data_set_references). + ### data_set_references * `data_set_arn` - (Required) Dataset Amazon Resource Name (ARN). * `data_set_placeholder` - (Required) Dataset placeholder. -### source_template +### dashboard_publish_options -* `arn` - (Required) The Amazon Resource Name (ARN) of the resource. +* `ad_hoc_filtering_option` - (Optional) Ad hoc (one-time) filtering option. See [ad_hoc_filtering_option](#ad_hoc_filtering_option). +* `data_point_drill_up_down_option` - (Optional) The drill-down options of data points in a dashboard. See [data_point_drill_up_down_option](#data_point_drill_up_down_option). +* `data_point_menu_label_option` - (Optional) The data point menu label options of a dashboard. See [data_point_menu_label_option](#data_point_menu_label_option). +* `data_point_tooltip_option` - (Optional) The data point tool tip options of a dashboard. See [data_point_tooltip_option](#data_point_tooltip_option). +* `export_to_csv_option` - (Optional) Export to .csv option. See [export_to_csv_option](#export_to_csv_option). +* `export_with_hidden_fields_option` - (Optional) Determines if hidden fields are exported with a dashboard. See [export_with_hidden_fields_option](#export_with_hidden_fields_option). +* `sheet_controls_option` - (Optional) Sheet controls option. See [sheet_controls_option](#sheet_controls_option). +* `sheet_layout_element_maximization_option` - (Optional) The sheet layout maximization options of a dashbaord. See [sheet_layout_element_maximization_option](#sheet_layout_element_maximization_option). +* `visual_axis_sort_option` - (Optional) The axis sort options of a dashboard. See [visual_axis_sort_option](#visual_axis_sort_option). +* `visual_menu_option` - (Optional) The menu options of a visual in a dashboard. See [visual_menu_option](#visual_menu_option). + +### ad_hoc_filtering_option + +* `availability_status` - (Optional) Availability status. Possibles values: ENABLED, DISABLED. + +### data_point_drill_up_down_option + +* `availability_status` - (Optional) Availability status. Possibles values: ENABLED, DISABLED. + +### data_point_menu_label_option + +* `availability_status` - (Optional) Availability status. Possibles values: ENABLED, DISABLED. + +### data_point_tooltip_option + +* `availability_status` - (Optional) Availability status. Possibles values: ENABLED, DISABLED. + +### export_to_csv_option + +* `availability_status` - (Optional) Availability status. Possibles values: ENABLED, DISABLED. + +### export_with_hidden_fields_option + +* `availability_status` - (Optional) Availability status. Possibles values: ENABLED, DISABLED. + +### sheet_controls_option + +* `visibility_state` - (Optional) Visibility state. Possibles values: EXPANDED, COLLAPSED. + +### sheet_layout_element_maximization_option + +* `availability_status` - (Optional) Availability status. Possibles values: ENABLED, DISABLED. + +### visual_axis_sort_option + +* `availability_status` - (Optional) Availability status. Possibles values: ENABLED, DISABLED. + +### visual_menu_option + +* `availability_status` - (Optional) Availability status. Possibles values: ENABLED, DISABLED. + +### parameters + +* `date_time_parameters` - (Optional) A list of parameters that have a data type of date-time. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DateTimeParameter.html). +* `decimal_parameters` - (Optional) A list of parameters that have a data type of decimal. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DecimalParameter.html). +* `integer_parameters` - (Optional) A list of parameters that have a data type of integer. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_IntegerParameter.html). +* `string_parameters` - (Optional) A list of parameters that have a data type of string. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_StringParameter.html). ### definition -* `data_set_configuration` - (Required) A list of dataset configurations. These configurations define the required columns for each dataset used within a dashboard. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataSetConfiguration.html). +* `data_set_identifiers_declarations` - (Required) A list dataset identifier declarations. With this mapping,you can use dataset identifiers instead of dataset Amazon Resource Names (ARNs) throughout the dashboard's sub-structures. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DataSetIdentifierDeclaration.html). * `analysis_defaults` - (Optional) The configuration for default analysis settings. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_AnalysisDefaults.html). * `calculated_fields` - (Optional) A list of calculated field definitions for the dashboard. See [AWS API Documentation for complete description](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_CalculatedField.html). * `column_configurations` - (Optional) A list of dashboard-level column configurations. Column configurations are used to set default formatting for a column that's used throughout a dashboard. See [AWS API Documentation for complete description](ttps://docs.aws.amazon.com/quicksight/latest/APIReference/API_ColumnConfiguration.html). @@ -155,7 +217,7 @@ In addition to all arguments above, the following attributes are exported: ## Import -A QuickSight Template can be imported using the AWS account ID and dashboard ID separated by a comma (`,`) e.g., +A QuickSight Dashboard can be imported using the AWS account ID and dashboard ID separated by a comma (`,`) e.g., ``` $ terraform import aws_quicksight_dashboard.example 123456789012,example-id From fe939eef7204ede432a0647e6d51cc6f2c9e6dd1 Mon Sep 17 00:00:00 2001 From: Fabien COMTE Date: Fri, 19 May 2023 16:13:19 +0200 Subject: [PATCH 03/10] fix typo --- website/docs/r/quicksight_dashboard.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/quicksight_dashboard.html.markdown b/website/docs/r/quicksight_dashboard.html.markdown index 102a8baac975..ebe1826e478d 100644 --- a/website/docs/r/quicksight_dashboard.html.markdown +++ b/website/docs/r/quicksight_dashboard.html.markdown @@ -133,7 +133,7 @@ The following arguments are optional: * `export_to_csv_option` - (Optional) Export to .csv option. See [export_to_csv_option](#export_to_csv_option). * `export_with_hidden_fields_option` - (Optional) Determines if hidden fields are exported with a dashboard. See [export_with_hidden_fields_option](#export_with_hidden_fields_option). * `sheet_controls_option` - (Optional) Sheet controls option. See [sheet_controls_option](#sheet_controls_option). -* `sheet_layout_element_maximization_option` - (Optional) The sheet layout maximization options of a dashbaord. See [sheet_layout_element_maximization_option](#sheet_layout_element_maximization_option). +* `sheet_layout_element_maximization_option` - (Optional) The sheet layout maximization options of a dashboard. See [sheet_layout_element_maximization_option](#sheet_layout_element_maximization_option). * `visual_axis_sort_option` - (Optional) The axis sort options of a dashboard. See [visual_axis_sort_option](#visual_axis_sort_option). * `visual_menu_option` - (Optional) The menu options of a visual in a dashboard. See [visual_menu_option](#visual_menu_option). From d9ead351988f7f033e5de81208bf4329a41e2238 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 19 May 2023 14:18:53 -0400 Subject: [PATCH 04/10] r/aws_quicksight_dashboard: tidy error messages --- internal/service/quicksight/dashboard.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/service/quicksight/dashboard.go b/internal/service/quicksight/dashboard.go index 5b68c39aaaba..f38e23365b60 100644 --- a/internal/service/quicksight/dashboard.go +++ b/internal/service/quicksight/dashboard.go @@ -231,15 +231,15 @@ func resourceDashboardRead(ctx context.Context, d *schema.ResourceData, meta int }) if err != nil { - return diag.Errorf("error describing QuickSight Dashboard (%s) Definition: %s", d.Id(), err) + return diag.Errorf("describing QuickSight Dashboard (%s) Definition: %s", d.Id(), err) } if err := d.Set("definition", quicksightschema.FlattenDashboardDefinition(descResp.Definition)); err != nil { - return diag.Errorf("error setting definition: %s", err) + return diag.Errorf("setting definition: %s", err) } if err := d.Set("dashboard_publish_options", quicksightschema.FlattenDashboardPublishOptions(descResp.DashboardPublishOptions)); err != nil { - return diag.Errorf("error setting dashboard_publish_options: %s", err) + return diag.Errorf("setting dashboard_publish_options: %s", err) } @@ -249,11 +249,11 @@ func resourceDashboardRead(ctx context.Context, d *schema.ResourceData, meta int }) if err != nil { - return diag.Errorf("error describing QuickSight Dashboard (%s) Permissions: %s", d.Id(), err) + return diag.Errorf("describing QuickSight Dashboard (%s) Permissions: %s", d.Id(), err) } if err := d.Set("permissions", flattenPermissions(permsResp.Permissions)); err != nil { - return diag.Errorf("error setting permissions: %s", err) + return diag.Errorf("setting permissions: %s", err) } return nil @@ -334,7 +334,7 @@ func resourceDashboardUpdate(ctx context.Context, d *schema.ResourceData, meta i _, err = conn.UpdateDashboardPermissionsWithContext(ctx, params) if err != nil { - return diag.Errorf("error updating QuickSight Dashboard (%s) permissions: %s", dashboardId, err) + return diag.Errorf("updating QuickSight Dashboard (%s) permissions: %s", dashboardId, err) } } From 46450f5a2ca56fc9281c51fe252f86ae5ee403a2 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 19 May 2023 14:21:55 -0400 Subject: [PATCH 05/10] r/aws_quicksight_dashboard: linter findings --- internal/service/quicksight/dashboard.go | 1 - internal/service/quicksight/dashboard_test.go | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/internal/service/quicksight/dashboard.go b/internal/service/quicksight/dashboard.go index f38e23365b60..7414868df33f 100644 --- a/internal/service/quicksight/dashboard.go +++ b/internal/service/quicksight/dashboard.go @@ -240,7 +240,6 @@ func resourceDashboardRead(ctx context.Context, d *schema.ResourceData, meta int if err := d.Set("dashboard_publish_options", quicksightschema.FlattenDashboardPublishOptions(descResp.DashboardPublishOptions)); err != nil { return diag.Errorf("setting dashboard_publish_options: %s", err) - } permsResp, err := conn.DescribeDashboardPermissionsWithContext(ctx, &quicksight.DescribeDashboardPermissionsInput{ diff --git a/internal/service/quicksight/dashboard_test.go b/internal/service/quicksight/dashboard_test.go index f0f8455c58aa..fbb639d44dde 100644 --- a/internal/service/quicksight/dashboard_test.go +++ b/internal/service/quicksight/dashboard_test.go @@ -6,7 +6,6 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/quicksight" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -245,16 +244,6 @@ func testAccCheckDashboardExists(ctx context.Context, name string, dashboard *qu } } -func testAccCheckDashboardNotRecreated(before, after *quicksight.Dashboard) resource.TestCheckFunc { - return func(s *terraform.State) error { - if creationTimeBefore, creationTimeAfter := aws.TimeValue(before.CreatedTime), aws.TimeValue(after.CreatedTime); creationTimeBefore != creationTimeAfter { - return create.Error(names.QuickSight, create.ErrActionCheckingNotRecreated, tfquicksight.ResNameDashboard, aws.StringValue(before.DashboardId), errors.New("recreated")) - } - - return nil - } -} - func testAccDashboardConfigBase(rId string, rName string) string { return acctest.ConfigCompose( testAccDataSetConfigBase(rId, rName), From 35a02f3ed29f56458757f826bea325a45854dc09 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 19 May 2023 14:37:21 -0400 Subject: [PATCH 06/10] r/aws_quicksight_dashboard: tidy test check helpers --- internal/service/quicksight/dashboard_test.go | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/internal/service/quicksight/dashboard_test.go b/internal/service/quicksight/dashboard_test.go index fbb639d44dde..7885d9e789cc 100644 --- a/internal/service/quicksight/dashboard_test.go +++ b/internal/service/quicksight/dashboard_test.go @@ -80,32 +80,6 @@ func TestAccQuickSightDashboard_disappears(t *testing.T) { }) } -func testAccCheckDashboardDestroy(ctx context.Context) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).QuickSightConn() - - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_quicksight_dashboard" { - continue - } - - output, err := tfquicksight.FindDashboardByID(ctx, conn, rs.Primary.ID) - if err != nil { - if tfawserr.ErrCodeEquals(err, quicksight.ErrCodeResourceNotFoundException) { - return nil - } - return err - } - - if output != nil { - return fmt.Errorf("QuickSight Dashboard (%s) still exists", rs.Primary.ID) - } - } - - return nil - } -} - func TestAccQuickSightDashboard_sourceEntity(t *testing.T) { ctx := acctest.Context(t) @@ -220,6 +194,32 @@ func TestAccQuickSightDashboard_dashboardSpecificConfig(t *testing.T) { }) } +func testAccCheckDashboardDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).QuickSightConn() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_quicksight_dashboard" { + continue + } + + output, err := tfquicksight.FindDashboardByID(ctx, conn, rs.Primary.ID) + if err != nil { + if tfawserr.ErrCodeEquals(err, quicksight.ErrCodeResourceNotFoundException) { + return nil + } + return err + } + + if output != nil { + return fmt.Errorf("QuickSight Dashboard (%s) still exists", rs.Primary.ID) + } + } + + return nil + } +} + func testAccCheckDashboardExists(ctx context.Context, name string, dashboard *quicksight.Dashboard) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[name] From 153c779f2282d3dcb2208ca8da07ccbec6c836e3 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 19 May 2023 15:04:42 -0400 Subject: [PATCH 07/10] r/aws_quicksight_template: fix template update --- internal/service/quicksight/template.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/internal/service/quicksight/template.go b/internal/service/quicksight/template.go index cc3d7281252e..83d033dfcb4d 100644 --- a/internal/service/quicksight/template.go +++ b/internal/service/quicksight/template.go @@ -246,12 +246,13 @@ func resourceTemplateUpdate(ctx context.Context, d *schema.ResourceData, meta in Name: aws.String(d.Get("name").(string)), VersionDescription: aws.String(d.Get("version_description").(string)), } - //_, createdFromEntity := d.GetOk("source_entity") - //if createdFromEntity { - in.SourceEntity = quicksightschema.ExpandTemplateSourceEntity(d.Get("source_entity").([]interface{})) - //} else { - in.Definition = quicksightschema.ExpandTemplateDefinition(d.Get("definition").([]interface{})) - //} + + // One of source_entity or definition is required for update + if _, ok := d.GetOk("source_entity"); ok { + in.SourceEntity = quicksightschema.ExpandTemplateSourceEntity(d.Get("source_entity").([]interface{})) + } else { + in.Definition = quicksightschema.ExpandTemplateDefinition(d.Get("definition").([]interface{})) + } log.Printf("[DEBUG] Updating QuickSight Template (%s): %#v", d.Id(), in) _, err := conn.UpdateTemplateWithContext(ctx, in) From d1969e748a5449a4cb3a8bd156d59225a8c90d86 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Fri, 19 May 2023 15:09:55 -0400 Subject: [PATCH 08/10] r/aws_quicksight_dashboard: switch to terraform-plugin-testing package --- internal/service/quicksight/dashboard_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/quicksight/dashboard_test.go b/internal/service/quicksight/dashboard_test.go index 7885d9e789cc..f4b229e350c3 100644 --- a/internal/service/quicksight/dashboard_test.go +++ b/internal/service/quicksight/dashboard_test.go @@ -9,8 +9,8 @@ import ( "github.com/aws/aws-sdk-go/service/quicksight" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" From 4661ec53e40d9ddc0d9be15a463a1366810a1af2 Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 22 May 2023 16:18:12 -0400 Subject: [PATCH 09/10] r/aws_quicksight_dashboard: s/parameters_declarations/parameter_declarations --- internal/service/quicksight/dashboard_test.go | 2 +- internal/service/quicksight/schema/dashboard.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/quicksight/dashboard_test.go b/internal/service/quicksight/dashboard_test.go index f4b229e350c3..d6d5d110a5ce 100644 --- a/internal/service/quicksight/dashboard_test.go +++ b/internal/service/quicksight/dashboard_test.go @@ -502,7 +502,7 @@ resource "aws_quicksight_dashboard" "test" { data_set_arn = aws_quicksight_data_set.test.arn identifier = "1" } - parameters_declarations { + parameter_declarations { string_parameter_declaration { name = "test" parameter_value_type = "SINGLE_VALUED" diff --git a/internal/service/quicksight/schema/dashboard.go b/internal/service/quicksight/schema/dashboard.go index 752c530f0180..97a6e0a5270f 100644 --- a/internal/service/quicksight/schema/dashboard.go +++ b/internal/service/quicksight/schema/dashboard.go @@ -63,7 +63,7 @@ func DashboardDefinitionSchema() *schema.Schema { }, }, }, - "parameters_declarations": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ParameterDeclaration.html + "parameter_declarations": { // https://docs.aws.amazon.com/quicksight/latest/APIReference/API_ParameterDeclaration.html Type: schema.TypeList, MinItems: 1, MaxItems: 200, @@ -367,7 +367,7 @@ func ExpandDashboardDefinition(tfList []interface{}) *quicksight.DashboardVersio if v, ok := tfMap["filter_groups"].([]interface{}); ok && len(v) > 0 { definition.FilterGroups = expandFilterGroups(v) } - if v, ok := tfMap["parameters_declarations"].([]interface{}); ok && len(v) > 0 { + if v, ok := tfMap["parameter_declarations"].([]interface{}); ok && len(v) > 0 { definition.ParameterDeclarations = expandParameterDeclarations(v) } if v, ok := tfMap["sheets"].([]interface{}); ok && len(v) > 0 { @@ -575,7 +575,7 @@ func FlattenDashboardDefinition(apiObject *quicksight.DashboardVersionDefinition tfMap["filter_groups"] = flattenFilterGroups(apiObject.FilterGroups) } if apiObject.ParameterDeclarations != nil { - tfMap["parameters_declarations"] = flattenParameterDeclarations(apiObject.ParameterDeclarations) + tfMap["parameter_declarations"] = flattenParameterDeclarations(apiObject.ParameterDeclarations) } if apiObject.Sheets != nil { tfMap["sheets"] = flattenSheetDefinitions(apiObject.Sheets) From 68f57523254df14dccc26c0b1c8fc4c4c2f738fd Mon Sep 17 00:00:00 2001 From: Jared Baker Date: Mon, 22 May 2023 16:26:54 -0400 Subject: [PATCH 10/10] r/aws_quicksight_dashboard: add service package name --- internal/service/quicksight/dashboard.go | 2 +- internal/service/quicksight/service_package_gen.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/service/quicksight/dashboard.go b/internal/service/quicksight/dashboard.go index 7414868df33f..112b59b9d031 100644 --- a/internal/service/quicksight/dashboard.go +++ b/internal/service/quicksight/dashboard.go @@ -25,7 +25,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_quicksight_dashboard") +// @SDKResource("aws_quicksight_dashboard", name="Dashboard") // @Tags(identifierAttribute="arn") func ResourceDashboard() *schema.Resource { return &schema.Resource{ diff --git a/internal/service/quicksight/service_package_gen.go b/internal/service/quicksight/service_package_gen.go index 37a3da54b442..c72f9b593b57 100644 --- a/internal/service/quicksight/service_package_gen.go +++ b/internal/service/quicksight/service_package_gen.go @@ -84,6 +84,7 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka { Factory: ResourceDashboard, TypeName: "aws_quicksight_dashboard", + Name: "Dashboard", Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: "arn", },