diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 234789dfa4c..0ccf1ab5333 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -558,6 +558,7 @@ i18next.config.ts @grafana/grafana-frontend-platform /packages/grafana-data/src/transformations/ @grafana/datapro /packages/grafana-data/src/types/ @grafana/grafana-frontend-platform /packages/grafana-data/src/types/scopes.ts @grafana/grafana-operator-experience-squad +/packages/grafana-data/src/types/suggestions.ts @grafana/dataviz-squad /packages/grafana-data/src/utils/__snapshots__/ @grafanabot /packages/grafana-data/src/utils/anyToNumber.ts @grafana/grafana-frontend-platform /packages/grafana-data/src/utils/arrayUtils* @grafana/grafana-frontend-platform @@ -942,6 +943,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform /public/app/features/notifications/ @grafana/grafana-search-navigate-organise /public/app/features/org/ @grafana/grafana-search-navigate-organise /public/app/features/panel/ @grafana/dashboards-squad +/public/app/features/panel/suggestions/ @grafana/dataviz-squad /public/app/features/playlist/ @grafana/dashboards-squad /public/app/features/plugins/ @grafana/plugins-platform-frontend /public/app/features/profile/ @grafana/grafana-frontend-platform diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 57b56b49744..bcb6d105d35 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -237,7 +237,7 @@ }, "packages/grafana-data/src/types/panel.ts": { "@typescript-eslint/no-explicit-any": { - "count": 13 + "count": 11 } }, "packages/grafana-data/src/types/plugin.ts": { diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index a3ef43c91e8..06b7f19444e 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -651,12 +651,7 @@ export { type PanelMenuItem, type AngularPanelMenuItem, type PanelPluginDataSupport, - type VisualizationSuggestion, - type VisualizationSuggestionsSupplier, VizOrientation, - VisualizationSuggestionScore, - VisualizationSuggestionsBuilder, - VisualizationSuggestionsListAppender, } from './types/panel'; export { type DataSourcePluginOptionsEditorProps, @@ -717,6 +712,13 @@ export { type ApplyFieldOverrideOptions, FieldConfigProperty, } from './types/fieldOverrides'; +export { + type VisualizationSuggestion, + type VisualizationSuggestionsSupplier, + VisualizationSuggestionScore, + VisualizationSuggestionsBuilder, + VisualizationSuggestionsListAppender, +} from './types/suggestions'; export { type MatcherConfig, type DataTransformContext, diff --git a/packages/grafana-data/src/panel/PanelPlugin.ts b/packages/grafana-data/src/panel/PanelPlugin.ts index 4822d4c6acb..e9119a37b52 100644 --- a/packages/grafana-data/src/panel/PanelPlugin.ts +++ b/packages/grafana-data/src/panel/PanelPlugin.ts @@ -7,7 +7,6 @@ import { PanelModel } from '../types/dashboard'; import { FieldConfigProperty, FieldConfigSource } from '../types/fieldOverrides'; import { PanelPluginMeta, - VisualizationSuggestionsSupplier, PanelProps, PanelEditorProps, PanelMigrationHandler, @@ -15,6 +14,7 @@ import { PanelPluginDataSupport, } from '../types/panel'; import { GrafanaPlugin } from '../types/plugin'; +import { VisualizationSuggestionsSupplier } from '../types/suggestions'; import { FieldConfigEditorBuilder, PanelOptionsEditorBuilder } from '../utils/OptionsUIBuilders'; import { deprecationWarning } from '../utils/deprecationWarning'; diff --git a/packages/grafana-data/src/types/panel.ts b/packages/grafana-data/src/types/panel.ts index 426c52abadf..2664d0bec72 100644 --- a/packages/grafana-data/src/types/panel.ts +++ b/packages/grafana-data/src/types/panel.ts @@ -1,8 +1,5 @@ -import { defaultsDeep } from 'lodash'; - import { EventBus } from '../events/types'; import { StandardEditorProps } from '../field/standardFieldConfigEditorRegistry'; -import { PanelDataSummary, getPanelDataSummary } from '../panel/suggestions/getPanelDataSummary'; import { Registry } from '../utils/Registry'; import { OptionsEditorItem } from './OptionsUIRegistryBuilder'; @@ -17,7 +14,6 @@ import { IconName } from './icon'; import { OptionEditorConfig } from './options'; import { PluginMeta } from './plugin'; import { AbsoluteTimeRange, TimeRange, TimeZone } from './time'; -import { DataTransformerConfig } from './transformations'; export type InterpolateFunction = (value: string, scopedVars?: ScopedVars, format?: string | Function) => string; @@ -219,95 +215,3 @@ export interface PanelPluginDataSupport { annotations: boolean; alertStates: boolean; } - -/** - * @alpha - */ -export interface VisualizationSuggestion { - /** Name of suggestion */ - name: string; - /** Description */ - description?: string; - /** Panel plugin id */ - pluginId: string; - /** Panel plugin options */ - options?: Partial; - /** Panel plugin field options */ - fieldConfig?: FieldConfigSource>; - /** Data transformations */ - transformations?: DataTransformerConfig[]; - /** Options for how to render suggestion card */ - cardOptions?: { - /** Tweak for small preview */ - previewModifier?: (suggestion: VisualizationSuggestion) => void; - icon?: string; - imgSrc?: string; - }; - /** A value between 0-100 how suitable suggestion is */ - score?: VisualizationSuggestionScore; -} - -/** - * @alpha - */ -export enum VisualizationSuggestionScore { - /** We are pretty sure this is the best possible option */ - Best = 100, - /** Should be a really good option */ - Good = 70, - /** Can be visualized but there are likely better options. If no score is set this score is assumed */ - OK = 50, -} - -/** - * @alpha - */ -export class VisualizationSuggestionsBuilder { - /** Current data */ - data?: PanelData; - /** Current panel & options */ - panel?: PanelModel; - /** Summary stats for current data */ - dataSummary: PanelDataSummary; - - private list: VisualizationSuggestion[] = []; - - constructor(data?: PanelData, panel?: PanelModel) { - this.data = data; - this.panel = panel; - this.dataSummary = getPanelDataSummary(this.data?.series); - } - - getListAppender(defaults: VisualizationSuggestion) { - return new VisualizationSuggestionsListAppender(this.list, defaults); - } - - getList() { - return this.list; - } -} - -/** - * @alpha - */ -export type VisualizationSuggestionsSupplier = { - /** - * Adds good suitable suggestions for the current data - */ - getSuggestionsForData: (builder: VisualizationSuggestionsBuilder) => void; -}; - -/** - * Helps with typings and defaults - * @alpha - */ -export class VisualizationSuggestionsListAppender { - constructor( - private list: VisualizationSuggestion[], - private defaults: VisualizationSuggestion - ) {} - - append(overrides: Partial>) { - this.list.push(defaultsDeep(overrides, this.defaults)); - } -} diff --git a/packages/grafana-data/src/types/suggestions.ts b/packages/grafana-data/src/types/suggestions.ts new file mode 100644 index 00000000000..a7b2611a990 --- /dev/null +++ b/packages/grafana-data/src/types/suggestions.ts @@ -0,0 +1,100 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { defaultsDeep } from 'lodash'; + +import { DataTransformerConfig } from '@grafana/schema'; + +import { PanelDataSummary, getPanelDataSummary } from '../panel/suggestions/getPanelDataSummary'; + +import { PanelModel } from './dashboard'; +import { FieldConfigSource } from './fieldOverrides'; +import { PanelData } from './panel'; + +/** + * @alpha + */ +export interface VisualizationSuggestion { + /** Name of suggestion */ + name: string; + /** Description */ + description?: string; + /** Panel plugin id */ + pluginId: string; + /** Panel plugin options */ + options?: Partial; + /** Panel plugin field options */ + fieldConfig?: FieldConfigSource>; + /** Data transformations */ + transformations?: DataTransformerConfig[]; + /** Options for how to render suggestion card */ + cardOptions?: { + /** Tweak for small preview */ + previewModifier?: (suggestion: VisualizationSuggestion) => void; + icon?: string; + imgSrc?: string; + }; + /** A value between 0-100 how suitable suggestion is */ + score?: VisualizationSuggestionScore; +} + +/** + * @alpha + */ +export enum VisualizationSuggestionScore { + /** We are pretty sure this is the best possible option */ + Best = 100, + /** Should be a really good option */ + Good = 70, + /** Can be visualized but there are likely better options. If no score is set this score is assumed */ + OK = 50, +} + +/** + * @alpha + */ +export class VisualizationSuggestionsBuilder { + /** Summary stats for current data */ + dataSummary: PanelDataSummary; + private list: VisualizationSuggestion[] = []; + + constructor( + /** Current data */ + public data?: PanelData, + /** Current panel & options */ + public panel?: PanelModel + ) { + this.dataSummary = getPanelDataSummary(data?.series); + } + + getListAppender(defaults: VisualizationSuggestion) { + return new VisualizationSuggestionsListAppender(this.list, defaults); + } + + getList() { + return this.list; + } +} + +/** + * @alpha + */ +export type VisualizationSuggestionsSupplier = { + /** + * Adds good suitable suggestions for the current data + */ + getSuggestionsForData: (builder: VisualizationSuggestionsBuilder) => void; +}; + +/** + * Helps with typings and defaults + * @alpha + */ +export class VisualizationSuggestionsListAppender { + constructor( + private list: VisualizationSuggestion[], + private defaults: VisualizationSuggestion + ) {} + + append(overrides: Partial>) { + this.list.push(defaultsDeep(overrides, this.defaults)); + } +} diff --git a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx index 98e6fd7f980..d78b56f89a5 100644 --- a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx +++ b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx @@ -7,7 +7,7 @@ import { GrafanaTheme2, PanelData, PanelModel, VisualizationSuggestion } from '@ import { Trans } from '@grafana/i18n'; import { useStyles2 } from '@grafana/ui'; -import { getAllSuggestions } from '../../state/getAllSuggestions'; +import { getAllSuggestions } from '../../suggestions/getAllSuggestions'; import { VisualizationSuggestionCard } from './VisualizationSuggestionCard'; import { VizTypeChangeDetails } from './types'; diff --git a/public/app/features/panel/state/getAllSuggestions.test.ts b/public/app/features/panel/suggestions/getAllSuggestions.test.ts similarity index 98% rename from public/app/features/panel/state/getAllSuggestions.test.ts rename to public/app/features/panel/suggestions/getAllSuggestions.test.ts index 0ce616f9309..e0b194e1901 100644 --- a/public/app/features/panel/state/getAllSuggestions.test.ts +++ b/public/app/features/panel/suggestions/getAllSuggestions.test.ts @@ -8,6 +8,7 @@ import { toDataFrame, VisualizationSuggestion, } from '@grafana/data'; +import { GraphFieldConfig, ReduceDataOptions } from '@grafana/schema'; import { config } from 'app/core/config'; import { SuggestionName } from 'app/types/suggestions'; @@ -32,7 +33,7 @@ config.panels['text'] = { class ScenarioContext { data: DataFrame[] = []; - suggestions: VisualizationSuggestion[] = []; + suggestions: Array> = []; setData(scenarioData: DataFrame[]) { this.data = scenarioData; diff --git a/public/app/features/panel/state/getAllSuggestions.ts b/public/app/features/panel/suggestions/getAllSuggestions.ts similarity index 100% rename from public/app/features/panel/state/getAllSuggestions.ts rename to public/app/features/panel/suggestions/getAllSuggestions.ts diff --git a/public/app/plugins/panel/bargauge/suggestions.ts b/public/app/plugins/panel/bargauge/suggestions.ts index 9acbad2451b..61d48ce104a 100644 --- a/public/app/plugins/panel/bargauge/suggestions.ts +++ b/public/app/plugins/panel/bargauge/suggestions.ts @@ -1,4 +1,4 @@ -import { VisualizationSuggestionsBuilder, VizOrientation } from '@grafana/data'; +import { FieldColorModeId, VisualizationSuggestionsBuilder, VizOrientation } from '@grafana/data'; import { BarGaugeDisplayMode } from '@grafana/ui'; import { SuggestionName } from 'app/types/suggestions'; @@ -44,7 +44,7 @@ export class BarGaugeSuggestionsSupplier { fieldConfig: { defaults: { color: { - mode: 'continuous-GrYlRd', + mode: FieldColorModeId.ContinuousGrYlRd, }, }, overrides: [], @@ -64,7 +64,7 @@ export class BarGaugeSuggestionsSupplier { fieldConfig: { defaults: { color: { - mode: 'continuous-GrYlRd', + mode: FieldColorModeId.ContinuousGrYlRd, }, }, overrides: [], @@ -84,7 +84,7 @@ export class BarGaugeSuggestionsSupplier { fieldConfig: { defaults: { color: { - mode: 'continuous-GrYlRd', + mode: FieldColorModeId.ContinuousGrYlRd, }, }, overrides: [], @@ -104,7 +104,7 @@ export class BarGaugeSuggestionsSupplier { fieldConfig: { defaults: { color: { - mode: 'continuous-GrYlRd', + mode: FieldColorModeId.ContinuousGrYlRd, }, }, overrides: [], diff --git a/public/app/plugins/panel/gauge/suggestions.ts b/public/app/plugins/panel/gauge/suggestions.ts index dd1d4ad0c82..5f5ebc8f40e 100644 --- a/public/app/plugins/panel/gauge/suggestions.ts +++ b/public/app/plugins/panel/gauge/suggestions.ts @@ -1,4 +1,5 @@ import { ThresholdsMode, VisualizationSuggestionsBuilder } from '@grafana/data'; +import { GraphFieldConfig } from '@grafana/ui'; import { SuggestionName } from 'app/types/suggestions'; import { Options } from './panelcfg.gen'; @@ -16,7 +17,7 @@ export class GaugeSuggestionsSupplier { return; } - const list = builder.getListAppender({ + const list = builder.getListAppender({ name: SuggestionName.Gauge, pluginId: 'gauge', options: {}, @@ -36,8 +37,8 @@ export class GaugeSuggestionsSupplier { }, cardOptions: { previewModifier: (s) => { - if (s.options!.reduceOptions.values) { - s.options!.reduceOptions.limit = 2; + if (s.options?.reduceOptions?.values) { + s.options.reduceOptions.limit = 2; } }, }, diff --git a/public/app/plugins/panel/radialbar/suggestions.ts b/public/app/plugins/panel/radialbar/suggestions.ts index 468451be9f6..8471dc27cbe 100644 --- a/public/app/plugins/panel/radialbar/suggestions.ts +++ b/public/app/plugins/panel/radialbar/suggestions.ts @@ -1,5 +1,6 @@ import { VisualizationSuggestionsBuilder } from '@grafana/data'; -import { FieldColorModeId } from '@grafana/schema/dist/esm/index.gen'; +import { FieldColorModeId } from '@grafana/schema'; +import { GraphFieldConfig } from '@grafana/ui'; import { SuggestionName } from 'app/types/suggestions'; import { Options } from './panelcfg.gen'; @@ -17,7 +18,7 @@ export class GaugeSuggestionsSupplier { return; } - const list = builder.getListAppender({ + const list = builder.getListAppender({ name: SuggestionName.Gauge, pluginId: 'gauge', options: {}, @@ -27,8 +28,8 @@ export class GaugeSuggestionsSupplier { }, cardOptions: { previewModifier: (s) => { - if (s.options!.reduceOptions.values) { - s.options!.reduceOptions.limit = 2; + if (s.options?.reduceOptions?.values) { + s.options.reduceOptions.limit = 2; } }, }, diff --git a/public/app/plugins/panel/stat/suggestions.ts b/public/app/plugins/panel/stat/suggestions.ts index c07fa1d1b07..00af3220135 100644 --- a/public/app/plugins/panel/stat/suggestions.ts +++ b/public/app/plugins/panel/stat/suggestions.ts @@ -1,5 +1,5 @@ import { VisualizationSuggestionsBuilder } from '@grafana/data'; -import { BigValueColorMode, BigValueGraphMode } from '@grafana/schema'; +import { BigValueColorMode, BigValueGraphMode, GraphFieldConfig } from '@grafana/schema'; import { SuggestionName } from 'app/types/suggestions'; import { Options } from './panelcfg.gen'; @@ -12,7 +12,7 @@ export class StatSuggestionsSupplier { return; } - const list = builder.getListAppender({ + const list = builder.getListAppender({ name: SuggestionName.Stat, pluginId: 'stat', options: {}, @@ -25,8 +25,8 @@ export class StatSuggestionsSupplier { }, cardOptions: { previewModifier: (s) => { - if (s.options!.reduceOptions.values) { - s.options!.reduceOptions.limit = 1; + if (s.options?.reduceOptions?.values) { + s.options.reduceOptions.limit = 1; } }, },