1import { ComponentType } from 'react';
2import { MatcherConfig, FieldConfig, Field, DataFrame, TimeZone } from '../types';
3import { InterpolateFunction } from './panel';
4import { StandardEditorProps, FieldConfigOptionsRegistry, StandardEditorContext } from '../field';
5import { OptionsEditorItem } from './OptionsUIRegistryBuilder';
6import { OptionEditorConfig } from './options';
7import { GrafanaTheme2 } from '../themes';
8
9export interface DynamicConfigValue {
10  id: string;
11  value?: any;
12}
13
14export interface ConfigOverrideRule {
15  matcher: MatcherConfig;
16  properties: DynamicConfigValue[];
17}
18
19/**
20 * Describes config override rules created when interacting with Grafana.
21 *
22 * @internal
23 */
24export interface SystemConfigOverrideRule extends ConfigOverrideRule {
25  __systemRef: string;
26}
27
28/**
29 * Guard functionality to check if an override rule is of type {@link SystemConfigOverrideRule}.
30 * It will only return true if the {@link SystemConfigOverrideRule} has the passed systemRef.
31 *
32 * @param ref system override reference
33 * @internal
34 */
35export function isSystemOverrideWithRef<T extends SystemConfigOverrideRule>(ref: string) {
36  return (override: ConfigOverrideRule): override is T => {
37    const overrideAs = override as T;
38    return overrideAs.__systemRef === ref;
39  };
40}
41
42/**
43 * Guard functionality to check if an override rule is of type {@link SystemConfigOverrideRule}.
44 * It will return true if the {@link SystemConfigOverrideRule} has any systemRef set.
45 *
46 * @internal
47 */
48export const isSystemOverride = (override: ConfigOverrideRule): override is SystemConfigOverrideRule => {
49  return typeof (override as SystemConfigOverrideRule)?.__systemRef === 'string';
50};
51
52export interface FieldConfigSource<TOptions = any> {
53  // Defaults applied to all numeric fields
54  defaults: FieldConfig<TOptions>;
55
56  // Rules to override individual values
57  overrides: ConfigOverrideRule[];
58}
59
60export interface FieldOverrideContext extends StandardEditorContext<any, any> {
61  field?: Field;
62  dataFrameIndex?: number; // The index for the selected field frame
63}
64export interface FieldConfigEditorProps<TValue, TSettings>
65  extends Omit<StandardEditorProps<TValue, TSettings>, 'item'> {
66  item: FieldConfigPropertyItem<any, TValue, TSettings>; // The property info
67  value: TValue;
68  context: FieldOverrideContext;
69  onChange: (value?: TValue) => void;
70}
71
72export interface FieldOverrideEditorProps<TValue, TSettings> extends Omit<StandardEditorProps<TValue>, 'item'> {
73  item: FieldConfigPropertyItem<TValue, TSettings>;
74  context: FieldOverrideContext;
75}
76
77export interface FieldConfigEditorConfig<TOptions, TSettings = any, TValue = any>
78  extends OptionEditorConfig<TOptions, TSettings, TValue> {
79  /**
80   * Function that allows specifying whether or not this field config should apply to a given field.
81   * @param field
82   */
83  shouldApply?: (field: Field) => boolean;
84
85  /** Indicates that option shoukd not be available in the Field config tab */
86  hideFromDefaults?: boolean;
87
88  /** Indicates that option should not be available for the overrides */
89  hideFromOverrides?: boolean;
90}
91
92export interface FieldConfigPropertyItem<TOptions = any, TValue = any, TSettings extends {} = any>
93  extends OptionsEditorItem<TOptions, TSettings, FieldConfigEditorProps<TValue, TSettings>, TValue> {
94  // An editor that can be filled in with context info (template variables etc)
95  override: ComponentType<FieldOverrideEditorProps<TValue, TSettings>>;
96
97  /** true for plugin field config properties */
98  isCustom?: boolean;
99
100  /** Hides option from the Field config tab */
101  hideFromDefaults?: boolean;
102
103  /** Indicates that option should not be available for the overrides */
104  hideFromOverrides?: boolean;
105
106  /** Convert the override value to a well typed value */
107  process: (value: any, context: FieldOverrideContext, settings?: TSettings) => TValue | undefined | null;
108
109  /** Checks if field should be processed */
110  shouldApply: (field: Field) => boolean;
111}
112
113export interface ApplyFieldOverrideOptions {
114  data?: DataFrame[];
115  fieldConfig: FieldConfigSource;
116  fieldConfigRegistry?: FieldConfigOptionsRegistry;
117  replaceVariables: InterpolateFunction;
118  theme: GrafanaTheme2;
119  timeZone?: TimeZone;
120}
121
122export enum FieldConfigProperty {
123  Unit = 'unit',
124  Min = 'min',
125  Max = 'max',
126  Decimals = 'decimals',
127  DisplayName = 'displayName',
128  NoValue = 'noValue',
129  Thresholds = 'thresholds',
130  Mappings = 'mappings',
131  Links = 'links',
132  Color = 'color',
133}
134