mirror of https://github.com/grafana/grafana
DashbboardScene: RowRepeaterBehavior (#74505)
* Repeating rows start * working * Progress * Progress * Update * up scenes lib * Update * Progress * restore url sync * Progress * Fixes and tests * Update * Adds tests and code to remove repeats from save model * Update * Fix testpull/74650/head^2
parent
fb367bf91d
commit
97d568e60a
@ -1,334 +0,0 @@ |
|||||||
{ |
|
||||||
"annotations": { |
|
||||||
"list": [ |
|
||||||
{ |
|
||||||
"builtIn": 1, |
|
||||||
"datasource": "-- Grafana --", |
|
||||||
"enable": true, |
|
||||||
"hide": true, |
|
||||||
"iconColor": "rgba(0, 211, 255, 1)", |
|
||||||
"name": "Annotations & Alerts", |
|
||||||
"target": { |
|
||||||
"limit": 100, |
|
||||||
"matchAny": false, |
|
||||||
"tags": [], |
|
||||||
"type": "dashboard" |
|
||||||
}, |
|
||||||
"type": "dashboard" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"editable": true, |
|
||||||
"fiscalYearStartMonth": 0, |
|
||||||
"graphTooltip": 0, |
|
||||||
"iteration": 1640181176989, |
|
||||||
"links": [], |
|
||||||
"liveNow": false, |
|
||||||
"panels": [ |
|
||||||
{ |
|
||||||
"collapsed": false, |
|
||||||
"gridPos": { |
|
||||||
"h": 1, |
|
||||||
"w": 24, |
|
||||||
"x": 0, |
|
||||||
"y": 0 |
|
||||||
}, |
|
||||||
"id": 2, |
|
||||||
"panels": [], |
|
||||||
"repeat": "row", |
|
||||||
"title": "Row title $row", |
|
||||||
"type": "row" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"datasource": { |
|
||||||
"type": "testdata" |
|
||||||
}, |
|
||||||
"description": "", |
|
||||||
"fieldConfig": { |
|
||||||
"defaults": { |
|
||||||
"color": { |
|
||||||
"mode": "palette-classic" |
|
||||||
}, |
|
||||||
"custom": { |
|
||||||
"axisLabel": "", |
|
||||||
"axisPlacement": "auto", |
|
||||||
"barAlignment": 0, |
|
||||||
"drawStyle": "line", |
|
||||||
"fillOpacity": 0, |
|
||||||
"gradientMode": "none", |
|
||||||
"hideFrom": { |
|
||||||
"legend": false, |
|
||||||
"tooltip": false, |
|
||||||
"viz": false |
|
||||||
}, |
|
||||||
"lineInterpolation": "linear", |
|
||||||
"lineWidth": 1, |
|
||||||
"pointSize": 5, |
|
||||||
"scaleDistribution": { |
|
||||||
"type": "linear" |
|
||||||
}, |
|
||||||
"showPoints": "auto", |
|
||||||
"spanNulls": false, |
|
||||||
"stacking": { |
|
||||||
"group": "A", |
|
||||||
"mode": "none" |
|
||||||
}, |
|
||||||
"thresholdsStyle": { |
|
||||||
"mode": "off" |
|
||||||
} |
|
||||||
}, |
|
||||||
"mappings": [], |
|
||||||
"thresholds": { |
|
||||||
"mode": "absolute", |
|
||||||
"steps": [ |
|
||||||
{ |
|
||||||
"color": "green" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"color": "red", |
|
||||||
"value": 80 |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
}, |
|
||||||
"overrides": [] |
|
||||||
}, |
|
||||||
"gridPos": { |
|
||||||
"h": 8, |
|
||||||
"w": 8, |
|
||||||
"x": 0, |
|
||||||
"y": 1 |
|
||||||
}, |
|
||||||
"id": 4, |
|
||||||
"options": { |
|
||||||
"legend": { |
|
||||||
"calcs": [], |
|
||||||
"displayMode": "list", |
|
||||||
"placement": "bottom" |
|
||||||
}, |
|
||||||
"tooltip": { |
|
||||||
"mode": "single", |
|
||||||
"sort": "none" |
|
||||||
} |
|
||||||
}, |
|
||||||
"title": "Panel Title", |
|
||||||
"type": "timeseries" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"datasource": { |
|
||||||
"type": "testdata" |
|
||||||
}, |
|
||||||
"description": "", |
|
||||||
"fieldConfig": { |
|
||||||
"defaults": { |
|
||||||
"color": { |
|
||||||
"mode": "palette-classic" |
|
||||||
}, |
|
||||||
"custom": { |
|
||||||
"axisLabel": "", |
|
||||||
"axisPlacement": "auto", |
|
||||||
"barAlignment": 0, |
|
||||||
"drawStyle": "line", |
|
||||||
"fillOpacity": 0, |
|
||||||
"gradientMode": "none", |
|
||||||
"hideFrom": { |
|
||||||
"legend": false, |
|
||||||
"tooltip": false, |
|
||||||
"viz": false |
|
||||||
}, |
|
||||||
"lineInterpolation": "linear", |
|
||||||
"lineWidth": 1, |
|
||||||
"pointSize": 5, |
|
||||||
"scaleDistribution": { |
|
||||||
"type": "linear" |
|
||||||
}, |
|
||||||
"showPoints": "auto", |
|
||||||
"spanNulls": false, |
|
||||||
"stacking": { |
|
||||||
"group": "A", |
|
||||||
"mode": "none" |
|
||||||
}, |
|
||||||
"thresholdsStyle": { |
|
||||||
"mode": "off" |
|
||||||
} |
|
||||||
}, |
|
||||||
"mappings": [], |
|
||||||
"thresholds": { |
|
||||||
"mode": "absolute", |
|
||||||
"steps": [ |
|
||||||
{ |
|
||||||
"color": "green" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"color": "red", |
|
||||||
"value": 80 |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
}, |
|
||||||
"overrides": [] |
|
||||||
}, |
|
||||||
"gridPos": { |
|
||||||
"h": 8, |
|
||||||
"w": 8, |
|
||||||
"x": 8, |
|
||||||
"y": 1 |
|
||||||
}, |
|
||||||
"id": 9, |
|
||||||
"options": { |
|
||||||
"legend": { |
|
||||||
"calcs": [], |
|
||||||
"displayMode": "list", |
|
||||||
"placement": "bottom" |
|
||||||
}, |
|
||||||
"tooltip": { |
|
||||||
"mode": "single", |
|
||||||
"sort": "none" |
|
||||||
} |
|
||||||
}, |
|
||||||
"repeat": "vertical", |
|
||||||
"repeatDirection": "v", |
|
||||||
"title": "Vertical repeating $vertical", |
|
||||||
"type": "timeseries" |
|
||||||
} |
|
||||||
], |
|
||||||
"schemaVersion": 34, |
|
||||||
"tags": [], |
|
||||||
"templating": { |
|
||||||
"list": [ |
|
||||||
{ |
|
||||||
"current": { |
|
||||||
"selected": true, |
|
||||||
"text": [ |
|
||||||
"All" |
|
||||||
], |
|
||||||
"value": [ |
|
||||||
"$__all" |
|
||||||
] |
|
||||||
}, |
|
||||||
"hide": 0, |
|
||||||
"includeAll": true, |
|
||||||
"multi": true, |
|
||||||
"name": "vertical", |
|
||||||
"options": [ |
|
||||||
{ |
|
||||||
"selected": true, |
|
||||||
"text": "All", |
|
||||||
"value": "$__all" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "1", |
|
||||||
"value": "1" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "2", |
|
||||||
"value": "2" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "3", |
|
||||||
"value": "3" |
|
||||||
} |
|
||||||
], |
|
||||||
"query": "1,2,3", |
|
||||||
"queryValue": "", |
|
||||||
"skipUrlSync": false, |
|
||||||
"type": "custom" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"current": { |
|
||||||
"selected": true, |
|
||||||
"text": [ |
|
||||||
"All" |
|
||||||
], |
|
||||||
"value": [ |
|
||||||
"$__all" |
|
||||||
] |
|
||||||
}, |
|
||||||
"hide": 0, |
|
||||||
"includeAll": true, |
|
||||||
"multi": true, |
|
||||||
"name": "horizontal", |
|
||||||
"options": [ |
|
||||||
{ |
|
||||||
"selected": true, |
|
||||||
"text": "All", |
|
||||||
"value": "$__all" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "1", |
|
||||||
"value": "1" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "2", |
|
||||||
"value": "2" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "3", |
|
||||||
"value": "3" |
|
||||||
} |
|
||||||
], |
|
||||||
"query": "1,2,3", |
|
||||||
"queryValue": "", |
|
||||||
"skipUrlSync": false, |
|
||||||
"type": "custom" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"current": { |
|
||||||
"selected": true, |
|
||||||
"text": [ |
|
||||||
"All" |
|
||||||
], |
|
||||||
"value": [ |
|
||||||
"$__all" |
|
||||||
] |
|
||||||
}, |
|
||||||
"hide": 0, |
|
||||||
"includeAll": true, |
|
||||||
"multi": true, |
|
||||||
"name": "row", |
|
||||||
"options": [ |
|
||||||
{ |
|
||||||
"selected": true, |
|
||||||
"text": "All", |
|
||||||
"value": "$__all" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "1", |
|
||||||
"value": "1" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "2", |
|
||||||
"value": "2" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "3", |
|
||||||
"value": "3" |
|
||||||
} |
|
||||||
], |
|
||||||
"query": "1,2,3", |
|
||||||
"queryValue": "", |
|
||||||
"skipUrlSync": false, |
|
||||||
"type": "custom" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"time": { |
|
||||||
"from": "now-6h", |
|
||||||
"to": "now" |
|
||||||
}, |
|
||||||
"timepicker": {}, |
|
||||||
"timezone": "utc", |
|
||||||
"title": "Repeating a row with a non-repeating panel and vertical repeating panel", |
|
||||||
"uid": "7lS-ojt7z", |
|
||||||
"version": 2, |
|
||||||
"weekStart": "" |
|
||||||
} |
|
@ -1,257 +0,0 @@ |
|||||||
{ |
|
||||||
"annotations": { |
|
||||||
"list": [ |
|
||||||
{ |
|
||||||
"builtIn": 1, |
|
||||||
"datasource": "-- Grafana --", |
|
||||||
"enable": true, |
|
||||||
"hide": true, |
|
||||||
"iconColor": "rgba(0, 211, 255, 1)", |
|
||||||
"name": "Annotations & Alerts", |
|
||||||
"target": { |
|
||||||
"limit": 100, |
|
||||||
"matchAny": false, |
|
||||||
"tags": [], |
|
||||||
"type": "dashboard" |
|
||||||
}, |
|
||||||
"type": "dashboard" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"editable": true, |
|
||||||
"fiscalYearStartMonth": 0, |
|
||||||
"graphTooltip": 0, |
|
||||||
"iteration": 1640181195825, |
|
||||||
"links": [], |
|
||||||
"liveNow": false, |
|
||||||
"panels": [ |
|
||||||
{ |
|
||||||
"collapsed": false, |
|
||||||
"gridPos": { |
|
||||||
"h": 1, |
|
||||||
"w": 24, |
|
||||||
"x": 0, |
|
||||||
"y": 0 |
|
||||||
}, |
|
||||||
"id": 2, |
|
||||||
"panels": [], |
|
||||||
"repeat": "row", |
|
||||||
"title": "Row title $row", |
|
||||||
"type": "row" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"datasource": { |
|
||||||
"type": "testdata" |
|
||||||
}, |
|
||||||
"description": "", |
|
||||||
"fieldConfig": { |
|
||||||
"defaults": { |
|
||||||
"color": { |
|
||||||
"mode": "palette-classic" |
|
||||||
}, |
|
||||||
"custom": { |
|
||||||
"axisLabel": "", |
|
||||||
"axisPlacement": "auto", |
|
||||||
"barAlignment": 0, |
|
||||||
"drawStyle": "line", |
|
||||||
"fillOpacity": 0, |
|
||||||
"gradientMode": "none", |
|
||||||
"hideFrom": { |
|
||||||
"legend": false, |
|
||||||
"tooltip": false, |
|
||||||
"viz": false |
|
||||||
}, |
|
||||||
"lineInterpolation": "linear", |
|
||||||
"lineWidth": 1, |
|
||||||
"pointSize": 5, |
|
||||||
"scaleDistribution": { |
|
||||||
"type": "linear" |
|
||||||
}, |
|
||||||
"showPoints": "auto", |
|
||||||
"spanNulls": false, |
|
||||||
"stacking": { |
|
||||||
"group": "A", |
|
||||||
"mode": "none" |
|
||||||
}, |
|
||||||
"thresholdsStyle": { |
|
||||||
"mode": "off" |
|
||||||
} |
|
||||||
}, |
|
||||||
"mappings": [], |
|
||||||
"thresholds": { |
|
||||||
"mode": "absolute", |
|
||||||
"steps": [ |
|
||||||
{ |
|
||||||
"color": "green" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"color": "red", |
|
||||||
"value": 80 |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
}, |
|
||||||
"overrides": [] |
|
||||||
}, |
|
||||||
"gridPos": { |
|
||||||
"h": 8, |
|
||||||
"w": 8, |
|
||||||
"x": 0, |
|
||||||
"y": 1 |
|
||||||
}, |
|
||||||
"id": 4, |
|
||||||
"options": { |
|
||||||
"legend": { |
|
||||||
"calcs": [], |
|
||||||
"displayMode": "list", |
|
||||||
"placement": "bottom" |
|
||||||
}, |
|
||||||
"tooltip": { |
|
||||||
"mode": "single", |
|
||||||
"sort": "none" |
|
||||||
} |
|
||||||
}, |
|
||||||
"title": "Panel Title", |
|
||||||
"type": "timeseries" |
|
||||||
} |
|
||||||
], |
|
||||||
"schemaVersion": 34, |
|
||||||
"tags": [], |
|
||||||
"templating": { |
|
||||||
"list": [ |
|
||||||
{ |
|
||||||
"current": { |
|
||||||
"selected": true, |
|
||||||
"text": [ |
|
||||||
"All" |
|
||||||
], |
|
||||||
"value": [ |
|
||||||
"$__all" |
|
||||||
] |
|
||||||
}, |
|
||||||
"hide": 0, |
|
||||||
"includeAll": true, |
|
||||||
"multi": true, |
|
||||||
"name": "vertical", |
|
||||||
"options": [ |
|
||||||
{ |
|
||||||
"selected": true, |
|
||||||
"text": "All", |
|
||||||
"value": "$__all" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "1", |
|
||||||
"value": "1" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "2", |
|
||||||
"value": "2" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "3", |
|
||||||
"value": "3" |
|
||||||
} |
|
||||||
], |
|
||||||
"query": "1,2,3", |
|
||||||
"queryValue": "", |
|
||||||
"skipUrlSync": false, |
|
||||||
"type": "custom" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"current": { |
|
||||||
"selected": true, |
|
||||||
"text": [ |
|
||||||
"All" |
|
||||||
], |
|
||||||
"value": [ |
|
||||||
"$__all" |
|
||||||
] |
|
||||||
}, |
|
||||||
"hide": 0, |
|
||||||
"includeAll": true, |
|
||||||
"multi": true, |
|
||||||
"name": "horizontal", |
|
||||||
"options": [ |
|
||||||
{ |
|
||||||
"selected": true, |
|
||||||
"text": "All", |
|
||||||
"value": "$__all" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "1", |
|
||||||
"value": "1" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "2", |
|
||||||
"value": "2" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "3", |
|
||||||
"value": "3" |
|
||||||
} |
|
||||||
], |
|
||||||
"query": "1,2,3", |
|
||||||
"queryValue": "", |
|
||||||
"skipUrlSync": false, |
|
||||||
"type": "custom" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"current": { |
|
||||||
"selected": true, |
|
||||||
"text": [ |
|
||||||
"All" |
|
||||||
], |
|
||||||
"value": [ |
|
||||||
"$__all" |
|
||||||
] |
|
||||||
}, |
|
||||||
"hide": 0, |
|
||||||
"includeAll": true, |
|
||||||
"multi": true, |
|
||||||
"name": "row", |
|
||||||
"options": [ |
|
||||||
{ |
|
||||||
"selected": true, |
|
||||||
"text": "All", |
|
||||||
"value": "$__all" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "1", |
|
||||||
"value": "1" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "2", |
|
||||||
"value": "2" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"selected": false, |
|
||||||
"text": "3", |
|
||||||
"value": "3" |
|
||||||
} |
|
||||||
], |
|
||||||
"query": "1,2,3", |
|
||||||
"queryValue": "", |
|
||||||
"skipUrlSync": false, |
|
||||||
"type": "custom" |
|
||||||
} |
|
||||||
] |
|
||||||
}, |
|
||||||
"time": { |
|
||||||
"from": "now-6h", |
|
||||||
"to": "now" |
|
||||||
}, |
|
||||||
"timepicker": {}, |
|
||||||
"timezone": "utc", |
|
||||||
"title": "Repeating a row with a non-repeating panel", |
|
||||||
"uid": "ZzyTojpnz", |
|
||||||
"version": 3, |
|
||||||
"weekStart": "" |
|
||||||
} |
|
@ -1,41 +0,0 @@ |
|||||||
import { e2e } from '../utils'; |
|
||||||
const PAGE_UNDER_TEST = 'k3PEoCpnk/repeating-a-row-with-a-non-repeating-panel-and-horizontal-repeating-panel'; |
|
||||||
const DASHBOARD_NAME = 'Repeating a row with a non-repeating panel and horizontal repeating panel'; |
|
||||||
|
|
||||||
describe('Repeating a row with repeated panels and a non-repeating panel', () => { |
|
||||||
beforeEach(() => { |
|
||||||
e2e.flows.login('admin', 'admin'); |
|
||||||
}); |
|
||||||
|
|
||||||
it('should be able to collapse and expand a repeated row without losing panels', () => { |
|
||||||
e2e.flows.openDashboard({ uid: PAGE_UNDER_TEST }); |
|
||||||
e2e().contains(DASHBOARD_NAME).should('be.visible'); |
|
||||||
|
|
||||||
const panelsToCheck = [ |
|
||||||
'Row 2 non-repeating panel', |
|
||||||
'Row 2 repeating panel 1', |
|
||||||
'Row 2 repeating panel 2', |
|
||||||
'Row 2 repeating panel 3', |
|
||||||
]; |
|
||||||
|
|
||||||
// Collapse Row 1 first so the Row 2 panels all fit on the screen
|
|
||||||
e2e.components.DashboardRow.title('Row 1').click(); |
|
||||||
|
|
||||||
// Rows are expanded by default, so check that all panels are visible
|
|
||||||
panelsToCheck.forEach((title) => { |
|
||||||
e2e.components.Panels.Panel.title(title).should('be.visible'); |
|
||||||
}); |
|
||||||
|
|
||||||
// Collapse the row and check panels are no longer visible
|
|
||||||
e2e.components.DashboardRow.title('Row 2').click(); |
|
||||||
panelsToCheck.forEach((title) => { |
|
||||||
e2e.components.Panels.Panel.title(title).should('not.exist'); |
|
||||||
}); |
|
||||||
|
|
||||||
// Expand the row and check all panels are visible again
|
|
||||||
e2e.components.DashboardRow.title('Row 2').click(); |
|
||||||
panelsToCheck.forEach((title) => { |
|
||||||
e2e.components.Panels.Panel.title(title).should('be.visible'); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
@ -0,0 +1,144 @@ |
|||||||
|
import { |
||||||
|
EmbeddedScene, |
||||||
|
SceneCanvasText, |
||||||
|
SceneGridItem, |
||||||
|
SceneGridLayout, |
||||||
|
SceneGridRow, |
||||||
|
SceneTimeRange, |
||||||
|
SceneVariableSet, |
||||||
|
TestVariable, |
||||||
|
} from '@grafana/scenes'; |
||||||
|
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE } from 'app/features/variables/constants'; |
||||||
|
|
||||||
|
import { activateFullSceneTree } from '../utils/test-utils'; |
||||||
|
|
||||||
|
import { RepeatDirection } from './PanelRepeaterGridItem'; |
||||||
|
import { RowRepeaterBehavior } from './RowRepeaterBehavior'; |
||||||
|
|
||||||
|
describe('RowRepeaterBehavior', () => { |
||||||
|
describe('Given scene with variable with 5 values', () => { |
||||||
|
let scene: EmbeddedScene, grid: SceneGridLayout; |
||||||
|
|
||||||
|
beforeEach(async () => { |
||||||
|
({ scene, grid } = buildScene({ variableQueryTime: 0 })); |
||||||
|
activateFullSceneTree(scene); |
||||||
|
await new Promise((r) => setTimeout(r, 1)); |
||||||
|
}); |
||||||
|
|
||||||
|
it('Should repeat row', () => { |
||||||
|
// Verify that panel above row remains
|
||||||
|
expect(grid.state.children[0]).toBeInstanceOf(SceneGridItem); |
||||||
|
// Verify that first row still has repeat behavior
|
||||||
|
const row1 = grid.state.children[1] as SceneGridRow; |
||||||
|
expect(row1.state.$behaviors?.[0]).toBeInstanceOf(RowRepeaterBehavior); |
||||||
|
expect(row1.state.$variables!.state.variables[0].getValue()).toBe('1'); |
||||||
|
|
||||||
|
const row2 = grid.state.children[2] as SceneGridRow; |
||||||
|
expect(row2.state.$variables!.state.variables[0].getValueText?.()).toBe('B'); |
||||||
|
|
||||||
|
// Should give repeated panels unique keys
|
||||||
|
const gridItem = row2.state.children[0] as SceneGridItem; |
||||||
|
expect(gridItem.state.body?.state.key).toBe('canvas-1-row-1'); |
||||||
|
}); |
||||||
|
|
||||||
|
it('Should push row at the bottom down', () => { |
||||||
|
// Should push row at the bottom down
|
||||||
|
const rowAtTheBottom = grid.state.children[6] as SceneGridRow; |
||||||
|
expect(rowAtTheBottom.state.title).toBe('Row at the bottom'); |
||||||
|
|
||||||
|
// Panel at the top is 10, each row is (1+5)*5 = 30, so the grid item below it should be 40
|
||||||
|
expect(rowAtTheBottom.state.y).toBe(40); |
||||||
|
}); |
||||||
|
|
||||||
|
it('Should handle second repeat cycle and update remove old repeats', async () => { |
||||||
|
// trigger another repeat cycle by changing the variable
|
||||||
|
const variable = scene.state.$variables!.state.variables[0] as TestVariable; |
||||||
|
variable.changeValueTo(['2', '3']); |
||||||
|
|
||||||
|
await new Promise((r) => setTimeout(r, 1)); |
||||||
|
|
||||||
|
// should now only have 2 repeated rows (and the panel above + the row at the bottom)
|
||||||
|
expect(grid.state.children.length).toBe(4); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
interface SceneOptions { |
||||||
|
variableQueryTime: number; |
||||||
|
maxPerRow?: number; |
||||||
|
itemHeight?: number; |
||||||
|
repeatDirection?: RepeatDirection; |
||||||
|
} |
||||||
|
|
||||||
|
function buildScene(options: SceneOptions) { |
||||||
|
const grid = new SceneGridLayout({ |
||||||
|
children: [ |
||||||
|
new SceneGridItem({ |
||||||
|
x: 0, |
||||||
|
y: 0, |
||||||
|
width: 24, |
||||||
|
height: 10, |
||||||
|
body: new SceneCanvasText({ |
||||||
|
text: 'Panel above row', |
||||||
|
}), |
||||||
|
}), |
||||||
|
new SceneGridRow({ |
||||||
|
x: 0, |
||||||
|
y: 10, |
||||||
|
width: 24, |
||||||
|
height: 1, |
||||||
|
$behaviors: [ |
||||||
|
new RowRepeaterBehavior({ |
||||||
|
variableName: 'server', |
||||||
|
sources: [ |
||||||
|
new SceneGridItem({ |
||||||
|
x: 0, |
||||||
|
y: 11, |
||||||
|
width: 24, |
||||||
|
height: 5, |
||||||
|
body: new SceneCanvasText({ |
||||||
|
key: 'canvas-1', |
||||||
|
text: 'Panel inside repeated row, server = $server', |
||||||
|
}), |
||||||
|
}), |
||||||
|
], |
||||||
|
}), |
||||||
|
], |
||||||
|
}), |
||||||
|
new SceneGridRow({ |
||||||
|
x: 0, |
||||||
|
y: 16, |
||||||
|
width: 24, |
||||||
|
height: 5, |
||||||
|
title: 'Row at the bottom', |
||||||
|
}), |
||||||
|
], |
||||||
|
}); |
||||||
|
|
||||||
|
const scene = new EmbeddedScene({ |
||||||
|
$timeRange: new SceneTimeRange({ from: 'now-6h', to: 'now' }), |
||||||
|
$variables: new SceneVariableSet({ |
||||||
|
variables: [ |
||||||
|
new TestVariable({ |
||||||
|
name: 'server', |
||||||
|
query: 'A.*', |
||||||
|
value: ALL_VARIABLE_VALUE, |
||||||
|
text: ALL_VARIABLE_TEXT, |
||||||
|
isMulti: true, |
||||||
|
includeAll: true, |
||||||
|
delayMs: options.variableQueryTime, |
||||||
|
optionsToReturn: [ |
||||||
|
{ label: 'A', value: '1' }, |
||||||
|
{ label: 'B', value: '2' }, |
||||||
|
{ label: 'C', value: '3' }, |
||||||
|
{ label: 'D', value: '4' }, |
||||||
|
{ label: 'E', value: '5' }, |
||||||
|
], |
||||||
|
}), |
||||||
|
], |
||||||
|
}), |
||||||
|
body: grid, |
||||||
|
}); |
||||||
|
|
||||||
|
return { scene, grid }; |
||||||
|
} |
@ -0,0 +1,215 @@ |
|||||||
|
import { |
||||||
|
LocalValueVariable, |
||||||
|
MultiValueVariable, |
||||||
|
sceneGraph, |
||||||
|
SceneGridItemLike, |
||||||
|
SceneGridLayout, |
||||||
|
SceneGridRow, |
||||||
|
SceneObjectBase, |
||||||
|
SceneObjectState, |
||||||
|
SceneVariable, |
||||||
|
SceneVariableSet, |
||||||
|
VariableDependencyConfig, |
||||||
|
VariableValueSingle, |
||||||
|
} from '@grafana/scenes'; |
||||||
|
|
||||||
|
import { getMultiVariableValues } from '../utils/utils'; |
||||||
|
|
||||||
|
interface RowRepeaterBehaviorState extends SceneObjectState { |
||||||
|
variableName: string; |
||||||
|
sources: SceneGridItemLike[]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This behavior will run an effect function when specified variables change |
||||||
|
*/ |
||||||
|
|
||||||
|
export class RowRepeaterBehavior extends SceneObjectBase<RowRepeaterBehaviorState> { |
||||||
|
protected _variableDependency = new VariableDependencyConfig(this, { |
||||||
|
variableNames: [this.state.variableName], |
||||||
|
onVariableUpdatesCompleted: this._onVariableChanged.bind(this), |
||||||
|
}); |
||||||
|
|
||||||
|
private _isWaitingForVariables = false; |
||||||
|
|
||||||
|
public constructor(state: RowRepeaterBehaviorState) { |
||||||
|
super(state); |
||||||
|
|
||||||
|
this.addActivationHandler(() => this._activationHandler()); |
||||||
|
} |
||||||
|
|
||||||
|
private _activationHandler() { |
||||||
|
// If we our variable is ready we can process repeats on activation
|
||||||
|
if (sceneGraph.hasVariableDependencyInLoadingState(this)) { |
||||||
|
this._isWaitingForVariables = true; |
||||||
|
} else { |
||||||
|
this._performRepeat(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private _onVariableChanged(changedVariables: Set<SceneVariable>, dependencyChanged: boolean): void { |
||||||
|
if (dependencyChanged) { |
||||||
|
this._performRepeat(); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// If we are waiting for variables and the variable is no longer loading then we are ready to repeat as well
|
||||||
|
if (this._isWaitingForVariables && !sceneGraph.hasVariableDependencyInLoadingState(this)) { |
||||||
|
this._isWaitingForVariables = false; |
||||||
|
this._performRepeat(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private _performRepeat() { |
||||||
|
const variable = sceneGraph.lookupVariable(this.state.variableName, this.parent?.parent!); |
||||||
|
|
||||||
|
if (!variable) { |
||||||
|
console.error('RepeatedRowBehavior: Variable not found'); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (!(variable instanceof MultiValueVariable)) { |
||||||
|
console.error('RepeatedRowBehavior: Variable is not a MultiValueVariable'); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (!(this.parent instanceof SceneGridRow)) { |
||||||
|
console.error('RepeatedRowBehavior: Parent is not a SceneGridRow'); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const layout = sceneGraph.getLayout(this); |
||||||
|
|
||||||
|
if (!(layout instanceof SceneGridLayout)) { |
||||||
|
console.error('RepeatedRowBehavior: Layout is not a SceneGridLayout'); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const rowToRepeat = this.parent as SceneGridRow; |
||||||
|
const { values, texts } = getMultiVariableValues(variable); |
||||||
|
const rows: SceneGridRow[] = []; |
||||||
|
const rowContentHeight = getRowContentHeight(this.state.sources); |
||||||
|
let maxYOfRows = 0; |
||||||
|
|
||||||
|
// Loop through variable values and create repeates
|
||||||
|
for (let index = 0; index < values.length; index++) { |
||||||
|
const children: SceneGridItemLike[] = []; |
||||||
|
|
||||||
|
// Loop through panels inside row
|
||||||
|
for (const source of this.state.sources) { |
||||||
|
const sourceItemY = source.state.y ?? 0; |
||||||
|
const itemY = sourceItemY + (rowContentHeight + 1) * index; |
||||||
|
|
||||||
|
const itemClone = source.clone({ |
||||||
|
key: `${source.state.key}-clone-${index}`, |
||||||
|
y: itemY, |
||||||
|
}); |
||||||
|
|
||||||
|
//Make sure all the child scene objects have unique keys
|
||||||
|
ensureUniqueKeys(itemClone, index); |
||||||
|
|
||||||
|
children.push(itemClone); |
||||||
|
|
||||||
|
if (maxYOfRows < itemY + itemClone.state.height!) { |
||||||
|
maxYOfRows = itemY + itemClone.state.height!; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const rowClone = this.getRowClone(rowToRepeat, index, values[index], texts[index], rowContentHeight, children); |
||||||
|
rows.push(rowClone); |
||||||
|
} |
||||||
|
|
||||||
|
updateLayout(layout, rows, maxYOfRows, rowToRepeat); |
||||||
|
} |
||||||
|
|
||||||
|
getRowClone( |
||||||
|
rowToRepeat: SceneGridRow, |
||||||
|
index: number, |
||||||
|
value: VariableValueSingle, |
||||||
|
text: VariableValueSingle, |
||||||
|
rowContentHeight: number, |
||||||
|
children: SceneGridItemLike[] |
||||||
|
): SceneGridRow { |
||||||
|
if (index === 0) { |
||||||
|
rowToRepeat.setState({ |
||||||
|
// not activated
|
||||||
|
$variables: new SceneVariableSet({ |
||||||
|
variables: [new LocalValueVariable({ name: this.state.variableName, value, text: String(text) })], |
||||||
|
}), |
||||||
|
children, |
||||||
|
}); |
||||||
|
return rowToRepeat; |
||||||
|
} |
||||||
|
|
||||||
|
const sourceRowY = rowToRepeat.state.y ?? 0; |
||||||
|
|
||||||
|
return rowToRepeat.clone({ |
||||||
|
key: `${rowToRepeat.state.key}-clone-${index}`, |
||||||
|
$variables: new SceneVariableSet({ |
||||||
|
variables: [new LocalValueVariable({ name: this.state.variableName, value, text: String(text) })], |
||||||
|
}), |
||||||
|
$behaviors: [], |
||||||
|
children, |
||||||
|
y: sourceRowY + rowContentHeight * index + index, |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function getRowContentHeight(panels: SceneGridItemLike[]): number { |
||||||
|
let maxY = 0; |
||||||
|
let minY = Number.MAX_VALUE; |
||||||
|
|
||||||
|
for (const panel of panels) { |
||||||
|
if (panel.state.y! + panel.state.height! > maxY) { |
||||||
|
maxY = panel.state.y! + panel.state.height!; |
||||||
|
} |
||||||
|
if (panel.state.y! < minY) { |
||||||
|
minY = panel.state.y!; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return maxY - minY; |
||||||
|
} |
||||||
|
|
||||||
|
function updateLayout(layout: SceneGridLayout, rows: SceneGridRow[], maxYOfRows: number, rowToRepeat: SceneGridRow) { |
||||||
|
const allChildren = getLayoutChildrenFilterOutRepeatClones(layout, rowToRepeat); |
||||||
|
const index = allChildren.indexOf(rowToRepeat); |
||||||
|
|
||||||
|
if (index === -1) { |
||||||
|
throw new Error('RowRepeaterBehavior: Parent row not found in layout children'); |
||||||
|
} |
||||||
|
|
||||||
|
const newChildren = [...allChildren.slice(0, index), ...rows, ...allChildren.slice(index + 1)]; |
||||||
|
|
||||||
|
// Is there grid items after rows?
|
||||||
|
if (allChildren.length > index + 1) { |
||||||
|
const childrenAfter = allChildren.slice(index + 1); |
||||||
|
const firstChildAfterY = childrenAfter[0].state.y!; |
||||||
|
const diff = maxYOfRows - firstChildAfterY; |
||||||
|
|
||||||
|
for (const child of childrenAfter) { |
||||||
|
if (child.state.y! < maxYOfRows) { |
||||||
|
child.setState({ y: child.state.y! + diff }); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
layout.setState({ children: newChildren }); |
||||||
|
} |
||||||
|
|
||||||
|
function getLayoutChildrenFilterOutRepeatClones(layout: SceneGridLayout, rowToRepeat: SceneGridRow) { |
||||||
|
return layout.state.children.filter((child) => { |
||||||
|
if (child.state.key?.startsWith(`${rowToRepeat.state.key}-clone-`)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function ensureUniqueKeys(item: SceneGridItemLike, rowIndex: number) { |
||||||
|
item.forEachChild((child) => { |
||||||
|
child.setState({ key: `${child.state.key}-row-${rowIndex}` }); |
||||||
|
ensureUniqueKeys(child, rowIndex); |
||||||
|
}); |
||||||
|
} |
@ -0,0 +1,353 @@ |
|||||||
|
{ |
||||||
|
"annotations": { |
||||||
|
"list": [ |
||||||
|
{ |
||||||
|
"builtIn": 1, |
||||||
|
"datasource": { |
||||||
|
"type": "grafana", |
||||||
|
"uid": "-- Grafana --" |
||||||
|
}, |
||||||
|
"enable": true, |
||||||
|
"hide": true, |
||||||
|
"iconColor": "rgba(0, 211, 255, 1)", |
||||||
|
"name": "Annotations & Alerts", |
||||||
|
"type": "dashboard" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"editable": true, |
||||||
|
"fiscalYearStartMonth": 0, |
||||||
|
"graphTooltip": 0, |
||||||
|
"links": [], |
||||||
|
"liveNow": false, |
||||||
|
"panels": [ |
||||||
|
{ |
||||||
|
"collapsed": false, |
||||||
|
"gridPos": { |
||||||
|
"h": 1, |
||||||
|
"w": 24, |
||||||
|
"x": 0, |
||||||
|
"y": 0 |
||||||
|
}, |
||||||
|
"id": 20, |
||||||
|
"panels": [], |
||||||
|
"title": "Row at the top - not repeated - saved expanded", |
||||||
|
"type": "row" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"gridPos": { |
||||||
|
"h": 2, |
||||||
|
"w": 24, |
||||||
|
"x": 0, |
||||||
|
"y": 1 |
||||||
|
}, |
||||||
|
"id": 15, |
||||||
|
"options": { |
||||||
|
"code": { |
||||||
|
"language": "plaintext", |
||||||
|
"showLineNumbers": false, |
||||||
|
"showMiniMap": false |
||||||
|
}, |
||||||
|
"content": "<div class=\"center-vh\">\n Repeated row below. The row has \n a panel that is also repeated horizontally based\n on values in the $pod variable. \n</div>", |
||||||
|
"mode": "markdown" |
||||||
|
}, |
||||||
|
"pluginVersion": "10.2.0-pre", |
||||||
|
"type": "text" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"gridPos": { |
||||||
|
"h": 1, |
||||||
|
"w": 24, |
||||||
|
"x": 0, |
||||||
|
"y": 3 |
||||||
|
}, |
||||||
|
"id": 16, |
||||||
|
"panels": [], |
||||||
|
"repeat": "server", |
||||||
|
"repeatDirection": "h", |
||||||
|
"title": "Row for server $server", |
||||||
|
"type": "row" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"type": "testdata", |
||||||
|
"uid": "PD8C576611E62080A" |
||||||
|
}, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"color": { |
||||||
|
"mode": "palette-classic" |
||||||
|
}, |
||||||
|
"custom": { |
||||||
|
"axisCenteredZero": false, |
||||||
|
"axisColorMode": "text", |
||||||
|
"axisLabel": "", |
||||||
|
"axisPlacement": "auto", |
||||||
|
"axisShow": false, |
||||||
|
"barAlignment": 0, |
||||||
|
"drawStyle": "line", |
||||||
|
"fillOpacity": 0, |
||||||
|
"gradientMode": "none", |
||||||
|
"hideFrom": { |
||||||
|
"legend": false, |
||||||
|
"tooltip": false, |
||||||
|
"viz": false |
||||||
|
}, |
||||||
|
"insertNulls": false, |
||||||
|
"lineInterpolation": "linear", |
||||||
|
"lineWidth": 1, |
||||||
|
"pointSize": 5, |
||||||
|
"scaleDistribution": { |
||||||
|
"type": "linear" |
||||||
|
}, |
||||||
|
"showPoints": "auto", |
||||||
|
"spanNulls": false, |
||||||
|
"stacking": { |
||||||
|
"group": "A", |
||||||
|
"mode": "none" |
||||||
|
}, |
||||||
|
"thresholdsStyle": { |
||||||
|
"mode": "off" |
||||||
|
} |
||||||
|
}, |
||||||
|
"mappings": [], |
||||||
|
"thresholds": { |
||||||
|
"mode": "absolute", |
||||||
|
"steps": [ |
||||||
|
{ |
||||||
|
"color": "green", |
||||||
|
"value": null |
||||||
|
}, |
||||||
|
{ |
||||||
|
"color": "red", |
||||||
|
"value": 80 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"overrides": [] |
||||||
|
}, |
||||||
|
"gridPos": { |
||||||
|
"h": 10, |
||||||
|
"w": 12, |
||||||
|
"x": 0, |
||||||
|
"y": 4 |
||||||
|
}, |
||||||
|
"id": 2, |
||||||
|
"maxPerRow": 3, |
||||||
|
"options": { |
||||||
|
"legend": { |
||||||
|
"calcs": [], |
||||||
|
"displayMode": "list", |
||||||
|
"placement": "bottom", |
||||||
|
"showLegend": true |
||||||
|
}, |
||||||
|
"tooltip": { |
||||||
|
"mode": "single", |
||||||
|
"sort": "none" |
||||||
|
} |
||||||
|
}, |
||||||
|
"repeat": "pod", |
||||||
|
"repeatDirection": "h", |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"alias": "server = $server, pod id = $pod ", |
||||||
|
"datasource": { |
||||||
|
"type": "testdata", |
||||||
|
"uid": "PD8C576611E62080A" |
||||||
|
}, |
||||||
|
"refId": "A", |
||||||
|
"scenarioId": "random_walk", |
||||||
|
"seriesCount": 1 |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "server = $server, pod = $pod", |
||||||
|
"type": "timeseries" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"collapsed": true, |
||||||
|
"gridPos": { |
||||||
|
"h": 1, |
||||||
|
"w": 24, |
||||||
|
"x": 0, |
||||||
|
"y": 25 |
||||||
|
}, |
||||||
|
"id": 25, |
||||||
|
"panels": [ |
||||||
|
{ |
||||||
|
"gridPos": { |
||||||
|
"h": 2, |
||||||
|
"w": 24, |
||||||
|
"x": 0, |
||||||
|
"y": 26 |
||||||
|
}, |
||||||
|
"id": 30, |
||||||
|
"options": { |
||||||
|
"code": { |
||||||
|
"language": "plaintext", |
||||||
|
"showLineNumbers": false, |
||||||
|
"showMiniMap": false |
||||||
|
}, |
||||||
|
"content": "<div class=\"center-vh\">\n Just a panel\n</div>", |
||||||
|
"mode": "markdown" |
||||||
|
}, |
||||||
|
"pluginVersion": "10.2.0-pre", |
||||||
|
"type": "text" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Row at the bottom - not repeated - saved collapsed ", |
||||||
|
"type": "row" |
||||||
|
} |
||||||
|
], |
||||||
|
"refresh": "", |
||||||
|
"schemaVersion": 38, |
||||||
|
"tags": ["templating", "gdev"], |
||||||
|
"templating": { |
||||||
|
"list": [ |
||||||
|
{ |
||||||
|
"current": { |
||||||
|
"selected": true, |
||||||
|
"text": ["A", "B"], |
||||||
|
"value": ["A", "B"] |
||||||
|
}, |
||||||
|
"hide": 0, |
||||||
|
"includeAll": true, |
||||||
|
"multi": true, |
||||||
|
"name": "server", |
||||||
|
"options": [ |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "All", |
||||||
|
"value": "$__all" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": true, |
||||||
|
"text": "A", |
||||||
|
"value": "A" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": true, |
||||||
|
"text": "B", |
||||||
|
"value": "B" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "C", |
||||||
|
"value": "C" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "D", |
||||||
|
"value": "D" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "E", |
||||||
|
"value": "E" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "F", |
||||||
|
"value": "F" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "E", |
||||||
|
"value": "E" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "G", |
||||||
|
"value": "G" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "H", |
||||||
|
"value": "H" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "I", |
||||||
|
"value": "I" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "J", |
||||||
|
"value": "J" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "K", |
||||||
|
"value": "K" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "L", |
||||||
|
"value": "L" |
||||||
|
} |
||||||
|
], |
||||||
|
"query": "A,B,C,D,E,F,E,G,H,I,J,K,L", |
||||||
|
"queryValue": "", |
||||||
|
"skipUrlSync": false, |
||||||
|
"type": "custom" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"current": { |
||||||
|
"selected": true, |
||||||
|
"text": ["Bob", "Rob"], |
||||||
|
"value": ["1", "2"] |
||||||
|
}, |
||||||
|
"hide": 0, |
||||||
|
"includeAll": true, |
||||||
|
"multi": true, |
||||||
|
"name": "pod", |
||||||
|
"options": [ |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "All", |
||||||
|
"value": "$__all" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": true, |
||||||
|
"text": "Bob", |
||||||
|
"value": "1" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": true, |
||||||
|
"text": "Rob", |
||||||
|
"value": "2" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "Sod", |
||||||
|
"value": "3" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "Hod", |
||||||
|
"value": "4" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"selected": false, |
||||||
|
"text": "Cod", |
||||||
|
"value": "5" |
||||||
|
} |
||||||
|
], |
||||||
|
"query": "Bob : 1, Rob : 2,Sod : 3, Hod : 4, Cod : 5", |
||||||
|
"queryValue": "", |
||||||
|
"skipUrlSync": false, |
||||||
|
"type": "custom" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"time": { |
||||||
|
"from": "now-6h", |
||||||
|
"to": "now" |
||||||
|
}, |
||||||
|
"timepicker": {}, |
||||||
|
"timezone": "", |
||||||
|
"title": "Repeating rows", |
||||||
|
"uid": "Repeating-rows-uid", |
||||||
|
"version": 1, |
||||||
|
"weekStart": "" |
||||||
|
} |
Loading…
Reference in new issue