@oriolrius/grafana-business-text
Version:
Data-driven text with Markdown and Handlebars support for Grafana
245 lines (236 loc) • 7.9 kB
text/typescript
import { Field, FieldConfigProperty, FieldType, PanelPlugin } from '@grafana/data';
import {
AfterRenderWithUrlEditor,
ContentPartialsEditor,
HelpersWithUrlEditor,
ResourcesEditor,
StylesWithUrlEditor,
TextEditor,
TextPanel,
} from './components';
import {
CODE_LANGUAGE_OPTIONS,
DEFAULT_OPTIONS,
EDITORS_OPTIONS,
FORMAT_OPTIONS,
RENDER_MODE_OPTIONS,
WRAP_OPTIONS,
} from './constants';
import { getMigratedOptions } from './migration';
import { EditorType, PanelOptions } from './types';
/**
* Panel Plugin
*/
export const plugin = new PanelPlugin<PanelOptions>(TextPanel)
.setNoPadding()
.setMigrationHandler(getMigratedOptions)
.useFieldConfig({
disableStandardOptions: [
FieldConfigProperty.Color,
FieldConfigProperty.Min,
FieldConfigProperty.Max,
FieldConfigProperty.DisplayName,
FieldConfigProperty.NoValue,
FieldConfigProperty.Links,
FieldConfigProperty.Mappings,
'unitScale' as never,
'fieldMinMax' as never,
],
})
.setPanelOptions((builder) => {
builder
.addSelect({
path: 'renderMode',
name: 'Render template',
settings: {
options: RENDER_MODE_OPTIONS,
},
defaultValue: DEFAULT_OPTIONS.renderMode,
})
.addMultiSelect({
path: 'editors',
name: 'Select Editors to display. Editors with updated values always displayed.',
settings: {
options: EDITORS_OPTIONS as never,
},
defaultValue: DEFAULT_OPTIONS.editors,
})
.addFieldNamePicker({
path: 'status',
name: 'Field with status value. To be used to get statusColor based on thresholds.',
settings: {
filter: (f: Field) => f.type === FieldType.number,
noFieldsMessage: 'No number fields found',
},
});
/**
* Editor
*/
builder
.addRadio({
path: 'editor.language',
name: 'Primary Content Language',
description: 'Used for formatting and suggestions.',
settings: {
options: CODE_LANGUAGE_OPTIONS,
},
defaultValue: DEFAULT_OPTIONS.editor.language,
category: ['Editor'],
})
.addRadio({
path: 'editor.format',
name: 'Formatting',
settings: {
options: FORMAT_OPTIONS,
},
defaultValue: DEFAULT_OPTIONS.editor.format,
category: ['Editor'],
});
/**
* Content
*/
builder
.addRadio({
path: 'wrap',
name: 'Wrap automatically in paragraphs',
description: 'If disabled, result will NOT be wrapped into <p> tags.',
defaultValue: DEFAULT_OPTIONS.wrap,
settings: {
options: WRAP_OPTIONS,
},
category: ['Content'],
})
.addCustomEditor({
id: 'contentPartials',
path: 'contentPartials',
name: 'Content Partials',
description: 'Partial call syntax: {{> name }}',
defaultValue: DEFAULT_OPTIONS.contentPartials,
editor: ContentPartialsEditor,
category: ['Content'],
})
.addCustomEditor({
id: 'content',
path: 'content',
name: 'Content',
defaultValue: DEFAULT_OPTIONS.content,
editor: TextEditor,
category: ['Content'],
})
.addCustomEditor({
id: 'defaultContent',
path: 'defaultContent',
name: 'Default Content',
description: 'Displayed when query result is empty.',
defaultValue: DEFAULT_OPTIONS.defaultContent,
editor: TextEditor,
category: ['Content'],
showIf: (config) =>
config.editors.includes(EditorType.DEFAULT) || config.defaultContent !== DEFAULT_OPTIONS.defaultContent,
});
/**
* JavaScript
*/
builder
.addTextInput({
path: 'helpersRemoteUrl',
name: 'Remote URL',
description: 'URL to fetch JavaScript helpers code from.',
defaultValue: DEFAULT_OPTIONS.helpersRemoteUrl,
category: ['JavaScript'],
showIf: (config) => config.editors.includes(EditorType.HELPERS) || config.helpers !== DEFAULT_OPTIONS.helpers,
})
.addCustomEditor({
id: 'helpers',
path: 'helpers',
name: 'Before Content Rendering',
description: 'Allows to execute code before content rendering. E.g. add Handlebars Helpers.',
defaultValue: DEFAULT_OPTIONS.helpers,
editor: HelpersWithUrlEditor,
category: ['JavaScript'],
showIf: (config) => config.editors.includes(EditorType.HELPERS) || config.helpers !== DEFAULT_OPTIONS.helpers,
})
.addTextInput({
path: 'afterRenderRemoteUrl',
name: 'Remote URL',
description: 'URL to fetch JavaScript after render code from.',
defaultValue: DEFAULT_OPTIONS.afterRenderRemoteUrl,
category: ['JavaScript'],
showIf: (config) => config.editors.includes(EditorType.AFTER_RENDER) || config.afterRender !== DEFAULT_OPTIONS.afterRender,
})
.addCustomEditor({
id: 'afterRender',
path: 'afterRender',
name: 'After Content Ready',
description:
'Allows to execute code after content is ready. E.g. use element for drawing chart or event listeners.',
defaultValue: DEFAULT_OPTIONS.afterRender,
editor: AfterRenderWithUrlEditor,
category: ['JavaScript'],
showIf: (config) =>
config.editors.includes(EditorType.AFTER_RENDER) || config.afterRender !== DEFAULT_OPTIONS.afterRender,
});
/**
* Styles
*/
builder
.addCustomEditor({
id: 'externalStyles',
path: 'externalStyles',
name: 'CSS Styles',
defaultValue: DEFAULT_OPTIONS.externalStyles,
editor: ResourcesEditor,
category: ['CSS Styles'],
})
.addTextInput({
path: 'stylesRemoteUrl',
name: 'Remote URL',
description: 'URL to fetch CSS styles code from.',
defaultValue: DEFAULT_OPTIONS.stylesRemoteUrl,
category: ['CSS Styles'],
showIf: (config) => config.editors.includes(EditorType.STYLES) || config.styles !== DEFAULT_OPTIONS.styles,
})
.addCustomEditor({
id: 'styles',
path: 'styles',
name: 'Styles editor',
description: 'Allows to add styles. Use & {} for parent style.',
defaultValue: DEFAULT_OPTIONS.styles,
editor: StylesWithUrlEditor,
category: ['CSS Styles'],
showIf: (config) => config.editors.includes(EditorType.STYLES) || config.styles !== DEFAULT_OPTIONS.styles,
});
/**
* Data Source Integration
*/
builder
.addBooleanSwitch({
path: 'dataSource.enableDataSourceQueries',
name: 'Enable Data Source Queries',
description: 'Allow JavaScript code to execute queries against Grafana data sources.',
defaultValue: DEFAULT_OPTIONS.dataSource.enableDataSourceQueries,
category: ['Data Source'],
})
.addNumberInput({
path: 'dataSource.queryTimeout',
name: 'Query Timeout (ms)',
description: 'Maximum time to wait for data source queries to complete.',
defaultValue: DEFAULT_OPTIONS.dataSource.queryTimeout,
category: ['Data Source'],
showIf: (config) => config.dataSource?.enableDataSourceQueries,
settings: {
min: 1000,
max: 300000,
step: 1000,
},
})
.addBooleanSwitch({
path: 'dataSource.showQueryErrors',
name: 'Show Query Errors',
description: 'Display data source query errors as notifications.',
defaultValue: DEFAULT_OPTIONS.dataSource.showQueryErrors,
category: ['Data Source'],
showIf: (config) => config.dataSource?.enableDataSourceQueries,
});
return builder;
});