Migrate table to cue model (#61852)

* WIP table cue model

* WIP table types migration

* refactor

* WIP table cue

* docs

* veneer fix, docs

* docs
This commit is contained in:
Victor Marin 2023-03-01 17:48:36 +02:00 committed by GitHub
parent e1bc3fad83
commit a91e0a49c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 216 additions and 72 deletions

View File

@ -0,0 +1,47 @@
---
keywords:
- grafana
- schema
title: TablePanelCfg kind
---
> Both documentation generation and kinds schemas are in active development and subject to change without prior notice.
## TablePanelCfg
#### Maturity: [experimental](../../../maturity/#experimental)
#### Version: 0.0
| Property | Type | Required | Description |
|----------------|-------------------------|----------|-------------|
| `PanelOptions` | [object](#paneloptions) | **Yes** | |
### PanelOptions
| Property | Type | Required | Description |
|-----------------|---------------------------------------------------|----------|--------------------------------------------------------------------------------------|
| `frameIndex` | number | **Yes** | Represents the index of the selected frame Default: `0`. |
| `showHeader` | boolean | **Yes** | Controls whether the panel should show the header Default: `true`. |
| `footer` | [object](#footer) | No | Controls footer options Default: `map[countRows:false reducer:[] show:false]`. |
| `showRowNums` | boolean | No | Controls whether the columns should be numbered Default: `false`. |
| `showTypeIcons` | boolean | No | Controls whether the header should show icons for the column types Default: `false`. |
| `sortBy` | [TableSortByFieldState](#tablesortbyfieldstate)[] | No | Used to control row sorting |
### TableSortByFieldState
Sort by field state
| Property | Type | Required | Description |
|---------------|---------|----------|-----------------------------------------------|
| `displayName` | string | **Yes** | Sets the display name of the field to sort by |
| `desc` | boolean | No | Flag used to indicate descending sort order |
### Footer
Controls footer options
| Property | Type | Required | Description |
|----------|------|----------|-------------|

View File

@ -631,13 +631,35 @@ export enum TableCellBackgroundDisplayMode {
}
/**
* TODO docs
* Sort by field state
*/
export interface TableSortByFieldState {
/**
* Flag used to indicate descending sort order
*/
desc?: boolean;
/**
* Sets the display name of the field to sort by
*/
displayName: string;
}
/**
* Footer options
*/
export interface TableFooterOptions {
countRows?: boolean;
enablePagination?: boolean;
fields?: Array<string>;
reducer: Array<string>;
show: boolean;
}
export const defaultTableFooterOptions: Partial<TableFooterOptions> = {
fields: [],
reducer: [],
};
/**
* Auto mode table cell options
*/

View File

@ -11,12 +11,23 @@ TableCellDisplayMode: "auto" | "color-text" | "color-background" | "color-backgr
// or a gradient.
TableCellBackgroundDisplayMode: "basic" | "gradient" @cuetsy(kind="enum",memberNames="Basic|Gradient")
// TODO docs
// Sort by field state
TableSortByFieldState: {
// Sets the display name of the field to sort by
displayName: string
// Flag used to indicate descending sort order
desc?: bool
} @cuetsy(kind="interface")
// Footer options
TableFooterOptions: {
show: bool
reducer: [...string] // actually 1 value
fields?: [...string]
enablePagination?: bool
countRows?: bool
} @cuetsy(kind="interface")
// Auto mode table cell options
TableAutoCellOptions: {
type: TableCellDisplayMode & "auto"

View File

@ -23,3 +23,12 @@ export interface TextDimensionConfig extends BaseDimensionConfig<string>, Omit<r
export interface ColorDimensionConfig extends BaseDimensionConfig<string>, Omit<raw.ColorDimensionConfig, 'fixed'> {}
export * from '../common/common.gen';
// TODO remove when https://github.com/grafana/cuetsy/issues/74 is fixed
export const defaultTableFieldOptions: raw.TableFieldOptions = {
align: 'auto',
inspect: false,
cellOptions: {
type: raw.TableCellDisplayMode.Auto,
},
};

View File

@ -1598,6 +1598,30 @@
"pluralName": "TableOldPanelCfgs",
"schemaInterface": "PanelCfg"
},
"tablepanelcfg": {
"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/tablepanelcfg/schema-reference",
"go": "n/a",
"schema": "https://github.com/grafana/grafana/tree/main/public/app/plugins/panel/table/panelcfg.cue",
"ts": "https://github.com/grafana/grafana/tree/main/public/app/plugins/panel/table/panelcfg.gen.ts"
},
"machineName": "tablepanelcfg",
"maturity": "experimental",
"name": "TablePanelCfg",
"pluralMachineName": "tablepanelcfgs",
"pluralName": "TablePanelCfgs",
"schemaInterface": "PanelCfg"
},
"team": {
"category": "core",
"codeowners": [
@ -1972,6 +1996,7 @@
"statpanelcfg",
"statushistorypanelcfg",
"tableoldpanelcfg",
"tablepanelcfg",
"tempodataquery",
"tempodatasourcecfg",
"testdatadataquery",
@ -2031,12 +2056,13 @@
"statetimelinepanelcfg",
"statpanelcfg",
"statushistorypanelcfg",
"tablepanelcfg",
"tempodataquery",
"testdatadataquery",
"textpanelcfg",
"xychartpanelcfg"
],
"count": 25
"count": 26
},
"mature": {
"name": "mature",

View File

@ -74,6 +74,7 @@ func corePlugins(rt *thema.Runtime) []pfs.ParsedPlugin {
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", "table", rt),
parsePluginOrPanic("public/app/plugins/panel/table-old", "table_old", rt),
parsePluginOrPanic("public/app/plugins/panel/text", "text", rt),
parsePluginOrPanic("public/app/plugins/panel/traces", "traces", rt),

View File

@ -7,7 +7,7 @@ import { PanelRenderer } from '@grafana/runtime';
import { GraphFieldConfig, GraphTresholdsStyleMode } from '@grafana/schema';
import { PanelContext, PanelContextProvider, useStyles2 } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { PanelOptions } from 'app/plugins/panel/table/models.gen';
import { PanelOptions } from 'app/plugins/panel/table/panelcfg.gen';
import { useVizHeight } from '../../hooks/useVizHeight';
import { SupportedPanelPlugins, PanelPluginsButtonGroup } from '../PanelPluginsButtonGroup';

View File

@ -14,7 +14,7 @@ import {
import { config, getDataSourceSrv, PanelRenderer } from '@grafana/runtime';
import { Alert, CodeEditor, DateTimePicker, LinkButton, useStyles2, useTheme2 } from '@grafana/ui';
import { isExpressionQuery } from 'app/features/expressions/guards';
import { PanelOptions } from 'app/plugins/panel/table/models.gen';
import { PanelOptions } from 'app/plugins/panel/table/panelcfg.gen';
import { AccessControlAction } from 'app/types';
import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto';

View File

@ -4,7 +4,7 @@ import { RefreshEvent } from '@grafana/runtime';
import { PanelChrome } from '@grafana/ui';
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
import { PanelRenderer } from 'app/features/panel/components/PanelRenderer';
import { PanelOptions } from 'app/plugins/panel/table/models.gen';
import { PanelOptions } from 'app/plugins/panel/table/panelcfg.gen';
import PanelHeaderCorner from '../../dashgrid/PanelHeader/PanelHeaderCorner';
import { getTimeSrv } from '../../services/TimeSrv';

View File

@ -1,7 +1,7 @@
import { VizPanel, VizPanelState } from '@grafana/scenes';
import { GraphFieldConfig, TableFieldOptions } from '@grafana/schema';
import { PanelOptions as BarGaugePanelOptions } from 'app/plugins/panel/bargauge/panelcfg.gen';
import { PanelOptions as TablePanelOptions } from 'app/plugins/panel/table/models.gen';
import { PanelOptions as TablePanelOptions } from 'app/plugins/panel/table/panelcfg.gen';
import { TimeSeriesOptions } from 'app/plugins/panel/timeseries/types';
export type TypedVizPanelState<TOptions, TFieldConfig> = Omit<

View File

@ -24,7 +24,6 @@ import (
var skipPlugins = map[string]bool{
"canvas": true,
"candlestick": true,
"table": true,
"timeseries": true,
"influxdb": true, // plugin.json fails validation (defaultMatchFormat)
"mixed": true, // plugin.json fails validation (mixed)

View File

@ -7,7 +7,7 @@ import { Select, Table, usePanelContext, useTheme2 } from '@grafana/ui';
import { TableSortByFieldState } from '@grafana/ui/src/components/Table/types';
import { OPTIONAL_ROW_NUMBER_COLUMN_WIDTH } from '@grafana/ui/src/components/Table/utils';
import { PanelOptions } from './models.gen';
import { PanelOptions } from './panelcfg.gen';
interface Props extends PanelProps<PanelOptions> {}

View File

@ -10,7 +10,7 @@ import {
} from '@grafana/data';
import { ReduceTransformerOptions } from '@grafana/data/src/transformations/transformers/reduce';
import { PanelOptions } from './models.gen';
import { PanelOptions } from './panelcfg.gen';
/**
* At 7.0, the `table` panel was swapped from an angular implementation to a react one.

View File

@ -1,42 +0,0 @@
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE: This file will be auto generated from models.cue
// It is currenty hand written but will serve as the target for cuetsy
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import { TableCellDisplayMode, TableSortByFieldState, TableFooterCalc } from '@grafana/ui';
import { TableFieldOptions } from '@grafana/schema';
// Only the latest schema version is translated to TypeScript, on the premise
// that either the dashboard loading process, or (eventually) CUE-defined
// migrations ensure that bulk of the frontend application only ever
// need directly consider the most recent version of the schema.
export const modelVersion = Object.freeze([1, 0]);
export interface PanelOptions {
frameIndex: number;
showHeader: boolean;
showRowNums?: boolean;
showTypeIcons?: boolean;
sortBy?: TableSortByFieldState[];
footer?: TableFooterCalc; // TODO: should be array (options builder is limited)
}
export const defaultPanelOptions: PanelOptions = {
frameIndex: 0,
showHeader: true,
showRowNums: false,
showTypeIcons: false,
footer: {
show: false,
reducer: [],
countRows: false,
},
};
export const defaultPanelFieldConfig: TableFieldOptions = {
align: 'auto',
cellOptions: {
type: TableCellDisplayMode.Auto,
},
inspect: false,
};

View File

@ -7,13 +7,13 @@ import {
standardEditorsRegistry,
identityOverrideProcessor,
} from '@grafana/data';
import { TableFieldOptions, TableCellOptions, TableCellDisplayMode } from '@grafana/schema';
import { TableFieldOptions, TableCellOptions, TableCellDisplayMode, defaultTableFieldOptions } from '@grafana/schema';
import { PaginationEditor } from './PaginationEditor';
import { TableCellOptionEditor } from './TableCellOptionEditor';
import { TablePanel } from './TablePanel';
import { tableMigrationHandler, tablePanelChangedHandler } from './migrations';
import { PanelOptions, defaultPanelOptions, defaultPanelFieldConfig } from './models.gen';
import { PanelOptions, defaultPanelOptions } from './panelcfg.gen';
import { TableSuggestionsSupplier } from './suggestions';
const footerCategory = 'Table footer';
@ -35,7 +35,7 @@ export const plugin = new PanelPlugin<PanelOptions, TableFieldOptions>(TablePane
max: 500,
},
shouldApply: () => true,
defaultValue: defaultPanelFieldConfig.minWidth,
defaultValue: defaultTableFieldOptions.minWidth,
})
.addNumberInput({
path: 'width',
@ -46,7 +46,7 @@ export const plugin = new PanelPlugin<PanelOptions, TableFieldOptions>(TablePane
max: 300,
},
shouldApply: () => true,
defaultValue: defaultPanelFieldConfig.width,
defaultValue: defaultTableFieldOptions.width,
})
.addRadio({
path: 'align',
@ -59,7 +59,7 @@ export const plugin = new PanelPlugin<PanelOptions, TableFieldOptions>(TablePane
{ label: 'right', value: 'right' },
],
},
defaultValue: defaultPanelFieldConfig.align,
defaultValue: defaultTableFieldOptions.align,
})
.addCustomEditor<void, TableCellOptions>({
id: 'cellOptions',
@ -67,7 +67,7 @@ export const plugin = new PanelPlugin<PanelOptions, TableFieldOptions>(TablePane
name: 'Cell Type',
editor: TableCellOptionEditor,
override: TableCellOptionEditor,
defaultValue: defaultPanelFieldConfig.cellOptions,
defaultValue: defaultTableFieldOptions.cellOptions,
process: identityOverrideProcessor,
category: cellCategory,
shouldApply: () => true,
@ -91,7 +91,7 @@ export const plugin = new PanelPlugin<PanelOptions, TableFieldOptions>(TablePane
path: 'filterable',
name: 'Column filter',
description: 'Enables/disables field filters in table',
defaultValue: defaultPanelFieldConfig.filterable,
defaultValue: defaultTableFieldOptions.filterable,
})
.addBooleanSwitch({
path: 'hidden',

View File

@ -15,23 +15,37 @@
package grafanaplugin
import (
"github.com/grafana/grafana/packages/grafana-schema/src/common"
ui "github.com/grafana/grafana/packages/grafana-schema/src/common"
)
composableKinds: PanelCfg: {
maturity: "experimental"
lineage: {
seqs: [
{
schemas: [
{
PanelOptions: {
frameIndex: number | *0
showHeader: bool | *true
showTypeIcons: bool | *false
showRowNums?: bool | *false
sortBy?: [...common.TableSortByFieldState]
// Represents the index of the selected frame
frameIndex: number | *0
// Controls whether the panel should show the header
showHeader: bool | *true
// Controls whether the columns should be numbered
showRowNums?: bool | *false
// Controls whether the header should show icons for the column types
showTypeIcons?: bool | *false
// Used to control row sorting
sortBy?: [...ui.TableSortByFieldState]
// Controls footer options
footer?: ui.TableFooterOptions | *{
// Controls whether the footer should be shown
show: false
// Controls whether the footer should show the total number of rows on Count calculation
countRows: false
// Represents the selected calculations
reducer: []
}
} @cuetsy(kind="interface")
PanelFieldConfig: common.TableFieldOptions & {} @cuetsy(kind="interface")
},
]
},

View File

@ -0,0 +1,62 @@
// 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 {
/**
* Controls footer options
*/
footer?: ui.TableFooterOptions;
/**
* Represents the index of the selected frame
*/
frameIndex: number;
/**
* Controls whether the panel should show the header
*/
showHeader: boolean;
/**
* Controls whether the columns should be numbered
*/
showRowNums?: boolean;
/**
* Controls whether the header should show icons for the column types
*/
showTypeIcons?: boolean;
/**
* Used to control row sorting
*/
sortBy?: Array<ui.TableSortByFieldState>;
}
export const defaultPanelOptions: Partial<PanelOptions> = {
footer: {
/**
* Controls whether the footer should be shown
*/
show: false,
/**
* Controls whether the footer should show the total number of rows on Count calculation
*/
countRows: false,
/**
* Represents the selected calculations
*/
reducer: [],
},
frameIndex: 0,
showHeader: true,
showRowNums: false,
showTypeIcons: false,
sortBy: [],
};

View File

@ -3,11 +3,6 @@
"name": "Table",
"id": "table",
"models": {
"version": [1, 0],
"changed": "2021/03/30"
},
"info": {
"description": "Supports many column styles",
"author": {

View File

@ -2,7 +2,7 @@ import { VisualizationSuggestionsBuilder } from '@grafana/data';
import { TableFieldOptions } from '@grafana/schema';
import { SuggestionName } from 'app/types/suggestions';
import { PanelOptions } from './models.gen';
import { PanelOptions } from './panelcfg.gen';
export class TableSuggestionsSupplier {
getSuggestionsForData(builder: VisualizationSuggestionsBuilder) {