1import {
2  SingleStatBaseOptions,
3  BigValueColorMode,
4  BigValueGraphMode,
5  BigValueJustifyMode,
6  BigValueTextMode,
7} from '@grafana/ui';
8import {
9  ReducerID,
10  standardEditorsRegistry,
11  FieldOverrideContext,
12  getFieldDisplayName,
13  escapeStringForRegex,
14  VizOrientation,
15  PanelOptionsEditorBuilder,
16} from '@grafana/data';
17
18// Structure copied from angular
19export interface StatPanelOptions extends SingleStatBaseOptions {
20  graphMode: BigValueGraphMode;
21  colorMode: BigValueColorMode;
22  justifyMode: BigValueJustifyMode;
23  textMode: BigValueTextMode;
24}
25
26export function addStandardDataReduceOptions<T extends SingleStatBaseOptions>(
27  builder: PanelOptionsEditorBuilder<T>,
28  includeFieldMatcher = true
29) {
30  const valueOptionsCategory = ['Value options'];
31
32  builder.addRadio({
33    path: 'reduceOptions.values',
34    name: 'Show',
35    description: 'Calculate a single value per column or series or show each row',
36    settings: {
37      options: [
38        { value: false, label: 'Calculate' },
39        { value: true, label: 'All values' },
40      ],
41    },
42    category: valueOptionsCategory,
43    defaultValue: false,
44  });
45
46  builder.addNumberInput({
47    path: 'reduceOptions.limit',
48    name: 'Limit',
49    description: 'Max number of rows to display',
50    category: valueOptionsCategory,
51    settings: {
52      placeholder: '25',
53      integer: true,
54      min: 1,
55      max: 5000,
56    },
57    showIf: (options) => options.reduceOptions.values === true,
58  });
59
60  builder.addCustomEditor({
61    id: 'reduceOptions.calcs',
62    path: 'reduceOptions.calcs',
63    name: 'Calculation',
64    description: 'Choose a reducer function / calculation',
65    category: valueOptionsCategory,
66    editor: standardEditorsRegistry.get('stats-picker').editor as any,
67    defaultValue: [ReducerID.lastNotNull],
68    // Hides it when all values mode is on
69    showIf: (currentConfig) => currentConfig.reduceOptions.values === false,
70  });
71
72  if (includeFieldMatcher) {
73    builder.addSelect({
74      path: 'reduceOptions.fields',
75      name: 'Fields',
76      description: 'Select the fields that should be included in the panel',
77      category: valueOptionsCategory,
78      settings: {
79        allowCustomValue: true,
80        options: [],
81        getOptions: async (context: FieldOverrideContext) => {
82          const options = [
83            { value: '', label: 'Numeric Fields' },
84            { value: '/.*/', label: 'All Fields' },
85          ];
86          if (context && context.data) {
87            for (const frame of context.data) {
88              for (const field of frame.fields) {
89                const name = getFieldDisplayName(field, frame, context.data);
90                const value = `/^${escapeStringForRegex(name)}$/`;
91                options.push({ value, label: name });
92              }
93            }
94          }
95          return Promise.resolve(options);
96        },
97      },
98      defaultValue: '',
99    });
100  }
101}
102
103export function addOrientationOption<T extends SingleStatBaseOptions>(
104  builder: PanelOptionsEditorBuilder<T>,
105  category?: string[]
106) {
107  builder.addRadio({
108    path: 'orientation',
109    name: 'Orientation',
110    description: 'Layout orientation',
111    category,
112    settings: {
113      options: [
114        { value: VizOrientation.Auto, label: 'Auto' },
115        { value: VizOrientation.Horizontal, label: 'Horizontal' },
116        { value: VizOrientation.Vertical, label: 'Vertical' },
117      ],
118    },
119    defaultValue: VizOrientation.Auto,
120  });
121}
122