Skip to content

Commit a248274

Browse files
authored
feat: add group_order attribute to status page component resource (#11)
The API exposes two ordering fields on components: - order: display order of the component's group on the status page - groupOrder: display order of the component within its group Only 'order' was exposed. This adds 'group_order' to the schema, create/update requests, and read responses.
1 parent 933f0a7 commit a248274

2 files changed

Lines changed: 225 additions & 7 deletions

File tree

internal/statuspage/component_resource.go

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type componentModel struct {
3939
Description types.String `tfsdk:"description"`
4040
Order types.Int64 `tfsdk:"order"`
4141
GroupID types.String `tfsdk:"group_id"`
42+
GroupOrder types.Int64 `tfsdk:"group_order"`
4243
CreatedAt types.String `tfsdk:"created_at"`
4344
UpdatedAt types.String `tfsdk:"updated_at"`
4445
}
@@ -84,12 +85,18 @@ func (r *componentResource) Schema(_ context.Context, _ resource.SchemaRequest,
8485
Validators: []validator.String{stringvalidator.LengthAtMost(1024)},
8586
},
8687
"order": schema.Int64Attribute{
87-
Optional: true,
88-
Computed: true,
88+
Optional: true,
89+
Computed: true,
90+
MarkdownDescription: "Display order of the component's group on the status page.",
8991
},
9092
"group_id": schema.StringAttribute{
9193
Optional: true,
9294
},
95+
"group_order": schema.Int64Attribute{
96+
Optional: true,
97+
Computed: true,
98+
MarkdownDescription: "Display order of the component within its group.",
99+
},
93100
"created_at": schema.StringAttribute{Computed: true},
94101
"updated_at": schema.StringAttribute{Computed: true},
95102
},
@@ -101,16 +108,18 @@ type apiAddMonitorComponentRequest struct {
101108
MonitorID string `json:"monitorId"`
102109
Name string `json:"name,omitempty"`
103110
Description string `json:"description,omitempty"`
104-
Order int64 `json:"order,omitempty"`
111+
Order *int64 `json:"order,omitempty"`
105112
GroupID string `json:"groupId,omitempty"`
113+
GroupOrder *int64 `json:"groupOrder,omitempty"`
106114
}
107115

108116
type apiAddStaticComponentRequest struct {
109117
PageID string `json:"pageId"`
110118
Name string `json:"name"`
111119
Description string `json:"description,omitempty"`
112-
Order int64 `json:"order,omitempty"`
120+
Order *int64 `json:"order,omitempty"`
113121
GroupID string `json:"groupId,omitempty"`
122+
GroupOrder *int64 `json:"groupOrder,omitempty"`
114123
}
115124

116125
type apiComponentResponse struct {
@@ -126,6 +135,7 @@ type apiComponent struct {
126135
MonitorID string `json:"monitorId"`
127136
Order int64 `json:"order"`
128137
GroupID string `json:"groupId"`
138+
GroupOrder int64 `json:"groupOrder"`
129139
CreatedAt string `json:"createdAt"`
130140
UpdatedAt string `json:"updatedAt"`
131141
}
@@ -136,6 +146,7 @@ type apiUpdateComponentRequest struct {
136146
Description *string `json:"description,omitempty"`
137147
Order *int64 `json:"order,omitempty"`
138148
GroupID *string `json:"groupId,omitempty"`
149+
GroupOrder *int64 `json:"groupOrder,omitempty"`
139150
}
140151

141152
type apiStatusPageContentResponse struct {
@@ -160,18 +171,32 @@ func (r *componentResource) Create(ctx context.Context, req resource.CreateReque
160171
MonitorID: data.MonitorID.ValueString(),
161172
Name: data.Name.ValueString(),
162173
Description: data.Description.ValueString(),
163-
Order: data.Order.ValueInt64(),
164174
GroupID: data.GroupID.ValueString(),
165175
}
176+
if !data.Order.IsNull() && !data.Order.IsUnknown() {
177+
v := data.Order.ValueInt64()
178+
apiReq.Order = &v
179+
}
180+
if !data.GroupOrder.IsNull() && !data.GroupOrder.IsUnknown() {
181+
v := data.GroupOrder.ValueInt64()
182+
apiReq.GroupOrder = &v
183+
}
166184
err = r.client.Do(ctx, "/openstatus.status_page.v1.StatusPageService/AddMonitorComponent", apiReq, &apiResp)
167185
} else {
168186
apiReq := apiAddStaticComponentRequest{
169187
PageID: data.PageID.ValueString(),
170188
Name: data.Name.ValueString(),
171189
Description: data.Description.ValueString(),
172-
Order: data.Order.ValueInt64(),
173190
GroupID: data.GroupID.ValueString(),
174191
}
192+
if !data.Order.IsNull() && !data.Order.IsUnknown() {
193+
v := data.Order.ValueInt64()
194+
apiReq.Order = &v
195+
}
196+
if !data.GroupOrder.IsNull() && !data.GroupOrder.IsUnknown() {
197+
v := data.GroupOrder.ValueInt64()
198+
apiReq.GroupOrder = &v
199+
}
175200
err = r.client.Do(ctx, "/openstatus.status_page.v1.StatusPageService/AddStaticComponent", apiReq, &apiResp)
176201
}
177202

@@ -235,10 +260,14 @@ func (r *componentResource) Update(ctx context.Context, req resource.UpdateReque
235260
v := data.Order.ValueInt64()
236261
updateReq.Order = &v
237262
}
238-
if !data.GroupID.IsNull() {
263+
if !data.GroupID.IsNull() && !data.GroupID.IsUnknown() {
239264
v := data.GroupID.ValueString()
240265
updateReq.GroupID = &v
241266
}
267+
if !data.GroupOrder.IsNull() && !data.GroupOrder.IsUnknown() {
268+
v := data.GroupOrder.ValueInt64()
269+
updateReq.GroupOrder = &v
270+
}
242271

243272
var apiResp apiComponentResponse
244273
err := r.client.Do(ctx, "/openstatus.status_page.v1.StatusPageService/UpdateComponent", updateReq, &apiResp)
@@ -300,6 +329,7 @@ func componentAPIToModel(api apiComponent, data *componentModel) {
300329
data.Description = types.StringValue(api.Description)
301330
}
302331
data.Order = types.Int64Value(api.Order)
332+
data.GroupOrder = types.Int64Value(api.GroupOrder)
303333
if api.GroupID != "" {
304334
data.GroupID = types.StringValue(api.GroupID)
305335
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
package statuspage
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
)
7+
8+
func ptr[T any](v T) *T { return &v }
9+
10+
func TestAPIAddMonitorComponentRequest_IncludesGroupOrder(t *testing.T) {
11+
req := apiAddMonitorComponentRequest{
12+
PageID: "1",
13+
MonitorID: "42",
14+
Name: "Hub UI",
15+
Order: ptr(int64(0)),
16+
GroupID: "10",
17+
GroupOrder: ptr(int64(3)),
18+
}
19+
20+
data, err := json.Marshal(req)
21+
if err != nil {
22+
t.Fatalf("unexpected marshal error: %v", err)
23+
}
24+
25+
var raw map[string]interface{}
26+
if err := json.Unmarshal(data, &raw); err != nil {
27+
t.Fatalf("unexpected unmarshal error: %v", err)
28+
}
29+
30+
val, ok := raw["groupOrder"]
31+
if !ok {
32+
t.Fatal("groupOrder field missing from JSON")
33+
}
34+
if val != float64(3) {
35+
t.Errorf("groupOrder = %v, want 3", val)
36+
}
37+
}
38+
39+
func TestAPIAddMonitorComponentRequest_OmitsNilGroupOrder(t *testing.T) {
40+
req := apiAddMonitorComponentRequest{
41+
PageID: "1",
42+
MonitorID: "42",
43+
Name: "Hub UI",
44+
}
45+
46+
data, err := json.Marshal(req)
47+
if err != nil {
48+
t.Fatalf("unexpected marshal error: %v", err)
49+
}
50+
51+
var raw map[string]interface{}
52+
if err := json.Unmarshal(data, &raw); err != nil {
53+
t.Fatalf("unexpected unmarshal error: %v", err)
54+
}
55+
56+
if _, ok := raw["groupOrder"]; ok {
57+
t.Error("groupOrder should be omitted when nil")
58+
}
59+
if _, ok := raw["order"]; ok {
60+
t.Error("order should be omitted when nil")
61+
}
62+
}
63+
64+
func TestAPIAddStaticComponentRequest_IncludesGroupOrder(t *testing.T) {
65+
req := apiAddStaticComponentRequest{
66+
PageID: "1",
67+
Name: "Static",
68+
Order: ptr(int64(1)),
69+
GroupID: "10",
70+
GroupOrder: ptr(int64(2)),
71+
}
72+
73+
data, err := json.Marshal(req)
74+
if err != nil {
75+
t.Fatalf("unexpected marshal error: %v", err)
76+
}
77+
78+
var raw map[string]interface{}
79+
if err := json.Unmarshal(data, &raw); err != nil {
80+
t.Fatalf("unexpected unmarshal error: %v", err)
81+
}
82+
83+
val, ok := raw["groupOrder"]
84+
if !ok {
85+
t.Fatal("groupOrder field missing from JSON")
86+
}
87+
if val != float64(2) {
88+
t.Errorf("groupOrder = %v, want 2", val)
89+
}
90+
}
91+
92+
func TestAPIComponent_GroupOrderParsed(t *testing.T) {
93+
apiJSON := `{
94+
"id": "1",
95+
"pageId": "2",
96+
"name": "Hub UI",
97+
"description": "",
98+
"type": "PAGE_COMPONENT_TYPE_MONITOR",
99+
"monitorId": "42",
100+
"order": 0,
101+
"groupId": "10",
102+
"groupOrder": 3,
103+
"createdAt": "2026-03-23T00:00:00Z",
104+
"updatedAt": "2026-03-23T00:00:00Z"
105+
}`
106+
107+
var comp apiComponent
108+
if err := json.Unmarshal([]byte(apiJSON), &comp); err != nil {
109+
t.Fatalf("unexpected unmarshal error: %v", err)
110+
}
111+
112+
if comp.GroupOrder != 3 {
113+
t.Errorf("GroupOrder = %d, want 3", comp.GroupOrder)
114+
}
115+
if comp.Order != 0 {
116+
t.Errorf("Order = %d, want 0", comp.Order)
117+
}
118+
}
119+
120+
func TestAPIUpdateComponentRequest_IncludesGroupOrder(t *testing.T) {
121+
req := apiUpdateComponentRequest{
122+
ID: "1",
123+
GroupOrder: ptr(int64(5)),
124+
}
125+
126+
data, err := json.Marshal(req)
127+
if err != nil {
128+
t.Fatalf("unexpected marshal error: %v", err)
129+
}
130+
131+
var raw map[string]interface{}
132+
if err := json.Unmarshal(data, &raw); err != nil {
133+
t.Fatalf("unexpected unmarshal error: %v", err)
134+
}
135+
136+
val, ok := raw["groupOrder"]
137+
if !ok {
138+
t.Fatal("groupOrder field missing from JSON")
139+
}
140+
if val != float64(5) {
141+
t.Errorf("groupOrder = %v, want 5", val)
142+
}
143+
}
144+
145+
func TestAPIUpdateComponentRequest_OmitsNilGroupOrder(t *testing.T) {
146+
req := apiUpdateComponentRequest{
147+
ID: "1",
148+
}
149+
150+
data, err := json.Marshal(req)
151+
if err != nil {
152+
t.Fatalf("unexpected marshal error: %v", err)
153+
}
154+
155+
var raw map[string]interface{}
156+
if err := json.Unmarshal(data, &raw); err != nil {
157+
t.Fatalf("unexpected unmarshal error: %v", err)
158+
}
159+
160+
if _, ok := raw["groupOrder"]; ok {
161+
t.Error("groupOrder should be omitted when nil")
162+
}
163+
}
164+
165+
func TestComponentAPIToModel_SetsGroupOrder(t *testing.T) {
166+
api := apiComponent{
167+
ID: "1",
168+
PageID: "2",
169+
Name: "Hub UI",
170+
Type: "PAGE_COMPONENT_TYPE_MONITOR",
171+
MonitorID: "42",
172+
Order: 0,
173+
GroupID: "10",
174+
GroupOrder: 3,
175+
CreatedAt: "2026-03-23T00:00:00Z",
176+
UpdatedAt: "2026-03-23T00:00:00Z",
177+
}
178+
179+
var data componentModel
180+
componentAPIToModel(api, &data)
181+
182+
if data.GroupOrder.ValueInt64() != 3 {
183+
t.Errorf("GroupOrder = %d, want 3", data.GroupOrder.ValueInt64())
184+
}
185+
if data.Order.ValueInt64() != 0 {
186+
t.Errorf("Order = %d, want 0", data.Order.ValueInt64())
187+
}
188+
}

0 commit comments

Comments
 (0)