@@ -19,6 +19,15 @@ import (
1919 "github.com/axiomhq/axiom-go/axiom"
2020)
2121
22+ var dashboardServerManagedFields = map [string ]struct {}{
23+ "id" : {},
24+ "version" : {},
25+ "createdAt" : {},
26+ "updatedAt" : {},
27+ "createdBy" : {},
28+ "updatedBy" : {},
29+ }
30+
2231var (
2332 _ resource.Resource = & DashboardResource {}
2433 _ resource.ResourceWithImportState = & DashboardResource {}
@@ -75,7 +84,7 @@ func (r *DashboardResource) Schema(_ context.Context, _ resource.SchemaRequest,
7584 Attributes : map [string ]schema.Attribute {
7685 "id" : schema.StringAttribute {
7786 Computed : true ,
78- MarkdownDescription : "Dashboard identifier (same value as `uid`) ." ,
87+ MarkdownDescription : "Internal dashboard identifier returned by the API ." ,
7988 PlanModifiers : []planmodifier.String {
8089 stringplanmodifier .UseStateForUnknown (),
8190 },
@@ -179,7 +188,7 @@ func (r *DashboardResource) Create(ctx context.Context, req resource.CreateReque
179188 return
180189 }
181190
182- state , err := flattenDashboardResource (created .Dashboard , plan .Overwrite )
191+ state , err := flattenDashboardResource (created .Dashboard , plan .Overwrite , plan . Dashboard )
183192 if err != nil {
184193 resp .Diagnostics .AddError ("Failed to create dashboard" , err .Error ())
185194 return
@@ -222,7 +231,7 @@ func (r *DashboardResource) Read(ctx context.Context, req resource.ReadRequest,
222231 return
223232 }
224233
225- flattened , err := flattenDashboardResource (* dashboard , state .Overwrite )
234+ flattened , err := flattenDashboardResource (* dashboard , state .Overwrite , state . Dashboard )
226235 if err != nil {
227236 resp .Diagnostics .AddError ("Failed to read dashboard" , err .Error ())
228237 return
@@ -271,7 +280,7 @@ func (r *DashboardResource) Update(ctx context.Context, req resource.UpdateReque
271280 return
272281 }
273282
274- flattened , err := flattenDashboardResource (updated .Dashboard , plan .Overwrite )
283+ flattened , err := flattenDashboardResource (updated .Dashboard , plan .Overwrite , plan . Dashboard )
275284 if err != nil {
276285 resp .Diagnostics .AddError ("Failed to update dashboard" , err .Error ())
277286 return
@@ -310,7 +319,7 @@ func (r *DashboardResource) ImportState(ctx context.Context, req resource.Import
310319func dashboardUpsertPayloadFromModel (plan DashboardResourceModel , fallbackUID string , currentVersion int64 , isCreate bool ) (dashboardUpsertRequest , string , diag.Diagnostics ) {
311320 var diags diag.Diagnostics
312321
313- normalizedDashboard , err := normalizeDashboardString (plan .Dashboard .ValueString ())
322+ normalizedDashboard , dashboardMap , err := normalizeDashboardString (plan .Dashboard .ValueString ())
314323 if err != nil {
315324 diags .AddError ("Invalid dashboard JSON" , fmt .Sprintf ("`dashboard` must be valid JSON: %s" , err ))
316325 return dashboardUpsertRequest {}, "" , diags
@@ -321,6 +330,15 @@ func dashboardUpsertPayloadFromModel(plan DashboardResourceModel, fallbackUID st
321330 uid = plan .UID .ValueString ()
322331 }
323332
333+ dashboardUID , hasDashboardUID := stringValueFromMap (dashboardMap , "uid" )
334+ if hasDashboardUID {
335+ if uid != "" && uid != dashboardUID {
336+ diags .AddError ("UID mismatch" , "`uid` must match `dashboard.uid` when both are set." )
337+ return dashboardUpsertRequest {}, "" , diags
338+ }
339+ uid = dashboardUID
340+ }
341+
324342 payload := dashboardUpsertRequest {
325343 Dashboard : normalizedDashboard ,
326344 UID : uid ,
@@ -356,8 +374,8 @@ func dashboardUIDFromState(state DashboardResourceModel) string {
356374 return ""
357375}
358376
359- func flattenDashboardResource (in dashboardResourcePayload , overwrite types.Bool ) (DashboardResourceModel , error ) {
360- normalizedDashboard , err := normalizeDashboardRaw (in .Dashboard )
377+ func flattenDashboardResource (in dashboardResourcePayload , overwrite types.Bool , configuredDashboard types. String ) (DashboardResourceModel , error ) {
378+ normalizedDashboard , err := normalizeDashboardRaw (in .Dashboard , configuredDashboard )
361379 if err != nil {
362380 return DashboardResourceModel {}, fmt .Errorf ("unable to normalize dashboard document: %w" , err )
363381 }
@@ -396,21 +414,21 @@ func decodeDashboardResource(raw []byte) (*dashboardResourcePayload, error) {
396414 return out , nil
397415}
398416
399- func normalizeDashboardString (raw string ) (json.RawMessage , error ) {
417+ func normalizeDashboardString (raw string ) (json.RawMessage , map [ string ] any , error ) {
400418 parsed := make (map [string ]any )
401419 if err := json .Unmarshal ([]byte (raw ), & parsed ); err != nil {
402- return nil , err
420+ return nil , nil , err
403421 }
404422
405423 normalized , err := json .Marshal (parsed )
406424 if err != nil {
407- return nil , err
425+ return nil , nil , err
408426 }
409427
410- return normalized , nil
428+ return normalized , parsed , nil
411429}
412430
413- func normalizeDashboardRaw (raw json.RawMessage ) (string , error ) {
431+ func normalizeDashboardRaw (raw json.RawMessage , configured types. String ) (string , error ) {
414432 if len (raw ) == 0 {
415433 return "" , errors .New ("dashboard payload is empty" )
416434 }
@@ -420,6 +438,14 @@ func normalizeDashboardRaw(raw json.RawMessage) (string, error) {
420438 return "" , err
421439 }
422440
441+ for field := range dashboardServerManagedFields {
442+ delete (parsed , field )
443+ }
444+
445+ if ! dashboardConfigHasUID (configured ) {
446+ delete (parsed , "uid" )
447+ }
448+
423449 normalized , err := json .Marshal (parsed )
424450 if err != nil {
425451 return "" , err
@@ -428,6 +454,34 @@ func normalizeDashboardRaw(raw json.RawMessage) (string, error) {
428454 return string (normalized ), nil
429455}
430456
457+ func dashboardConfigHasUID (configured types.String ) bool {
458+ if configured .IsNull () || configured .IsUnknown () || configured .ValueString () == "" {
459+ return false
460+ }
461+
462+ parsed := make (map [string ]any )
463+ if err := json .Unmarshal ([]byte (configured .ValueString ()), & parsed ); err != nil {
464+ return false
465+ }
466+
467+ _ , ok := stringValueFromMap (parsed , "uid" )
468+ return ok
469+ }
470+
471+ func stringValueFromMap (in map [string ]any , key string ) (string , bool ) {
472+ v , ok := in [key ]
473+ if ! ok {
474+ return "" , false
475+ }
476+
477+ s , ok := v .(string )
478+ if ! ok || s == "" {
479+ return "" , false
480+ }
481+
482+ return s , true
483+ }
484+
431485func addDashboardUpdateError (resp * resource.UpdateResponse , err error , uid string , localVersion int64 ) {
432486 addDashboardWriteErrorDiagnostics (& resp .Diagnostics , err , uid , localVersion )
433487}
0 commit comments