Skip to content

Commit 83f0874

Browse files
fix(flexible-board, resource): Allow panel positions to be autogenerated via the API
1 parent e089157 commit 83f0874

File tree

13 files changed

+654
-123
lines changed

13 files changed

+654
-123
lines changed

docs/resources/board.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Resource: honeycombio_board
22

3-
Creates a classic board. Classic boards are deprecated, use [honeycombio_flexible_board](./flexible_board.md) resource instead. For more information about boards, check out [Create Custom Boards](https://docs.honeycomb.io/observe/boards).
3+
Creates a legacy board. Legacy boards are deprecated, use [honeycombio_flexible_board](./flexible_board.md) resource instead. For more information about boards, check out [Create Custom Boards](https://docs.honeycomb.io/observe/boards).
44

55
## Example Usage
66

7-
### Simple Classic Board
7+
### Simple Legacy Board
88

99
```hcl
1010
data "honeycombio_query_specification" "query" {
@@ -35,7 +35,7 @@ resource "honeycombio_board" "board" {
3535
}
3636
```
3737

38-
### Classic Board with a Service Level Objective (SLO) and an annotated query
38+
### Legacy Board with a Service Level Objective (SLO) and an annotated query
3939

4040
```hcl
4141
data "honeycombio_query_specification" "latency_by_userid" {
@@ -116,7 +116,6 @@ Each board configuration may have zero or more `query` blocks, which accept the
116116
- `graph_settings` - (Optional) A map of boolean toggles to manages the settings for this query's graph on the board.
117117
If a value is unspecified, it is assumed to be false.
118118
Currently supported toggles are:
119-
120119
- `hide_markers`
121120
- `log_scale`
122121
- `omit_missing_values`

docs/resources/flexible_board.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,10 @@ Each board configuration may have zero or more `panel` blocks which accept the f
139139

140140
Each `position` configuration accepts the following arguments:
141141

142-
- `x_coordinate` - (Optional) The x-axis origin point for placing the panel within the layout.
143-
- `y_coordinate` - (Optional) The y-axis origin point for placing the panel within the layout.
144-
- `width` - (Optional) The width of the panel in honeycomb UI columns. Defaults to 6 for queries and 3 for slos. Maximum value is 12.
145-
- `height` - (Optional) The height of the panel in rows. Defaults to 4.
142+
- `x_coordinate` - (Optional) The x-axis origin point for placing the panel within the layout. Must be provided with `y_coordinate`.
143+
- `y_coordinate` - (Optional) The y-axis origin point for placing the panel within the layout. Must be provided with `x_coordinate`.
144+
- `width` - (Optional) The width of the panel in honeycomb UI columns. Automatically calculated when not provided. Maximum value is 12.
145+
- `height` - (Optional) The height of the panel in rows. Automatically calculated when not provided.
146146

147147
Each `slo_panel` configuration accepts the following arguments:
148148

example/flexible_board/main.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,11 @@ resource "honeycombio_flexible_board" "overview" {
111111
slo_panel {
112112
slo_id = honeycombio_slo.slo.id
113113
}
114+
position {
115+
x_coordinate = 6
116+
y_coordinate = 0
117+
width = 6
118+
height = 6
119+
}
114120
}
115121
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package validation
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag"
7+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
8+
"github.com/hashicorp/terraform-plugin-framework/types"
9+
)
10+
11+
var _ validator.List = panelPositionsConsistencyValidator{}
12+
13+
// panelPositionsConsistencyValidator validates that either all panels have positions or none of them do.
14+
type panelPositionsConsistencyValidator struct{}
15+
16+
func (v panelPositionsConsistencyValidator) Description(_ context.Context) string {
17+
return "either all panels must have positions or none of them should have positions"
18+
}
19+
20+
func (v panelPositionsConsistencyValidator) MarkdownDescription(ctx context.Context) string {
21+
return v.Description(ctx)
22+
}
23+
24+
func (v panelPositionsConsistencyValidator) ValidateList(ctx context.Context, request validator.ListRequest, response *validator.ListResponse) {
25+
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
26+
return
27+
}
28+
29+
elements := request.ConfigValue.Elements()
30+
if len(elements) == 0 {
31+
return
32+
}
33+
34+
var hasPositionCount int
35+
var noPositionCount int
36+
37+
for _, element := range elements {
38+
if element.IsNull() || element.IsUnknown() {
39+
continue
40+
}
41+
42+
panelObj, ok := element.(types.Object)
43+
if !ok {
44+
continue
45+
}
46+
47+
attrs := panelObj.Attributes()
48+
position, exists := attrs["position"]
49+
if !exists {
50+
continue
51+
}
52+
53+
// Check if position is set (not null and not unknown)
54+
if position.IsNull() || position.IsUnknown() {
55+
noPositionCount++
56+
} else {
57+
// Check if position object has any actual values set
58+
positionObj, ok := position.(types.Object)
59+
if !ok {
60+
noPositionCount++
61+
continue
62+
}
63+
64+
positionAttrs := positionObj.Attributes()
65+
hasAnyCoordinate := false
66+
67+
// Check if any coordinate is set
68+
for _, coordName := range []string{"x_coordinate", "y_coordinate"} {
69+
if coord, exists := positionAttrs[coordName]; exists {
70+
if !coord.IsNull() && !coord.IsUnknown() {
71+
hasAnyCoordinate = true
72+
break
73+
}
74+
}
75+
}
76+
77+
if hasAnyCoordinate {
78+
hasPositionCount++
79+
} else {
80+
noPositionCount++
81+
}
82+
}
83+
}
84+
85+
// If we have both panels with positions and panels without positions, that's invalid
86+
if hasPositionCount > 0 && noPositionCount > 0 {
87+
response.Diagnostics.Append(
88+
validatordiag.InvalidAttributeValueDiagnostic(
89+
request.Path,
90+
v.Description(ctx),
91+
"Found panels with positions and panels without positions. All panels must have consistent position configuration.",
92+
),
93+
)
94+
}
95+
}
96+
97+
// RequireConsistentPanelPositions returns a ListValidator which ensures that either all panels
98+
// have positions or none of them do.
99+
//
100+
// Null (unconfigured) and unknown (known after apply) values are skipped.
101+
func RequireConsistentPanelPositions() validator.List {
102+
return panelPositionsConsistencyValidator{}
103+
}

0 commit comments

Comments
 (0)