Dashboard Controls: Fix schema transformation for link placement (#114630)
* fix: add missing transformation for scenes -> save model v2 * fix: link placement transformation on the backend between schemas * fix: update the openapi spec in the tests * tes: add tests for `transformSceneToSaveModelSchemaV2` * tests: extend conversion_test.go to cover link placements
This commit is contained in:
@@ -109,8 +109,14 @@ DashboardLink: {
|
||||
includeVars: bool | *false
|
||||
// If true, includes current time range in the link as query params
|
||||
keepTime: bool | *false
|
||||
// Placement can be used to display the link somewhere else on the dashboard other than above the visualisations.
|
||||
placement?: DashboardLinkPlacement
|
||||
}
|
||||
|
||||
// Dashboard Link placement. Defines where the link should be displayed.
|
||||
// - "inControlsMenu" renders the link in bottom part of the dashboard controls dropdown menu
|
||||
DashboardLinkPlacement: "inControlsMenu"
|
||||
|
||||
DataSourceRef: {
|
||||
// The plugin type-id
|
||||
type?: string
|
||||
|
||||
@@ -113,8 +113,14 @@ DashboardLink: {
|
||||
includeVars: bool | *false
|
||||
// If true, includes current time range in the link as query params
|
||||
keepTime: bool | *false
|
||||
// Placement can be used to display the link somewhere else on the dashboard other than above the visualisations.
|
||||
placement?: DashboardLinkPlacement
|
||||
}
|
||||
|
||||
// Dashboard Link placement. Defines where the link should be displayed.
|
||||
// - "inControlsMenu" renders the link in bottom part of the dashboard controls dropdown menu
|
||||
DashboardLinkPlacement: "inControlsMenu"
|
||||
|
||||
DataSourceRef: {
|
||||
// The plugin type-id
|
||||
type?: string
|
||||
|
||||
@@ -1216,6 +1216,8 @@ type DashboardDashboardLink struct {
|
||||
IncludeVars bool `json:"includeVars"`
|
||||
// If true, includes current time range in the link as query params
|
||||
KeepTime bool `json:"keepTime"`
|
||||
// Placement can be used to display the link somewhere else on the dashboard other than above the visualisations.
|
||||
Placement *string `json:"placement,omitempty"`
|
||||
}
|
||||
|
||||
// NewDashboardDashboardLink creates a new DashboardDashboardLink object.
|
||||
@@ -1226,6 +1228,7 @@ func NewDashboardDashboardLink() *DashboardDashboardLink {
|
||||
TargetBlank: false,
|
||||
IncludeVars: false,
|
||||
KeepTime: false,
|
||||
Placement: (func(input string) *string { return &input })(DashboardDashboardLinkPlacement),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1238,6 +1241,11 @@ const (
|
||||
DashboardDashboardLinkTypeDashboards DashboardDashboardLinkType = "dashboards"
|
||||
)
|
||||
|
||||
// Dashboard Link placement. Defines where the link should be displayed.
|
||||
// - "inControlsMenu" renders the link in bottom part of the dashboard controls dropdown menu
|
||||
// +k8s:openapi-gen=true
|
||||
const DashboardDashboardLinkPlacement = "inControlsMenu"
|
||||
|
||||
// Time configuration
|
||||
// It defines the default time config for the time picker, the refresh picker for the specific dashboard.
|
||||
// +k8s:openapi-gen=true
|
||||
|
||||
@@ -1600,6 +1600,13 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardDashboardLink(ref common.Refere
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"placement": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Placement can be used to display the link somewhere else on the dashboard other than above the visualisations.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"title", "type", "icon", "tooltip", "tags", "asDropdown", "targetBlank", "includeVars", "keepTime"},
|
||||
},
|
||||
|
||||
+1
@@ -70,6 +70,7 @@
|
||||
"title": "Documentation",
|
||||
"tooltip": "View documentation",
|
||||
"type": "link",
|
||||
"placement": "inControlsMenu",
|
||||
"url": "https://docs.example.com/dashboard-guide"
|
||||
},
|
||||
{
|
||||
|
||||
Vendored
+1
@@ -69,6 +69,7 @@
|
||||
"title": "Documentation",
|
||||
"tooltip": "View documentation",
|
||||
"type": "link",
|
||||
"placement": "inControlsMenu",
|
||||
"url": "https://docs.example.com/dashboard-guide"
|
||||
},
|
||||
{
|
||||
|
||||
Vendored
+2
-1
@@ -132,7 +132,8 @@
|
||||
"asDropdown": false,
|
||||
"targetBlank": true,
|
||||
"includeVars": false,
|
||||
"keepTime": false
|
||||
"keepTime": false,
|
||||
"placement": "inControlsMenu"
|
||||
},
|
||||
{
|
||||
"title": "Tag-based Link",
|
||||
|
||||
Vendored
+2
-1
@@ -137,7 +137,8 @@
|
||||
"asDropdown": false,
|
||||
"targetBlank": true,
|
||||
"includeVars": false,
|
||||
"keepTime": false
|
||||
"keepTime": false,
|
||||
"placement": "inControlsMenu"
|
||||
},
|
||||
{
|
||||
"title": "Tag-based Link",
|
||||
|
||||
@@ -376,6 +376,13 @@ func transformLinks(dashboard map[string]interface{}) []dashv2alpha1.DashboardDa
|
||||
}
|
||||
}
|
||||
|
||||
// Optional placement field - only set if present
|
||||
if placement, exists := linkMap["placement"]; exists {
|
||||
if placementStr, ok := placement.(string); ok {
|
||||
dashLink.Placement = &placementStr
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, dashLink)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,6 +548,7 @@ func convertDashboardLink_V2alpha1_to_V2beta1(in *dashv2alpha1.DashboardDashboar
|
||||
out.TargetBlank = in.TargetBlank
|
||||
out.IncludeVars = in.IncludeVars
|
||||
out.KeepTime = in.KeepTime
|
||||
out.Placement = in.Placement
|
||||
}
|
||||
|
||||
func convertDataLink_V2alpha1_to_V2beta1(in *dashv2alpha1.DashboardDataLink, out *dashv2beta1.DashboardDataLink) {
|
||||
|
||||
@@ -565,6 +565,7 @@ func convertDashboardLink_V2beta1_to_V2alpha1(in *dashv2beta1.DashboardDashboard
|
||||
out.TargetBlank = in.TargetBlank
|
||||
out.IncludeVars = in.IncludeVars
|
||||
out.KeepTime = in.KeepTime
|
||||
out.Placement = in.Placement
|
||||
}
|
||||
|
||||
func convertDataLink_V2beta1_to_V2alpha1(in *dashv2beta1.DashboardDataLink, out *dashv2alpha1.DashboardDataLink) {
|
||||
|
||||
@@ -971,6 +971,8 @@ export interface DashboardLink {
|
||||
includeVars: boolean;
|
||||
// If true, includes current time range in the link as query params
|
||||
keepTime: boolean;
|
||||
// Placement can be used to display the link somewhere else on the dashboard other than above the visualisations.
|
||||
placement?: "inControlsMenu";
|
||||
}
|
||||
|
||||
export const defaultDashboardLink = (): DashboardLink => ({
|
||||
@@ -983,6 +985,7 @@ export const defaultDashboardLink = (): DashboardLink => ({
|
||||
targetBlank: false,
|
||||
includeVars: false,
|
||||
keepTime: false,
|
||||
placement: DashboardLinkPlacement,
|
||||
});
|
||||
|
||||
// Dashboard Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)
|
||||
@@ -990,6 +993,10 @@ export type DashboardLinkType = "link" | "dashboards";
|
||||
|
||||
export const defaultDashboardLinkType = (): DashboardLinkType => ("link");
|
||||
|
||||
// Dashboard Link placement. Defines where the link should be displayed.
|
||||
// - "inControlsMenu" renders the link in bottom part of the dashboard controls dropdown menu
|
||||
export const DashboardLinkPlacement = "inControlsMenu";
|
||||
|
||||
// Time configuration
|
||||
// It defines the default time config for the time picker, the refresh picker for the specific dashboard.
|
||||
export interface TimeSettingsSpec {
|
||||
|
||||
@@ -1877,6 +1877,10 @@
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"placement": {
|
||||
"description": "Placement can be used to display the link somewhere else on the dashboard other than above the visualisations.",
|
||||
"type": "string"
|
||||
},
|
||||
"tags": {
|
||||
"description": "List of tags to limit the linked dashboards. If empty, all dashboards will be displayed. Only valid if the type is dashboards",
|
||||
"type": "array",
|
||||
|
||||
+39
@@ -411,6 +411,45 @@ describe('transformSceneToSaveModelSchemaV2', () => {
|
||||
expect(result.annotations).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should transform links with placement property', () => {
|
||||
const sceneWithPlacementLink = new DashboardScene({
|
||||
links: [
|
||||
{
|
||||
title: 'Link in Controls Menu',
|
||||
url: 'http://test.com',
|
||||
type: 'link',
|
||||
placement: 'inControlsMenu',
|
||||
asDropdown: false,
|
||||
icon: '',
|
||||
includeVars: false,
|
||||
keepTime: false,
|
||||
tags: [],
|
||||
targetBlank: false,
|
||||
tooltip: '',
|
||||
},
|
||||
{
|
||||
title: 'Link without placement',
|
||||
url: 'http://test2.com',
|
||||
type: 'link',
|
||||
asDropdown: false,
|
||||
icon: '',
|
||||
includeVars: false,
|
||||
keepTime: false,
|
||||
tags: [],
|
||||
targetBlank: false,
|
||||
tooltip: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const result = transformSceneToSaveModelSchemaV2(sceneWithPlacementLink);
|
||||
|
||||
expect(result.links).toBeDefined();
|
||||
expect(result.links).toHaveLength(2);
|
||||
expect(result.links![0]).toHaveProperty('placement', 'inControlsMenu');
|
||||
expect(result.links![1]).not.toHaveProperty('placement');
|
||||
});
|
||||
|
||||
it('should transform the minimum scene to save model schema v2', () => {
|
||||
const minimalScene = new DashboardScene({});
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ export function transformSceneToSaveModelSchemaV2(scene: DashboardScene, isSnaps
|
||||
keepTime: link.keepTime ?? defaultDashboardLink().keepTime,
|
||||
includeVars: link.includeVars ?? defaultDashboardLink().includeVars,
|
||||
targetBlank: link.targetBlank ?? defaultDashboardLink().targetBlank,
|
||||
...(link.placement !== undefined && { placement: link.placement }),
|
||||
})),
|
||||
tags: sceneDash.tags ?? defaultDashboardV2Spec().tags,
|
||||
// EOF dashboard settings
|
||||
|
||||
@@ -142,6 +142,19 @@ describe('ResponseTransformers', () => {
|
||||
type: 'link',
|
||||
tooltip: 'Link 1 Tooltip',
|
||||
},
|
||||
{
|
||||
title: 'Link 2',
|
||||
url: 'https://grafana.com',
|
||||
asDropdown: false,
|
||||
targetBlank: true,
|
||||
includeVars: true,
|
||||
keepTime: true,
|
||||
tags: ['tag3', 'tag4'],
|
||||
icon: 'external link',
|
||||
type: 'link',
|
||||
tooltip: 'Link 2 Tooltip',
|
||||
placement: 'inControlsMenu',
|
||||
},
|
||||
],
|
||||
annotations: {
|
||||
list: [],
|
||||
@@ -886,6 +899,19 @@ describe('ResponseTransformers', () => {
|
||||
type: 'link',
|
||||
tooltip: 'Link 1 Tooltip',
|
||||
},
|
||||
{
|
||||
title: 'Link 2',
|
||||
url: 'https://grafana.com',
|
||||
asDropdown: false,
|
||||
targetBlank: true,
|
||||
includeVars: true,
|
||||
keepTime: true,
|
||||
tags: ['tag3', 'tag4'],
|
||||
icon: 'external link',
|
||||
type: 'link',
|
||||
tooltip: 'Link 2 Tooltip',
|
||||
placement: 'inControlsMenu',
|
||||
},
|
||||
],
|
||||
annotations: handyTestingSchema.annotations,
|
||||
variables: handyTestingSchema.variables,
|
||||
|
||||
@@ -216,6 +216,7 @@ export function ensureV2Response(
|
||||
keepTime: link.keepTime ?? defaultDashboardLink().keepTime,
|
||||
includeVars: link.includeVars ?? defaultDashboardLink().includeVars,
|
||||
targetBlank: link.targetBlank ?? defaultDashboardLink().targetBlank,
|
||||
...(link.placement !== undefined && { placement: link.placement }),
|
||||
})),
|
||||
annotations,
|
||||
variables,
|
||||
|
||||
Reference in New Issue
Block a user