mirror of https://github.com/grafana/grafana.git
				
				
				
			Refactor state timeline/status history to cue model and refactor `TimelineChart` component (#61631)
* Adapt state timeline to scuemata * Refactor status history to cue model * Refactor * Refactor TimelineChart as a core component * wip * Change as per CR Co-authored-by: sam boyer <sdboyer@grafana.com>
This commit is contained in:
		
							parent
							
								
									6c9174a766
								
							
						
					
					
						commit
						6a93c77082
					
				|  | @ -2476,6 +2476,24 @@ exports[`better eslint`] = { | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], |       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "2"] |       [0, 0, 0, "Unexpected any. Specify a different type.", "2"] | ||||||
|     ], |     ], | ||||||
|  |     "public/app/core/components/TimelineChart/TimelineChart.tsx:5381": [ | ||||||
|  |       [0, 0, 0, "Do not use any type assertions.", "0"], | ||||||
|  |       [0, 0, 0, "Unexpected any. Specify a different type.", "1"] | ||||||
|  |     ], | ||||||
|  |     "public/app/core/components/TimelineChart/timeline.ts:5381": [ | ||||||
|  |       [0, 0, 0, "Unexpected any. Specify a different type.", "0"], | ||||||
|  |       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], | ||||||
|  |       [0, 0, 0, "Unexpected any. Specify a different type.", "2"], | ||||||
|  |       [0, 0, 0, "Do not use any type assertions.", "3"], | ||||||
|  |       [0, 0, 0, "Do not use any type assertions.", "4"] | ||||||
|  |     ], | ||||||
|  |     "public/app/core/components/TimelineChart/utils.test.ts:5381": [ | ||||||
|  |       [0, 0, 0, "Unexpected any. Specify a different type.", "0"] | ||||||
|  |     ], | ||||||
|  |     "public/app/core/components/TimelineChart/utils.ts:5381": [ | ||||||
|  |       [0, 0, 0, "Unexpected any. Specify a different type.", "0"], | ||||||
|  |       [0, 0, 0, "Unexpected any. Specify a different type.", "1"] | ||||||
|  |     ], | ||||||
|     "public/app/core/components/connectWithCleanUp.tsx:5381": [ |     "public/app/core/components/connectWithCleanUp.tsx:5381": [ | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "0"], |       [0, 0, 0, "Unexpected any. Specify a different type.", "0"], | ||||||
|       [0, 0, 0, "Do not use any type assertions.", "1"] |       [0, 0, 0, "Do not use any type assertions.", "1"] | ||||||
|  | @ -7510,10 +7528,6 @@ exports[`better eslint`] = { | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], |       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], | ||||||
|       [0, 0, 0, "Do not use any type assertions.", "2"] |       [0, 0, 0, "Do not use any type assertions.", "2"] | ||||||
|     ], |     ], | ||||||
|     "public/app/plugins/panel/state-timeline/TimelineChart.tsx:5381": [ |  | ||||||
|       [0, 0, 0, "Do not use any type assertions.", "0"], |  | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "1"] |  | ||||||
|     ], |  | ||||||
|     "public/app/plugins/panel/state-timeline/migrations.ts:5381": [ |     "public/app/plugins/panel/state-timeline/migrations.ts:5381": [ | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "0"], |       [0, 0, 0, "Unexpected any. Specify a different type.", "0"], | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], |       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], | ||||||
|  | @ -7524,22 +7538,6 @@ exports[`better eslint`] = { | ||||||
|       [0, 0, 0, "Do not use any type assertions.", "6"], |       [0, 0, 0, "Do not use any type assertions.", "6"], | ||||||
|       [0, 0, 0, "Do not use any type assertions.", "7"] |       [0, 0, 0, "Do not use any type assertions.", "7"] | ||||||
|     ], |     ], | ||||||
|     "public/app/plugins/panel/state-timeline/timeline.ts:5381": [ |  | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "0"], |  | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], |  | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "2"], |  | ||||||
|       [0, 0, 0, "Do not use any type assertions.", "3"], |  | ||||||
|       [0, 0, 0, "Do not use any type assertions.", "4"] |  | ||||||
|     ], |  | ||||||
|     "public/app/plugins/panel/state-timeline/types.ts:5381": [ |  | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "0"] |  | ||||||
|     ], |  | ||||||
|     "public/app/plugins/panel/state-timeline/utils.test.ts:5381": [ |  | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "0"] |  | ||||||
|     ], |  | ||||||
|     "public/app/plugins/panel/state-timeline/utils.ts:5381": [ |  | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "0"] |  | ||||||
|     ], |  | ||||||
|     "public/app/plugins/panel/table-old/column_options.ts:5381": [ |     "public/app/plugins/panel/table-old/column_options.ts:5381": [ | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "0"], |       [0, 0, 0, "Unexpected any. Specify a different type.", "0"], | ||||||
|       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], |       [0, 0, 0, "Unexpected any. Specify a different type.", "1"], | ||||||
|  |  | ||||||
|  | @ -0,0 +1,41 @@ | ||||||
|  | --- | ||||||
|  | keywords: | ||||||
|  |   - grafana | ||||||
|  |   - schema | ||||||
|  | title: StateTimelinePanelCfg kind | ||||||
|  | --- | ||||||
|  | > Both documentation generation and kinds schemas are in active development and subject to change without prior notice. | ||||||
|  | 
 | ||||||
|  | # StateTimelinePanelCfg kind | ||||||
|  | 
 | ||||||
|  | ## Maturity: experimental | ||||||
|  | ## Version: 0.0 | ||||||
|  | 
 | ||||||
|  | ## Properties | ||||||
|  | 
 | ||||||
|  | | Property           | Type                        | Required | Description | | ||||||
|  | |--------------------|-----------------------------|----------|-------------| | ||||||
|  | | `PanelFieldConfig` | [object](#panelfieldconfig) | **Yes**  |             | | ||||||
|  | | `PanelOptions`     | [object](#paneloptions)     | **Yes**  |             | | ||||||
|  | 
 | ||||||
|  | ## PanelFieldConfig | ||||||
|  | 
 | ||||||
|  | ### Properties | ||||||
|  | 
 | ||||||
|  | | Property      | Type    | Required | Description    | | ||||||
|  | |---------------|---------|----------|----------------| | ||||||
|  | | `fillOpacity` | integer | No       | Default: `70`. | | ||||||
|  | | `lineWidth`   | integer | No       | Default: `0`.  | | ||||||
|  | 
 | ||||||
|  | ## PanelOptions | ||||||
|  | 
 | ||||||
|  | ### Properties | ||||||
|  | 
 | ||||||
|  | | Property      | Type    | Required | Description                                                                                                 | | ||||||
|  | |---------------|---------|----------|-------------------------------------------------------------------------------------------------------------| | ||||||
|  | | `alignValue`  | string  | No       | Controls the value alignment in the TimelineChart component Possible values are: `center`, `left`, `right`. | | ||||||
|  | | `mergeValues` | boolean | No       | Merge equal consecutive values Default: `true`.                                                             | | ||||||
|  | | `rowHeight`   | number  | No       | Controls the row height Default: `0.9`.                                                                     | | ||||||
|  | | `showValue`   | string  | No       | TODO docs Possible values are: `auto`, `never`, `always`.                                                   | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @ -0,0 +1,39 @@ | ||||||
|  | --- | ||||||
|  | keywords: | ||||||
|  |   - grafana | ||||||
|  |   - schema | ||||||
|  | title: StatusHistoryPanelCfg kind | ||||||
|  | --- | ||||||
|  | > Both documentation generation and kinds schemas are in active development and subject to change without prior notice. | ||||||
|  | 
 | ||||||
|  | # StatusHistoryPanelCfg kind | ||||||
|  | 
 | ||||||
|  | ## Maturity: experimental | ||||||
|  | ## Version: 0.0 | ||||||
|  | 
 | ||||||
|  | ## Properties | ||||||
|  | 
 | ||||||
|  | | Property           | Type                        | Required | Description | | ||||||
|  | |--------------------|-----------------------------|----------|-------------| | ||||||
|  | | `PanelFieldConfig` | [object](#panelfieldconfig) | **Yes**  |             | | ||||||
|  | | `PanelOptions`     | [object](#paneloptions)     | **Yes**  |             | | ||||||
|  | 
 | ||||||
|  | ## PanelFieldConfig | ||||||
|  | 
 | ||||||
|  | ### Properties | ||||||
|  | 
 | ||||||
|  | | Property      | Type    | Required | Description    | | ||||||
|  | |---------------|---------|----------|----------------| | ||||||
|  | | `fillOpacity` | integer | No       | Default: `70`. | | ||||||
|  | | `lineWidth`   | integer | No       | Default: `1`.  | | ||||||
|  | 
 | ||||||
|  | ## PanelOptions | ||||||
|  | 
 | ||||||
|  | ### Properties | ||||||
|  | 
 | ||||||
|  | | Property    | Type   | Required | Description                                               | | ||||||
|  | |-------------|--------|----------|-----------------------------------------------------------| | ||||||
|  | | `colWidth`  | number | No       | Controls the column width Default: `0.9`.                 | | ||||||
|  | | `showValue` | string | No       | TODO docs Possible values are: `auto`, `never`, `always`. | | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @ -485,6 +485,11 @@ export enum BigValueTextMode { | ||||||
|  */ |  */ | ||||||
| export type FieldTextAlignment = ('auto' | 'left' | 'right' | 'center'); | export type FieldTextAlignment = ('auto' | 'left' | 'right' | 'center'); | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Controls the value alignment in the TimelineChart component | ||||||
|  |  */ | ||||||
|  | export type TimelineValueAlignment = ('center' | 'left' | 'right'); | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * TODO docs |  * TODO docs | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -193,6 +193,9 @@ BigValueTextMode: "auto" | "value" | "value_and_name" | "name" | "none" @cuetsy( | ||||||
| // TODO docs | // TODO docs | ||||||
| FieldTextAlignment: "auto" | "left" | "right" | "center" @cuetsy(kind="type") | FieldTextAlignment: "auto" | "left" | "right" | "center" @cuetsy(kind="type") | ||||||
| 
 | 
 | ||||||
|  | // Controls the value alignment in the TimelineChart component | ||||||
|  | TimelineValueAlignment: "center" | "left" | "right" @cuetsy(kind="type") | ||||||
|  | 
 | ||||||
| // TODO docs | // TODO docs | ||||||
| VizTextDisplayOptions: { | VizTextDisplayOptions: { | ||||||
| 	// Explicit title text size | 	// Explicit title text size | ||||||
|  |  | ||||||
|  | @ -1349,6 +1349,30 @@ | ||||||
|       "pluralMachineName": "serviceaccounts", |       "pluralMachineName": "serviceaccounts", | ||||||
|       "pluralName": "ServiceAccounts" |       "pluralName": "ServiceAccounts" | ||||||
|     }, |     }, | ||||||
|  |     "statetimelinepanelcfg": { | ||||||
|  |       "category": "composable", | ||||||
|  |       "codeowners": [ | ||||||
|  |         "grafana/grafana-bi-squad" | ||||||
|  |       ], | ||||||
|  |       "currentVersion": [ | ||||||
|  |         0, | ||||||
|  |         0 | ||||||
|  |       ], | ||||||
|  |       "grafanaMaturityCount": 0, | ||||||
|  |       "lineageIsGroup": true, | ||||||
|  |       "links": { | ||||||
|  |         "docs": "https://grafana.com/docs/grafana/next/developers/kinds/composable/statetimelinepanelcfg/schema-reference", | ||||||
|  |         "go": "n/a", | ||||||
|  |         "schema": "https://github.com/grafana/grafana/tree/main/public/app/plugins/panel/state-timeline/panelcfg.cue", | ||||||
|  |         "ts": "https://github.com/grafana/grafana/tree/main/public/app/plugins/panel/state-timeline/panelcfg.gen.ts" | ||||||
|  |       }, | ||||||
|  |       "machineName": "statetimelinepanelcfg", | ||||||
|  |       "maturity": "experimental", | ||||||
|  |       "name": "StateTimelinePanelCfg", | ||||||
|  |       "pluralMachineName": "statetimelinepanelcfgs", | ||||||
|  |       "pluralName": "StateTimelinePanelCfgs", | ||||||
|  |       "schemaInterface": "PanelCfg" | ||||||
|  |     }, | ||||||
|     "statpanelcfg": { |     "statpanelcfg": { | ||||||
|       "category": "composable", |       "category": "composable", | ||||||
|       "codeowners": [ |       "codeowners": [ | ||||||
|  | @ -1373,6 +1397,30 @@ | ||||||
|       "pluralName": "StatPanelCfgs", |       "pluralName": "StatPanelCfgs", | ||||||
|       "schemaInterface": "PanelCfg" |       "schemaInterface": "PanelCfg" | ||||||
|     }, |     }, | ||||||
|  |     "statushistorypanelcfg": { | ||||||
|  |       "category": "composable", | ||||||
|  |       "codeowners": [ | ||||||
|  |         "grafana/grafana-bi-squad" | ||||||
|  |       ], | ||||||
|  |       "currentVersion": [ | ||||||
|  |         0, | ||||||
|  |         0 | ||||||
|  |       ], | ||||||
|  |       "grafanaMaturityCount": 0, | ||||||
|  |       "lineageIsGroup": true, | ||||||
|  |       "links": { | ||||||
|  |         "docs": "https://grafana.com/docs/grafana/next/developers/kinds/composable/statushistorypanelcfg/schema-reference", | ||||||
|  |         "go": "n/a", | ||||||
|  |         "schema": "https://github.com/grafana/grafana/tree/main/public/app/plugins/panel/status-history/panelcfg.cue", | ||||||
|  |         "ts": "https://github.com/grafana/grafana/tree/main/public/app/plugins/panel/status-history/panelcfg.gen.ts" | ||||||
|  |       }, | ||||||
|  |       "machineName": "statushistorypanelcfg", | ||||||
|  |       "maturity": "experimental", | ||||||
|  |       "name": "StatusHistoryPanelCfg", | ||||||
|  |       "pluralMachineName": "statushistorypanelcfgs", | ||||||
|  |       "pluralName": "StatusHistoryPanelCfgs", | ||||||
|  |       "schemaInterface": "PanelCfg" | ||||||
|  |     }, | ||||||
|     "tableoldpanelcfg": { |     "tableoldpanelcfg": { | ||||||
|       "category": "composable", |       "category": "composable", | ||||||
|       "codeowners": [], |       "codeowners": [], | ||||||
|  | @ -1744,7 +1792,9 @@ | ||||||
|           "postgresqldatasourcecfg", |           "postgresqldatasourcecfg", | ||||||
|           "prometheusdataquery", |           "prometheusdataquery", | ||||||
|           "prometheusdatasourcecfg", |           "prometheusdatasourcecfg", | ||||||
|  |           "statetimelinepanelcfg", | ||||||
|           "statpanelcfg", |           "statpanelcfg", | ||||||
|  |           "statushistorypanelcfg", | ||||||
|           "tableoldpanelcfg", |           "tableoldpanelcfg", | ||||||
|           "tempodataquery", |           "tempodataquery", | ||||||
|           "tempodatasourcecfg", |           "tempodatasourcecfg", | ||||||
|  | @ -1757,7 +1807,7 @@ | ||||||
|           "zipkindataquery", |           "zipkindataquery", | ||||||
|           "zipkindatasourcecfg" |           "zipkindatasourcecfg" | ||||||
|         ], |         ], | ||||||
|         "count": 63 |         "count": 65 | ||||||
|       }, |       }, | ||||||
|       "core": { |       "core": { | ||||||
|         "name": "core", |         "name": "core", | ||||||
|  | @ -1791,11 +1841,13 @@ | ||||||
|           "histogrampanelcfg", |           "histogrampanelcfg", | ||||||
|           "newspanelcfg", |           "newspanelcfg", | ||||||
|           "piechartpanelcfg", |           "piechartpanelcfg", | ||||||
|  |           "statetimelinepanelcfg", | ||||||
|           "statpanelcfg", |           "statpanelcfg", | ||||||
|  |           "statushistorypanelcfg", | ||||||
|           "textpanelcfg", |           "textpanelcfg", | ||||||
|           "xychartpanelcfg" |           "xychartpanelcfg" | ||||||
|         ], |         ], | ||||||
|         "count": 12 |         "count": 14 | ||||||
|       }, |       }, | ||||||
|       "mature": { |       "mature": { | ||||||
|         "name": "mature", |         "name": "mature", | ||||||
|  |  | ||||||
|  | @ -71,6 +71,8 @@ func corePlugins(rt *thema.Runtime) []pfs.ParsedPlugin { | ||||||
| 		parsePluginOrPanic("public/app/plugins/panel/nodeGraph", "nodeGraph", rt), | 		parsePluginOrPanic("public/app/plugins/panel/nodeGraph", "nodeGraph", rt), | ||||||
| 		parsePluginOrPanic("public/app/plugins/panel/piechart", "piechart", rt), | 		parsePluginOrPanic("public/app/plugins/panel/piechart", "piechart", rt), | ||||||
| 		parsePluginOrPanic("public/app/plugins/panel/stat", "stat", rt), | 		parsePluginOrPanic("public/app/plugins/panel/stat", "stat", rt), | ||||||
|  | 		parsePluginOrPanic("public/app/plugins/panel/state-timeline", "state_timeline", rt), | ||||||
|  | 		parsePluginOrPanic("public/app/plugins/panel/status-history", "status_history", rt), | ||||||
| 		parsePluginOrPanic("public/app/plugins/panel/table-old", "table_old", rt), | 		parsePluginOrPanic("public/app/plugins/panel/table-old", "table_old", rt), | ||||||
| 		parsePluginOrPanic("public/app/plugins/panel/text", "text", rt), | 		parsePluginOrPanic("public/app/plugins/panel/text", "text", rt), | ||||||
| 		parsePluginOrPanic("public/app/plugins/panel/traces", "traces", rt), | 		parsePluginOrPanic("public/app/plugins/panel/traces", "traces", rt), | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import React from 'react'; | import React from 'react'; | ||||||
| 
 | 
 | ||||||
| import { DataFrame, FALLBACK_COLOR, FieldType, TimeRange } from '@grafana/data'; | import { DataFrame, FALLBACK_COLOR, FieldType, TimeRange } from '@grafana/data'; | ||||||
| import { VisibilityMode } from '@grafana/schema'; | import { VisibilityMode, TimelineValueAlignment } from '@grafana/schema'; | ||||||
| import { | import { | ||||||
|   PanelContext, |   PanelContext, | ||||||
|   PanelContextRoot, |   PanelContextRoot, | ||||||
|  | @ -13,17 +13,14 @@ import { | ||||||
|   VizLegendItem, |   VizLegendItem, | ||||||
| } from '@grafana/ui'; | } from '@grafana/ui'; | ||||||
| 
 | 
 | ||||||
| import { TimelineMode, TimelineOptions, TimelineValueAlignment } from './types'; | import { preparePlotConfigBuilder, TimelineMode } from './utils'; | ||||||
| import { preparePlotConfigBuilder } from './utils'; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @alpha |  * @alpha | ||||||
|  */ |  */ | ||||||
| export interface TimelineProps | export interface TimelineProps extends Omit<GraphNGProps, 'prepConfig' | 'propsToDiff' | 'renderLegend'> { | ||||||
|   extends TimelineOptions, |  | ||||||
|     Omit<GraphNGProps, 'prepConfig' | 'propsToDiff' | 'renderLegend'> { |  | ||||||
|   mode: TimelineMode; |   mode: TimelineMode; | ||||||
|   rowHeight: number; |   rowHeight?: number; | ||||||
|   showValue: VisibilityMode; |   showValue: VisibilityMode; | ||||||
|   alignValue?: TimelineValueAlignment; |   alignValue?: TimelineValueAlignment; | ||||||
|   colWidth?: number; |   colWidth?: number; | ||||||
|  | @ -2,12 +2,14 @@ import uPlot, { Cursor, Series } from 'uplot'; | ||||||
| 
 | 
 | ||||||
| import { GrafanaTheme2, TimeRange } from '@grafana/data'; | import { GrafanaTheme2, TimeRange } from '@grafana/data'; | ||||||
| import { alpha } from '@grafana/data/src/themes/colorManipulator'; | import { alpha } from '@grafana/data/src/themes/colorManipulator'; | ||||||
| import { VisibilityMode } from '@grafana/schema'; | import { VisibilityMode, TimelineValueAlignment } from '@grafana/schema'; | ||||||
| import { FIXED_UNIT } from '@grafana/ui/src/components/GraphNG/GraphNG'; | import { FIXED_UNIT } from '@grafana/ui/src/components/GraphNG/GraphNG'; | ||||||
| import { distribute, SPACE_BETWEEN } from 'app/plugins/panel/barchart/distribute'; | import { distribute, SPACE_BETWEEN } from 'app/plugins/panel/barchart/distribute'; | ||||||
| import { pointWithin, Quadtree, Rect } from 'app/plugins/panel/barchart/quadtree'; | import { pointWithin, Quadtree, Rect } from 'app/plugins/panel/barchart/quadtree'; | ||||||
|  | import { PanelFieldConfig as StateTimeLineFieldConfig } from 'app/plugins/panel/state-timeline/panelcfg.gen'; | ||||||
|  | import { PanelFieldConfig as StatusHistoryFieldConfig } from 'app/plugins/panel/status-history/panelcfg.gen'; | ||||||
| 
 | 
 | ||||||
| import { TimelineFieldConfig, TimelineMode, TimelineValueAlignment } from './types'; | import { TimelineMode } from './utils'; | ||||||
| 
 | 
 | ||||||
| const { round, min, ceil } = Math; | const { round, min, ceil } = Math; | ||||||
| 
 | 
 | ||||||
|  | @ -39,7 +41,7 @@ export interface TimelineCoreOptions { | ||||||
|   mode: TimelineMode; |   mode: TimelineMode; | ||||||
|   alignValue?: TimelineValueAlignment; |   alignValue?: TimelineValueAlignment; | ||||||
|   numSeries: number; |   numSeries: number; | ||||||
|   rowHeight: number; |   rowHeight?: number; | ||||||
|   colWidth?: number; |   colWidth?: number; | ||||||
|   theme: GrafanaTheme2; |   theme: GrafanaTheme2; | ||||||
|   showValue: VisibilityMode; |   showValue: VisibilityMode; | ||||||
|  | @ -49,7 +51,7 @@ export interface TimelineCoreOptions { | ||||||
|   label: (seriesIdx: number) => string; |   label: (seriesIdx: number) => string; | ||||||
|   getTimeRange: () => TimeRange; |   getTimeRange: () => TimeRange; | ||||||
|   formatValue?: (seriesIdx: number, value: any) => string; |   formatValue?: (seriesIdx: number, value: any) => string; | ||||||
|   getFieldConfig: (seriesIdx: number) => TimelineFieldConfig; |   getFieldConfig: (seriesIdx: number) => StateTimeLineFieldConfig | StatusHistoryFieldConfig; | ||||||
|   onHover: (seriesIdx: number, valueIdx: number, rect: Rect) => void; |   onHover: (seriesIdx: number, valueIdx: number, rect: Rect) => void; | ||||||
|   onLeave: () => void; |   onLeave: () => void; | ||||||
| } | } | ||||||
|  | @ -567,7 +569,7 @@ export function getConfig(opts: TimelineCoreOptions) { | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getFillColor(fieldConfig: TimelineFieldConfig, color: string) { | function getFillColor(fieldConfig: { fillOpacity?: number; lineWidth?: number }, color: string) { | ||||||
|   // if #rgba with pre-existing alpha. ignore fieldConfig.fillOpacity
 |   // if #rgba with pre-existing alpha. ignore fieldConfig.fillOpacity
 | ||||||
|   // e.g. thresholds with opacity
 |   // e.g. thresholds with opacity
 | ||||||
|   if (color[0] === '#' && color.length === 9) { |   if (color[0] === '#' && color.length === 9) { | ||||||
|  | @ -24,7 +24,15 @@ import { | ||||||
|   TimeRange, |   TimeRange, | ||||||
| } from '@grafana/data'; | } from '@grafana/data'; | ||||||
| import { maybeSortFrame } from '@grafana/data/src/transformations/transformers/joinDataFrames'; | import { maybeSortFrame } from '@grafana/data/src/transformations/transformers/joinDataFrames'; | ||||||
| import { VizLegendOptions, AxisPlacement, ScaleDirection, ScaleOrientation } from '@grafana/schema'; | import { | ||||||
|  |   VizLegendOptions, | ||||||
|  |   AxisPlacement, | ||||||
|  |   ScaleDirection, | ||||||
|  |   ScaleOrientation, | ||||||
|  |   VisibilityMode, | ||||||
|  |   TimelineValueAlignment, | ||||||
|  |   HideableFieldConfig, | ||||||
|  | } from '@grafana/schema'; | ||||||
| import { | import { | ||||||
|   FIXED_UNIT, |   FIXED_UNIT, | ||||||
|   SeriesVisibilityChangeMode, |   SeriesVisibilityChangeMode, | ||||||
|  | @ -38,9 +46,37 @@ import { PlotTooltipInterpolator } from '@grafana/ui/src/components/uPlot/types' | ||||||
| import { preparePlotData2, getStackingGroups } from '@grafana/ui/src/components/uPlot/utils'; | import { preparePlotData2, getStackingGroups } from '@grafana/ui/src/components/uPlot/utils'; | ||||||
| 
 | 
 | ||||||
| import { getConfig, TimelineCoreOptions } from './timeline'; | import { getConfig, TimelineCoreOptions } from './timeline'; | ||||||
| import { TimelineFieldConfig, TimelineOptions } from './types'; |  | ||||||
| 
 | 
 | ||||||
| const defaultConfig: TimelineFieldConfig = { | /** | ||||||
|  |  * @internal | ||||||
|  |  */ | ||||||
|  | interface UPlotConfigOptions { | ||||||
|  |   frame: DataFrame; | ||||||
|  |   theme: GrafanaTheme2; | ||||||
|  |   mode: TimelineMode; | ||||||
|  |   sync?: () => DashboardCursorSync; | ||||||
|  |   rowHeight?: number; | ||||||
|  |   colWidth?: number; | ||||||
|  |   showValue: VisibilityMode; | ||||||
|  |   alignValue?: TimelineValueAlignment; | ||||||
|  |   mergeValues?: boolean; | ||||||
|  |   getValueColor: (frameIdx: number, fieldIdx: number, value: any) => string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @internal | ||||||
|  |  */ | ||||||
|  | interface PanelFieldConfig extends HideableFieldConfig { | ||||||
|  |   fillOpacity?: number; | ||||||
|  |   lineWidth?: number; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export enum TimelineMode { | ||||||
|  |   Changes = 'changes', | ||||||
|  |   Samples = 'samples', | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const defaultConfig: PanelFieldConfig = { | ||||||
|   lineWidth: 0, |   lineWidth: 0, | ||||||
|   fillOpacity: 80, |   fillOpacity: 80, | ||||||
| }; | }; | ||||||
|  | @ -52,7 +88,7 @@ export function mapMouseEventToMode(event: React.MouseEvent): SeriesVisibilityCh | ||||||
|   return SeriesVisibilityChangeMode.ToggleSelection; |   return SeriesVisibilityChangeMode.ToggleSelection; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({ | export const preparePlotConfigBuilder: UPlotConfigPrepFn<UPlotConfigOptions> = ({ | ||||||
|   frame, |   frame, | ||||||
|   theme, |   theme, | ||||||
|   timeZones, |   timeZones, | ||||||
|  | @ -92,12 +128,11 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({ | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const opts: TimelineCoreOptions = { |   const opts: TimelineCoreOptions = { | ||||||
|     // should expose in panel config
 |  | ||||||
|     mode: mode!, |     mode: mode!, | ||||||
|     numSeries: frame.fields.length - 1, |     numSeries: frame.fields.length - 1, | ||||||
|     isDiscrete: (seriesIdx) => isDiscrete(frame.fields[seriesIdx]), |     isDiscrete: (seriesIdx) => isDiscrete(frame.fields[seriesIdx]), | ||||||
|     mergeValues, |     mergeValues, | ||||||
|     rowHeight: rowHeight!, |     rowHeight: rowHeight, | ||||||
|     colWidth: colWidth, |     colWidth: colWidth, | ||||||
|     showValue: showValue!, |     showValue: showValue!, | ||||||
|     alignValue, |     alignValue, | ||||||
|  | @ -209,8 +244,8 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({ | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const field = frame.fields[i]; |     const field = frame.fields[i]; | ||||||
|     const config: FieldConfig<TimelineFieldConfig> = field.config; |     const config: FieldConfig<PanelFieldConfig> = field.config; | ||||||
|     const customConfig: TimelineFieldConfig = { |     const customConfig: PanelFieldConfig = { | ||||||
|       ...defaultConfig, |       ...defaultConfig, | ||||||
|       ...config.custom, |       ...config.custom, | ||||||
|     }; |     }; | ||||||
|  | @ -21,16 +21,14 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var skipPlugins = map[string]bool{ | var skipPlugins = map[string]bool{ | ||||||
| 	"canvas":         true, | 	"canvas":      true, | ||||||
| 	"heatmap":        true, | 	"heatmap":     true, | ||||||
| 	"candlestick":    true, | 	"candlestick": true, | ||||||
| 	"state-timeline": true, | 	"table":       true, | ||||||
| 	"status-history": true, | 	"timeseries":  true, | ||||||
| 	"table":          true, | 	"influxdb":    true, // plugin.json fails validation (defaultMatchFormat)
 | ||||||
| 	"timeseries":     true, | 	"mixed":       true, // plugin.json fails validation (mixed)
 | ||||||
| 	"influxdb":       true, // plugin.json fails validation (defaultMatchFormat)
 | 	"opentsdb":    true, // plugin.json fails validation (defaultMatchFormat)
 | ||||||
| 	"mixed":          true, // plugin.json fails validation (mixed)
 |  | ||||||
| 	"opentsdb":       true, // plugin.json fails validation (defaultMatchFormat)
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const sep = string(filepath.Separator) | const sep = string(filepath.Separator) | ||||||
|  |  | ||||||
|  | @ -33,9 +33,9 @@ import { | ||||||
| import { PropDiffFn } from '@grafana/ui/src/components/GraphNG/GraphNG'; | import { PropDiffFn } from '@grafana/ui/src/components/GraphNG/GraphNG'; | ||||||
| import { HoverEvent, addTooltipSupport } from '@grafana/ui/src/components/uPlot/config/addTooltipSupport'; | import { HoverEvent, addTooltipSupport } from '@grafana/ui/src/components/uPlot/config/addTooltipSupport'; | ||||||
| import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; | import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; | ||||||
|  | import { getFieldLegendItem } from 'app/core/components/TimelineChart/utils'; | ||||||
| 
 | 
 | ||||||
| import { DataHoverView } from '../geomap/components/DataHoverView'; | import { DataHoverView } from '../geomap/components/DataHoverView'; | ||||||
| import { getFieldLegendItem } from '../state-timeline/utils'; |  | ||||||
| 
 | 
 | ||||||
| import { PanelOptions } from './panelcfg.gen'; | import { PanelOptions } from './panelcfg.gen'; | ||||||
| import { prepareBarChartDisplayValues, preparePlotConfigBuilder } from './utils'; | import { prepareBarChartDisplayValues, preparePlotConfigBuilder } from './utils'; | ||||||
|  |  | ||||||
|  | @ -9,9 +9,9 @@ import { getMinMaxAndDelta } from '@grafana/data/src/field/scale'; | ||||||
| import { useStyles2, VizLegendItem } from '@grafana/ui'; | import { useStyles2, VizLegendItem } from '@grafana/ui'; | ||||||
| import { ColorScale } from 'app/core/components/ColorScale/ColorScale'; | import { ColorScale } from 'app/core/components/ColorScale/ColorScale'; | ||||||
| import { SanitizedSVG } from 'app/core/components/SVG/SanitizedSVG'; | import { SanitizedSVG } from 'app/core/components/SVG/SanitizedSVG'; | ||||||
|  | import { getThresholdItems } from 'app/core/components/TimelineChart/utils'; | ||||||
| import { config } from 'app/core/config'; | import { config } from 'app/core/config'; | ||||||
| import { DimensionSupplier } from 'app/features/dimensions'; | import { DimensionSupplier } from 'app/features/dimensions'; | ||||||
| import { getThresholdItems } from 'app/plugins/panel/state-timeline/utils'; |  | ||||||
| 
 | 
 | ||||||
| import { StyleConfigState } from '../style/types'; | import { StyleConfigState } from '../style/types'; | ||||||
| import { MapLayerState } from '../types'; | import { MapLayerState } from '../types'; | ||||||
|  |  | ||||||
|  | @ -12,6 +12,12 @@ import { | ||||||
| } from '@grafana/ui'; | } from '@grafana/ui'; | ||||||
| import { HoverEvent, addTooltipSupport } from '@grafana/ui/src/components/uPlot/config/addTooltipSupport'; | import { HoverEvent, addTooltipSupport } from '@grafana/ui/src/components/uPlot/config/addTooltipSupport'; | ||||||
| import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; | import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; | ||||||
|  | import { TimelineChart } from 'app/core/components/TimelineChart/TimelineChart'; | ||||||
|  | import { | ||||||
|  |   prepareTimelineFields, | ||||||
|  |   prepareTimelineLegendItems, | ||||||
|  |   TimelineMode, | ||||||
|  | } from 'app/core/components/TimelineChart/utils'; | ||||||
| import { getLastStreamingDataFramePacket } from 'app/features/live/data/StreamingDataFrame'; | import { getLastStreamingDataFramePacket } from 'app/features/live/data/StreamingDataFrame'; | ||||||
| 
 | 
 | ||||||
| import { AnnotationEditorPlugin } from '../timeseries/plugins/AnnotationEditorPlugin'; | import { AnnotationEditorPlugin } from '../timeseries/plugins/AnnotationEditorPlugin'; | ||||||
|  | @ -20,13 +26,11 @@ import { OutsideRangePlugin } from '../timeseries/plugins/OutsideRangePlugin'; | ||||||
| import { getTimezones } from '../timeseries/utils'; | import { getTimezones } from '../timeseries/utils'; | ||||||
| 
 | 
 | ||||||
| import { StateTimelineTooltip } from './StateTimelineTooltip'; | import { StateTimelineTooltip } from './StateTimelineTooltip'; | ||||||
| import { TimelineChart } from './TimelineChart'; | import { PanelOptions } from './panelcfg.gen'; | ||||||
| import { TimelineMode, TimelineOptions } from './types'; |  | ||||||
| import { prepareTimelineFields, prepareTimelineLegendItems } from './utils'; |  | ||||||
| 
 | 
 | ||||||
| const TOOLTIP_OFFSET = 10; | const TOOLTIP_OFFSET = 10; | ||||||
| 
 | 
 | ||||||
| interface TimelinePanelProps extends PanelProps<TimelineOptions> {} | interface TimelinePanelProps extends PanelProps<PanelOptions> {} | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @alpha |  * @alpha | ||||||
|  |  | ||||||
|  | @ -10,8 +10,7 @@ import { | ||||||
|   LinkModel, |   LinkModel, | ||||||
| } from '@grafana/data'; | } from '@grafana/data'; | ||||||
| import { MenuItem, SeriesTableRow, useTheme2 } from '@grafana/ui'; | import { MenuItem, SeriesTableRow, useTheme2 } from '@grafana/ui'; | ||||||
| 
 | import { findNextStateIndex, fmtDuration } from 'app/core/components/TimelineChart/utils'; | ||||||
| import { findNextStateIndex, fmtDuration } from './utils'; |  | ||||||
| 
 | 
 | ||||||
| interface StateTimelineTooltipProps { | interface StateTimelineTooltipProps { | ||||||
|   data: DataFrame[]; |   data: DataFrame[]; | ||||||
|  |  | ||||||
|  | @ -2,15 +2,15 @@ import { isArray } from 'lodash'; | ||||||
| 
 | 
 | ||||||
| import { FieldConfigSource, MappingType, PanelModel, ValueMap } from '@grafana/data'; | import { FieldConfigSource, MappingType, PanelModel, ValueMap } from '@grafana/data'; | ||||||
| 
 | 
 | ||||||
| import { TimelineFieldConfig, TimelineOptions } from './types'; | import { PanelFieldConfig, PanelOptions } from './panelcfg.gen'; | ||||||
| 
 | 
 | ||||||
| // This is called when the panel changes from another panel
 | // This is called when the panel changes from another panel
 | ||||||
| export const timelinePanelChangedHandler = ( | export const timelinePanelChangedHandler = ( | ||||||
|   panel: PanelModel<Partial<TimelineOptions>> | any, |   panel: PanelModel<Partial<PanelOptions>> | any, | ||||||
|   prevPluginId: string, |   prevPluginId: string, | ||||||
|   prevOptions: any |   prevOptions: any | ||||||
| ) => { | ) => { | ||||||
|   let options = (panel.options ?? {}) as TimelineOptions; |   let options = (panel.options ?? {}) as PanelOptions; | ||||||
| 
 | 
 | ||||||
|   // Changing from angular singlestat
 |   // Changing from angular singlestat
 | ||||||
|   if (prevPluginId === 'natel-discrete-panel' && prevOptions.angular) { |   if (prevPluginId === 'natel-discrete-panel' && prevOptions.angular) { | ||||||
|  | @ -21,7 +21,7 @@ export const timelinePanelChangedHandler = ( | ||||||
|       fieldConfig.defaults.unit = oldOptions.units; |       fieldConfig.defaults.unit = oldOptions.units; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const custom: TimelineFieldConfig = { |     const custom: PanelFieldConfig = { | ||||||
|       fillOpacity: 100, |       fillOpacity: 100, | ||||||
|       lineWidth: 0, |       lineWidth: 0, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -12,10 +12,10 @@ import { SpanNullsEditor } from '../timeseries/SpanNullsEditor'; | ||||||
| 
 | 
 | ||||||
| import { StateTimelinePanel } from './StateTimelinePanel'; | import { StateTimelinePanel } from './StateTimelinePanel'; | ||||||
| import { timelinePanelChangedHandler } from './migrations'; | import { timelinePanelChangedHandler } from './migrations'; | ||||||
|  | import { PanelOptions, PanelFieldConfig, defaultPanelOptions, defaultPanelFieldConfig } from './panelcfg.gen'; | ||||||
| import { StatTimelineSuggestionsSupplier } from './suggestions'; | import { StatTimelineSuggestionsSupplier } from './suggestions'; | ||||||
| import { TimelineOptions, TimelineFieldConfig, defaultPanelOptions, defaultTimelineFieldConfig } from './types'; |  | ||||||
| 
 | 
 | ||||||
| export const plugin = new PanelPlugin<TimelineOptions, TimelineFieldConfig>(StateTimelinePanel) | export const plugin = new PanelPlugin<PanelOptions, PanelFieldConfig>(StateTimelinePanel) | ||||||
|   .setPanelChangeHandler(timelinePanelChangedHandler) |   .setPanelChangeHandler(timelinePanelChangedHandler) | ||||||
|   .useFieldConfig({ |   .useFieldConfig({ | ||||||
|     standardOptions: { |     standardOptions: { | ||||||
|  | @ -33,7 +33,7 @@ export const plugin = new PanelPlugin<TimelineOptions, TimelineFieldConfig>(Stat | ||||||
|         .addSliderInput({ |         .addSliderInput({ | ||||||
|           path: 'lineWidth', |           path: 'lineWidth', | ||||||
|           name: 'Line width', |           name: 'Line width', | ||||||
|           defaultValue: defaultTimelineFieldConfig.lineWidth, |           defaultValue: defaultPanelFieldConfig.lineWidth, | ||||||
|           settings: { |           settings: { | ||||||
|             min: 0, |             min: 0, | ||||||
|             max: 10, |             max: 10, | ||||||
|  | @ -43,7 +43,7 @@ export const plugin = new PanelPlugin<TimelineOptions, TimelineFieldConfig>(Stat | ||||||
|         .addSliderInput({ |         .addSliderInput({ | ||||||
|           path: 'fillOpacity', |           path: 'fillOpacity', | ||||||
|           name: 'Fill opacity', |           name: 'Fill opacity', | ||||||
|           defaultValue: defaultTimelineFieldConfig.fillOpacity, |           defaultValue: defaultPanelFieldConfig.fillOpacity, | ||||||
|           settings: { |           settings: { | ||||||
|             min: 0, |             min: 0, | ||||||
|             max: 100, |             max: 100, | ||||||
|  |  | ||||||
|  | @ -15,33 +15,34 @@ | ||||||
| package grafanaplugin | package grafanaplugin | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"github.com/grafana/grafana/packages/grafana-schema/src/common" | 	ui "github.com/grafana/grafana/packages/grafana-schema/src/common" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| composableKinds: PanelCfg: { | composableKinds: PanelCfg: { | ||||||
|  | 	maturity: "experimental" | ||||||
| 	lineage: { | 	lineage: { | ||||||
| 		seqs: [ | 		seqs: [ | ||||||
| 			{ | 			{ | ||||||
| 				schemas: [ | 				schemas: [ | ||||||
| 					{ | 					{ | ||||||
| 						TimelineMode:           "changes" | "samples"       @cuetsy(kind="enum") |  | ||||||
| 						TimelineValueAlignment: "center" | "left" | "right" @cuetsy(kind="type") |  | ||||||
| 						PanelOptions: { | 						PanelOptions: { | ||||||
| 							// FIXME ts comments indicate this shouldn't be in the saved model, but currently is emitted | 							ui.OptionsWithLegend | ||||||
| 							mode?: TimelineMode | 							ui.OptionsWithTooltip | ||||||
| 							common.OptionsWithLegend | 							ui.OptionsWithTimezones | ||||||
| 							common.OptionsWithTooltip | 
 | ||||||
| 							common.OptionsWithTimezones | 							//Show timeline values on chart | ||||||
| 							showValue:    common.VisibilityMode | *"auto" | 							showValue: ui.VisibilityMode | *"auto" | ||||||
| 							rowHeight:    number | *0.9 | 							//Controls the row height | ||||||
| 							colWidth?:    number | 							rowHeight: float & <=1 | *0.9 | ||||||
|  | 							//Merge equal consecutive values | ||||||
| 							mergeValues?: bool | *true | 							mergeValues?: bool | *true | ||||||
| 							alignValue?:  TimelineValueAlignment | *"left" | 							//Controls value alignment on the timelines | ||||||
|  | 							alignValue?: ui.TimelineValueAlignment | *"left" | ||||||
| 						} @cuetsy(kind="interface") | 						} @cuetsy(kind="interface") | ||||||
| 						PanelFieldConfig: { | 						PanelFieldConfig: { | ||||||
| 							common.HideableFieldConfig | 							ui.HideableFieldConfig | ||||||
| 							lineWidth?:   number | *0 | 							lineWidth?:   uint32 & <=10 | *0 | ||||||
| 							fillOpacity?: number | *70 | 							fillOpacity?: uint32 & <=100 | *70 | ||||||
| 						} @cuetsy(kind="interface") | 						} @cuetsy(kind="interface") | ||||||
| 					}, | 					}, | ||||||
| 				] | 				] | ||||||
|  |  | ||||||
|  | @ -0,0 +1,49 @@ | ||||||
|  | // Code generated - EDITING IS FUTILE. DO NOT EDIT.
 | ||||||
|  | //
 | ||||||
|  | // Generated by:
 | ||||||
|  | //     public/app/plugins/gen.go
 | ||||||
|  | // Using jennies:
 | ||||||
|  | //     TSTypesJenny
 | ||||||
|  | //     PluginTSTypesJenny
 | ||||||
|  | //
 | ||||||
|  | // Run 'make gen-cue' from repository root to regenerate.
 | ||||||
|  | 
 | ||||||
|  | import * as ui from '@grafana/schema'; | ||||||
|  | 
 | ||||||
|  | export const PanelCfgModelVersion = Object.freeze([0, 0]); | ||||||
|  | 
 | ||||||
|  | export interface PanelOptions extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones { | ||||||
|  |   /** | ||||||
|  |    * Controls value alignment on the timelines | ||||||
|  |    */ | ||||||
|  |   alignValue?: ui.TimelineValueAlignment; | ||||||
|  |   /** | ||||||
|  |    * Merge equal consecutive values | ||||||
|  |    */ | ||||||
|  |   mergeValues?: boolean; | ||||||
|  |   /** | ||||||
|  |    * Controls the row height | ||||||
|  |    */ | ||||||
|  |   rowHeight: number; | ||||||
|  |   /** | ||||||
|  |    * Show timeline values on chart | ||||||
|  |    */ | ||||||
|  |   showValue: ui.VisibilityMode; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const defaultPanelOptions: Partial<PanelOptions> = { | ||||||
|  |   alignValue: 'left', | ||||||
|  |   mergeValues: true, | ||||||
|  |   rowHeight: 0.9, | ||||||
|  |   showValue: ui.VisibilityMode.Auto, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export interface PanelFieldConfig extends ui.HideableFieldConfig { | ||||||
|  |   fillOpacity?: number; | ||||||
|  |   lineWidth?: number; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const defaultPanelFieldConfig: Partial<PanelFieldConfig> = { | ||||||
|  |   fillOpacity: 70, | ||||||
|  |   lineWidth: 0, | ||||||
|  | }; | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { VisualizationSuggestionsBuilder } from '@grafana/data'; | import { VisualizationSuggestionsBuilder } from '@grafana/data'; | ||||||
| import { SuggestionName } from 'app/types/suggestions'; | import { SuggestionName } from 'app/types/suggestions'; | ||||||
| 
 | 
 | ||||||
| import { TimelineFieldConfig, TimelineOptions } from './types'; | import { PanelFieldConfig, PanelOptions } from './panelcfg.gen'; | ||||||
| 
 | 
 | ||||||
| export class StatTimelineSuggestionsSupplier { | export class StatTimelineSuggestionsSupplier { | ||||||
|   getSuggestionsForData(builder: VisualizationSuggestionsBuilder) { |   getSuggestionsForData(builder: VisualizationSuggestionsBuilder) { | ||||||
|  | @ -26,7 +26,7 @@ export class StatTimelineSuggestionsSupplier { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const list = builder.getListAppender<TimelineOptions, TimelineFieldConfig>({ |     const list = builder.getListAppender<PanelOptions, PanelFieldConfig>({ | ||||||
|       name: '', |       name: '', | ||||||
|       pluginId: 'state-timeline', |       pluginId: 'state-timeline', | ||||||
|       options: {}, |       options: {}, | ||||||
|  |  | ||||||
|  | @ -1,66 +0,0 @@ | ||||||
| import { DashboardCursorSync } from '@grafana/data'; |  | ||||||
| import { |  | ||||||
|   HideableFieldConfig, |  | ||||||
|   OptionsWithLegend, |  | ||||||
|   OptionsWithTimezones, |  | ||||||
|   OptionsWithTooltip, |  | ||||||
|   VisibilityMode, |  | ||||||
| } from '@grafana/schema'; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @alpha |  | ||||||
|  */ |  | ||||||
| export interface TimelineOptions extends OptionsWithLegend, OptionsWithTooltip, OptionsWithTimezones { |  | ||||||
|   mode: TimelineMode; // not in the saved model!
 |  | ||||||
| 
 |  | ||||||
|   showValue: VisibilityMode; |  | ||||||
|   rowHeight: number; |  | ||||||
| 
 |  | ||||||
|   // only used for "samples" mode (status-history)
 |  | ||||||
|   colWidth?: number; |  | ||||||
|   // only used in "changes" mode (state-timeline)
 |  | ||||||
|   mergeValues?: boolean; |  | ||||||
|   // only used in "changes" mode (state-timeline)
 |  | ||||||
|   alignValue?: TimelineValueAlignment; |  | ||||||
| 
 |  | ||||||
|   sync?: () => DashboardCursorSync; |  | ||||||
|   getValueColor?: (frameIdx: number, fieldIdx: number, value: any) => string; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export type TimelineValueAlignment = 'center' | 'left' | 'right'; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @alpha |  | ||||||
|  */ |  | ||||||
| export interface TimelineFieldConfig extends HideableFieldConfig { |  | ||||||
|   lineWidth?: number; // 0
 |  | ||||||
|   fillOpacity?: number; // 100
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @alpha |  | ||||||
|  */ |  | ||||||
| export const defaultPanelOptions: Partial<TimelineOptions> = { |  | ||||||
|   showValue: VisibilityMode.Auto, |  | ||||||
|   alignValue: 'left', |  | ||||||
|   mergeValues: true, |  | ||||||
|   rowHeight: 0.9, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @alpha |  | ||||||
|  */ |  | ||||||
| export const defaultTimelineFieldConfig: TimelineFieldConfig = { |  | ||||||
|   lineWidth: 0, |  | ||||||
|   fillOpacity: 70, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @alpha |  | ||||||
|  */ |  | ||||||
| export enum TimelineMode { |  | ||||||
|   // state-timeline
 |  | ||||||
|   Changes = 'changes', |  | ||||||
|   // status-history
 |  | ||||||
|   Samples = 'samples', |  | ||||||
| } |  | ||||||
|  | @ -12,19 +12,22 @@ import { | ||||||
| } from '@grafana/ui'; | } from '@grafana/ui'; | ||||||
| import { HoverEvent, addTooltipSupport } from '@grafana/ui/src/components/uPlot/config/addTooltipSupport'; | import { HoverEvent, addTooltipSupport } from '@grafana/ui/src/components/uPlot/config/addTooltipSupport'; | ||||||
| import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; | import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; | ||||||
|  | import { TimelineChart } from 'app/core/components/TimelineChart/TimelineChart'; | ||||||
|  | import { | ||||||
|  |   prepareTimelineFields, | ||||||
|  |   prepareTimelineLegendItems, | ||||||
|  |   TimelineMode, | ||||||
|  | } from 'app/core/components/TimelineChart/utils'; | ||||||
| 
 | 
 | ||||||
| import { TimelineChart } from '../state-timeline/TimelineChart'; |  | ||||||
| import { TimelineMode } from '../state-timeline/types'; |  | ||||||
| import { prepareTimelineFields, prepareTimelineLegendItems } from '../state-timeline/utils'; |  | ||||||
| import { OutsideRangePlugin } from '../timeseries/plugins/OutsideRangePlugin'; | import { OutsideRangePlugin } from '../timeseries/plugins/OutsideRangePlugin'; | ||||||
| import { getTimezones } from '../timeseries/utils'; | import { getTimezones } from '../timeseries/utils'; | ||||||
| 
 | 
 | ||||||
| import { StatusHistoryTooltip } from './StatusHistoryTooltip'; | import { StatusHistoryTooltip } from './StatusHistoryTooltip'; | ||||||
| import { StatusPanelOptions } from './types'; | import { PanelOptions } from './panelcfg.gen'; | ||||||
| 
 | 
 | ||||||
| const TOOLTIP_OFFSET = 10; | const TOOLTIP_OFFSET = 10; | ||||||
| 
 | 
 | ||||||
| interface TimelinePanelProps extends PanelProps<StatusPanelOptions> {} | interface TimelinePanelProps extends PanelProps<PanelOptions> {} | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @alpha |  * @alpha | ||||||
|  | @ -193,7 +196,6 @@ export const StatusHistoryPanel: React.FC<TimelinePanelProps> = ({ | ||||||
|       height={height} |       height={height} | ||||||
|       legendItems={legendItems} |       legendItems={legendItems} | ||||||
|       {...options} |       {...options} | ||||||
|       // hardcoded
 |  | ||||||
|       mode={TimelineMode.Samples} |       mode={TimelineMode.Samples} | ||||||
|     > |     > | ||||||
|       {(config, alignedFrame) => { |       {(config, alignedFrame) => { | ||||||
|  |  | ||||||
|  | @ -3,10 +3,10 @@ import { VisibilityMode } from '@grafana/schema'; | ||||||
| import { commonOptionsBuilder } from '@grafana/ui'; | import { commonOptionsBuilder } from '@grafana/ui'; | ||||||
| 
 | 
 | ||||||
| import { StatusHistoryPanel } from './StatusHistoryPanel'; | import { StatusHistoryPanel } from './StatusHistoryPanel'; | ||||||
|  | import { PanelOptions, PanelFieldConfig, defaultPanelFieldConfig } from './panelcfg.gen'; | ||||||
| import { StatusHistorySuggestionsSupplier } from './suggestions'; | import { StatusHistorySuggestionsSupplier } from './suggestions'; | ||||||
| import { StatusPanelOptions, StatusFieldConfig, defaultStatusFieldConfig } from './types'; |  | ||||||
| 
 | 
 | ||||||
| export const plugin = new PanelPlugin<StatusPanelOptions, StatusFieldConfig>(StatusHistoryPanel) | export const plugin = new PanelPlugin<PanelOptions, PanelFieldConfig>(StatusHistoryPanel) | ||||||
|   .useFieldConfig({ |   .useFieldConfig({ | ||||||
|     standardOptions: { |     standardOptions: { | ||||||
|       [FieldConfigProperty.Color]: { |       [FieldConfigProperty.Color]: { | ||||||
|  | @ -23,7 +23,7 @@ export const plugin = new PanelPlugin<StatusPanelOptions, StatusFieldConfig>(Sta | ||||||
|         .addSliderInput({ |         .addSliderInput({ | ||||||
|           path: 'lineWidth', |           path: 'lineWidth', | ||||||
|           name: 'Line width', |           name: 'Line width', | ||||||
|           defaultValue: defaultStatusFieldConfig.lineWidth, |           defaultValue: defaultPanelFieldConfig.lineWidth, | ||||||
|           settings: { |           settings: { | ||||||
|             min: 0, |             min: 0, | ||||||
|             max: 10, |             max: 10, | ||||||
|  | @ -33,7 +33,7 @@ export const plugin = new PanelPlugin<StatusPanelOptions, StatusFieldConfig>(Sta | ||||||
|         .addSliderInput({ |         .addSliderInput({ | ||||||
|           path: 'fillOpacity', |           path: 'fillOpacity', | ||||||
|           name: 'Fill opacity', |           name: 'Fill opacity', | ||||||
|           defaultValue: defaultStatusFieldConfig.fillOpacity, |           defaultValue: defaultPanelFieldConfig.fillOpacity, | ||||||
|           settings: { |           settings: { | ||||||
|             min: 0, |             min: 0, | ||||||
|             max: 100, |             max: 100, | ||||||
|  | @ -56,16 +56,6 @@ export const plugin = new PanelPlugin<StatusPanelOptions, StatusFieldConfig>(Sta | ||||||
|         }, |         }, | ||||||
|         defaultValue: VisibilityMode.Auto, |         defaultValue: VisibilityMode.Auto, | ||||||
|       }) |       }) | ||||||
|       .addSliderInput({ |  | ||||||
|         path: 'rowHeight', |  | ||||||
|         name: 'Row height', |  | ||||||
|         defaultValue: 0.9, |  | ||||||
|         settings: { |  | ||||||
|           min: 0, |  | ||||||
|           max: 1, |  | ||||||
|           step: 0.01, |  | ||||||
|         }, |  | ||||||
|       }) |  | ||||||
|       .addSliderInput({ |       .addSliderInput({ | ||||||
|         path: 'colWidth', |         path: 'colWidth', | ||||||
|         name: 'Column width', |         name: 'Column width', | ||||||
|  |  | ||||||
|  | @ -15,28 +15,30 @@ | ||||||
| package grafanaplugin | package grafanaplugin | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"github.com/grafana/grafana/packages/grafana-schema/src/common" | 	ui "github.com/grafana/grafana/packages/grafana-schema/src/common" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| composableKinds: PanelCfg: { | composableKinds: PanelCfg: { | ||||||
|  | 	maturity: "experimental" | ||||||
| 	lineage: { | 	lineage: { | ||||||
| 		seqs: [ | 		seqs: [ | ||||||
| 			{ | 			{ | ||||||
| 				schemas: [ | 				schemas: [ | ||||||
| 					{ | 					{ | ||||||
| 						PanelOptions: { | 						PanelOptions: { | ||||||
| 							common.OptionsWithLegend | 							ui.OptionsWithLegend | ||||||
| 							common.OptionsWithTooltip | 							ui.OptionsWithTooltip | ||||||
| 							common.OptionsWithTimezones | 							ui.OptionsWithTimezones | ||||||
| 							showValue:  common.VisibilityMode | 
 | ||||||
| 							rowHeight:  number | 							//Show values on the columns | ||||||
| 							colWidth?:  number | 							showValue: ui.VisibilityMode | *"auto" | ||||||
| 							alignValue: "center" | *"left" | "right" | 							//Controls the column width | ||||||
|  | 							colWidth?: float & <=1 | *0.9 | ||||||
| 						} @cuetsy(kind="interface") | 						} @cuetsy(kind="interface") | ||||||
| 						PanelFieldConfig: { | 						PanelFieldConfig: { | ||||||
| 							common.HideableFieldConfig | 							ui.HideableFieldConfig | ||||||
| 							lineWidth?:   number | *1 | 							lineWidth?:   uint32 & <=10 | *1 | ||||||
| 							fillOpacity?: number | *70 | 							fillOpacity?: uint32 & <=100 | *70 | ||||||
| 						} @cuetsy(kind="interface") | 						} @cuetsy(kind="interface") | ||||||
| 					}, | 					}, | ||||||
| 				] | 				] | ||||||
|  |  | ||||||
|  | @ -0,0 +1,39 @@ | ||||||
|  | // Code generated - EDITING IS FUTILE. DO NOT EDIT.
 | ||||||
|  | //
 | ||||||
|  | // Generated by:
 | ||||||
|  | //     public/app/plugins/gen.go
 | ||||||
|  | // Using jennies:
 | ||||||
|  | //     TSTypesJenny
 | ||||||
|  | //     PluginTSTypesJenny
 | ||||||
|  | //
 | ||||||
|  | // Run 'make gen-cue' from repository root to regenerate.
 | ||||||
|  | 
 | ||||||
|  | import * as ui from '@grafana/schema'; | ||||||
|  | 
 | ||||||
|  | export const PanelCfgModelVersion = Object.freeze([0, 0]); | ||||||
|  | 
 | ||||||
|  | export interface PanelOptions extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones { | ||||||
|  |   /** | ||||||
|  |    * Controls the column width | ||||||
|  |    */ | ||||||
|  |   colWidth?: number; | ||||||
|  |   /** | ||||||
|  |    * Show values on the columns | ||||||
|  |    */ | ||||||
|  |   showValue: ui.VisibilityMode; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const defaultPanelOptions: Partial<PanelOptions> = { | ||||||
|  |   colWidth: 0.9, | ||||||
|  |   showValue: ui.VisibilityMode.Auto, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export interface PanelFieldConfig extends ui.HideableFieldConfig { | ||||||
|  |   fillOpacity?: number; | ||||||
|  |   lineWidth?: number; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const defaultPanelFieldConfig: Partial<PanelFieldConfig> = { | ||||||
|  |   fillOpacity: 70, | ||||||
|  |   lineWidth: 1, | ||||||
|  | }; | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { FieldColorModeId, VisualizationSuggestionsBuilder } from '@grafana/data'; | import { FieldColorModeId, VisualizationSuggestionsBuilder } from '@grafana/data'; | ||||||
| import { SuggestionName } from 'app/types/suggestions'; | import { SuggestionName } from 'app/types/suggestions'; | ||||||
| 
 | 
 | ||||||
| import { StatusPanelOptions, StatusFieldConfig } from './types'; | import { PanelOptions, PanelFieldConfig } from './panelcfg.gen'; | ||||||
| 
 | 
 | ||||||
| export class StatusHistorySuggestionsSupplier { | export class StatusHistorySuggestionsSupplier { | ||||||
|   getSuggestionsForData(builder: VisualizationSuggestionsBuilder) { |   getSuggestionsForData(builder: VisualizationSuggestionsBuilder) { | ||||||
|  | @ -31,7 +31,7 @@ export class StatusHistorySuggestionsSupplier { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const list = builder.getListAppender<StatusPanelOptions, StatusFieldConfig>({ |     const list = builder.getListAppender<PanelOptions, PanelFieldConfig>({ | ||||||
|       name: '', |       name: '', | ||||||
|       pluginId: 'status-history', |       pluginId: 'status-history', | ||||||
|       options: {}, |       options: {}, | ||||||
|  |  | ||||||
|  | @ -1,32 +0,0 @@ | ||||||
| import { |  | ||||||
|   HideableFieldConfig, |  | ||||||
|   VisibilityMode, |  | ||||||
|   OptionsWithTooltip, |  | ||||||
|   OptionsWithLegend, |  | ||||||
|   OptionsWithTimezones, |  | ||||||
| } from '@grafana/schema'; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @alpha |  | ||||||
|  */ |  | ||||||
| export interface StatusPanelOptions extends OptionsWithTooltip, OptionsWithLegend, OptionsWithTimezones { |  | ||||||
|   showValue: VisibilityMode; |  | ||||||
|   rowHeight: number; |  | ||||||
|   colWidth?: number; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @alpha |  | ||||||
|  */ |  | ||||||
| export interface StatusFieldConfig extends HideableFieldConfig { |  | ||||||
|   lineWidth?: number; // 0
 |  | ||||||
|   fillOpacity?: number; // 100
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @alpha |  | ||||||
|  */ |  | ||||||
| export const defaultStatusFieldConfig: StatusFieldConfig = { |  | ||||||
|   lineWidth: 1, |  | ||||||
|   fillOpacity: 70, |  | ||||||
| }; |  | ||||||
		Loading…
	
		Reference in New Issue