mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Models: add cue spec for text, news, and dashlist panels (#32777)
This commit is contained in:
parent
33cfc3d9c2
commit
daa3175f1c
@ -7,8 +7,14 @@ package scuemata
|
||||
// rather, they are composed into panel structures as they are defined within
|
||||
// the larger Dashboard schema.
|
||||
#PanelSchema: {
|
||||
// Defines plugin specific options for a panel
|
||||
PanelOptions: {...}
|
||||
PanelFieldConfig: {...}
|
||||
|
||||
// Define the custom properties that exist within standard field config
|
||||
PanelFieldConfig?: {...}
|
||||
|
||||
// Panels may define their own types
|
||||
...
|
||||
}
|
||||
|
||||
// A lineage of panel schema
|
||||
|
22
public/app/plugins/panel/dashlist/models.cue
Normal file
22
public/app/plugins/panel/dashlist/models.cue
Normal file
@ -0,0 +1,22 @@
|
||||
package grafanaschema
|
||||
|
||||
Family: {
|
||||
lineages: [
|
||||
[
|
||||
{
|
||||
PanelOptions: {
|
||||
showStarred: bool | *true
|
||||
showRecentlyViewed: bool | *false
|
||||
showSearch: bool | *false
|
||||
showHeadings: bool | *true
|
||||
maxItems: int | *10
|
||||
query: string | *""
|
||||
folderId?: int
|
||||
tags: [...string] | *[]
|
||||
},
|
||||
PanelFieldConfig: {}
|
||||
}
|
||||
]
|
||||
]
|
||||
migrations: []
|
||||
}
|
27
public/app/plugins/panel/dashlist/models.gen.ts
Normal file
27
public/app/plugins/panel/dashlist/models.gen.ts
Normal file
@ -0,0 +1,27 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NOTE: This file will be auto generated from models.cue
|
||||
// It is currenty hand written but will serve as the target for cuetsy
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
export const modelVersion = Object.freeze([1, 0]);
|
||||
|
||||
export interface PanelOptions {
|
||||
showStarred: boolean;
|
||||
showRecentlyViewed: boolean;
|
||||
showSearch: boolean;
|
||||
showHeadings: boolean;
|
||||
maxItems: number;
|
||||
query?: string;
|
||||
folderId?: number;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
export const defaultPanelOptions: PanelOptions = {
|
||||
showStarred: true,
|
||||
showRecentlyViewed: false,
|
||||
showSearch: false,
|
||||
showHeadings: true,
|
||||
maxItems: 10,
|
||||
query: '',
|
||||
tags: [],
|
||||
};
|
@ -10,11 +10,12 @@ import { loadRSSFeed } from './rss';
|
||||
|
||||
// Types
|
||||
import { PanelProps, DataFrameView, dateTimeFormat, GrafanaTheme, textUtil } from '@grafana/data';
|
||||
import { NewsOptions, NewsItem } from './types';
|
||||
import { NewsItem } from './types';
|
||||
import { PanelOptions } from './models.gen';
|
||||
import { DEFAULT_FEED_URL, PROXY_PREFIX } from './constants';
|
||||
import { css } from '@emotion/css';
|
||||
|
||||
interface Props extends PanelProps<NewsOptions> {}
|
||||
interface Props extends PanelProps<PanelOptions> {}
|
||||
|
||||
interface State {
|
||||
news?: DataFrameView<NewsItem>;
|
||||
|
17
public/app/plugins/panel/news/models.cue
Normal file
17
public/app/plugins/panel/news/models.cue
Normal file
@ -0,0 +1,17 @@
|
||||
package grafanaschema
|
||||
|
||||
Family: {
|
||||
lineages: [
|
||||
[
|
||||
{
|
||||
PanelOptions: {
|
||||
// empty/missing will default to grafana blog
|
||||
feedUrl?: string
|
||||
useProxy?: bool
|
||||
},
|
||||
PanelFieldConfig: {}
|
||||
}
|
||||
]
|
||||
]
|
||||
migrations: []
|
||||
}
|
13
public/app/plugins/panel/news/models.gen.ts
Normal file
13
public/app/plugins/panel/news/models.gen.ts
Normal file
@ -0,0 +1,13 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NOTE: This file will be auto generated from models.cue
|
||||
// It is currenty hand written but will serve as the target for cuetsy
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
export const modelVersion = Object.freeze([1, 0]);
|
||||
|
||||
export interface PanelOptions {
|
||||
feedUrl?: string;
|
||||
useProxy?: boolean;
|
||||
}
|
||||
|
||||
export const defaultPanelOptions: PanelOptions = {};
|
@ -1,10 +1,10 @@
|
||||
import { isString } from 'lodash';
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
import { NewsPanel } from './NewsPanel';
|
||||
import { NewsOptions } from './types';
|
||||
import { PanelOptions, defaultPanelOptions } from './models.gen';
|
||||
import { DEFAULT_FEED_URL, PROXY_PREFIX } from './constants';
|
||||
|
||||
export const plugin = new PanelPlugin<NewsOptions>(NewsPanel).setPanelOptions((builder) => {
|
||||
export const plugin = new PanelPlugin<PanelOptions>(NewsPanel).setPanelOptions((builder) => {
|
||||
builder
|
||||
.addTextInput({
|
||||
path: 'feedUrl',
|
||||
@ -13,13 +13,15 @@ export const plugin = new PanelPlugin<NewsOptions>(NewsPanel).setPanelOptions((b
|
||||
settings: {
|
||||
placeholder: DEFAULT_FEED_URL,
|
||||
},
|
||||
defaultValue: defaultPanelOptions.feedUrl,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'useProxy',
|
||||
name: 'Use Proxy',
|
||||
description: 'If the feed is unable to connect, consider a CORS proxy',
|
||||
showIf: (currentConfig: NewsOptions) => {
|
||||
showIf: (currentConfig: PanelOptions) => {
|
||||
return isString(currentConfig.feedUrl) && !currentConfig.feedUrl.startsWith(PROXY_PREFIX);
|
||||
},
|
||||
defaultValue: defaultPanelOptions.useProxy,
|
||||
});
|
||||
});
|
||||
|
@ -1,12 +1,3 @@
|
||||
export interface NewsOptions {
|
||||
feedUrl?: string;
|
||||
useProxy?: boolean;
|
||||
}
|
||||
|
||||
export const defaults: NewsOptions = {
|
||||
// will default to grafana blog
|
||||
};
|
||||
|
||||
export interface NewsItem {
|
||||
date: number;
|
||||
title: string;
|
||||
|
@ -5,12 +5,12 @@ import { PanelProps, renderMarkdown, textUtil } from '@grafana/data';
|
||||
// Utils
|
||||
import config from 'app/core/config';
|
||||
// Types
|
||||
import { TextOptions } from './types';
|
||||
import { PanelOptions, TextMode } from './models.gen';
|
||||
import { CustomScrollbar, stylesFactory } from '@grafana/ui';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import DangerouslySetHtmlContent from 'dangerously-set-html-content';
|
||||
|
||||
interface Props extends PanelProps<TextOptions> {}
|
||||
interface Props extends PanelProps<PanelOptions> {}
|
||||
|
||||
interface State {
|
||||
html: string;
|
||||
@ -55,18 +55,18 @@ export class TextPanel extends PureComponent<Props, State> {
|
||||
return config.disableSanitizeHtml ? content : textUtil.sanitize(content);
|
||||
}
|
||||
|
||||
processContent(options: TextOptions): string {
|
||||
processContent(options: PanelOptions): string {
|
||||
const { mode, content } = options;
|
||||
|
||||
if (!content) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (mode === 'markdown') {
|
||||
return this.prepareMarkdown(content);
|
||||
if (mode === TextMode.HTML) {
|
||||
return this.prepareHTML(content);
|
||||
}
|
||||
|
||||
return this.prepareHTML(content);
|
||||
return this.prepareMarkdown(content);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -10,10 +10,10 @@ import {
|
||||
} from '@grafana/ui';
|
||||
import { GrafanaTheme, StandardEditorProps } from '@grafana/data';
|
||||
|
||||
import { TextOptions } from './types';
|
||||
import { PanelOptions, TextMode } from './models.gen';
|
||||
|
||||
export const TextPanelEditor: FC<StandardEditorProps<string, any, TextOptions>> = ({ value, onChange, context }) => {
|
||||
const language = useMemo(() => context.options?.mode ?? 'markdown', [context]);
|
||||
export const TextPanelEditor: FC<StandardEditorProps<string, any, PanelOptions>> = ({ value, onChange, context }) => {
|
||||
const language = useMemo(() => context.options?.mode ?? TextMode.Markdown, [context]);
|
||||
const theme = useTheme();
|
||||
const styles = getStyles(theme);
|
||||
|
||||
|
23
public/app/plugins/panel/text/models.cue
Normal file
23
public/app/plugins/panel/text/models.cue
Normal file
@ -0,0 +1,23 @@
|
||||
package grafanaschema
|
||||
|
||||
Family: {
|
||||
lineages: [
|
||||
[
|
||||
{
|
||||
TextMode: "html" | "markdown" @cuetsy(targetType="enum",withName="TextMode")
|
||||
|
||||
PanelOptions: {
|
||||
mode: TextMode | *"markdown"
|
||||
content: string | *"""
|
||||
# Title
|
||||
|
||||
For markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)
|
||||
"""
|
||||
}
|
||||
|
||||
PanelFieldConfig: {}
|
||||
}
|
||||
]
|
||||
]
|
||||
migrations: []
|
||||
}
|
24
public/app/plugins/panel/text/models.gen.ts
Normal file
24
public/app/plugins/panel/text/models.gen.ts
Normal file
@ -0,0 +1,24 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NOTE: This file will be auto generated from models.cue
|
||||
// It is currenty hand written but will serve as the target for cuetsy
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
export const modelVersion = Object.freeze([1, 0]);
|
||||
|
||||
export enum TextMode {
|
||||
HTML = 'html',
|
||||
Markdown = 'markdown',
|
||||
}
|
||||
|
||||
export interface PanelOptions {
|
||||
mode: TextMode;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export const defaultPanelOptions: PanelOptions = {
|
||||
mode: TextMode.Markdown,
|
||||
content: `# Title
|
||||
|
||||
For markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)
|
||||
`,
|
||||
};
|
@ -1,11 +1,11 @@
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
|
||||
import { TextPanel } from './TextPanel';
|
||||
import { TextOptions } from './types';
|
||||
import { textPanelMigrationHandler } from './textPanelMigrationHandler';
|
||||
import { TextPanelEditor } from './TextPanelEditor';
|
||||
import { defaultPanelOptions, PanelOptions, TextMode } from './models.gen';
|
||||
|
||||
export const plugin = new PanelPlugin<TextOptions>(TextPanel)
|
||||
export const plugin = new PanelPlugin<PanelOptions>(TextPanel)
|
||||
.setPanelOptions((builder) => {
|
||||
builder
|
||||
.addRadio({
|
||||
@ -14,22 +14,19 @@ export const plugin = new PanelPlugin<TextOptions>(TextPanel)
|
||||
description: 'text mode of the panel',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: 'markdown', label: 'Markdown' },
|
||||
{ value: 'html', label: 'HTML' },
|
||||
{ value: TextMode.Markdown, label: 'Markdown' },
|
||||
{ value: TextMode.HTML, label: 'HTML' },
|
||||
],
|
||||
},
|
||||
defaultValue: 'markdown',
|
||||
defaultValue: defaultPanelOptions.mode,
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'content',
|
||||
path: 'content',
|
||||
name: 'Content',
|
||||
description: 'Content of the panel',
|
||||
defaultValue: `# Title
|
||||
|
||||
For markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)
|
||||
`,
|
||||
editor: TextPanelEditor,
|
||||
defaultValue: defaultPanelOptions.content,
|
||||
});
|
||||
})
|
||||
.setMigrationHandler(textPanelMigrationHandler);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { textPanelMigrationHandler } from './textPanelMigrationHandler';
|
||||
import { TextMode, TextOptions } from './types';
|
||||
import { TextMode, PanelOptions } from './models.gen';
|
||||
import { FieldConfigSource, PanelModel } from '@grafana/data';
|
||||
|
||||
describe('textPanelMigrationHandler', () => {
|
||||
@ -37,7 +37,7 @@ describe('textPanelMigrationHandler', () => {
|
||||
|
||||
describe('when invoked and previous version was not old Angular text panel', () => {
|
||||
it('then should just pass options through', () => {
|
||||
const panel: PanelModel<TextOptions> = {
|
||||
const panel: PanelModel<PanelOptions> = {
|
||||
id: 1,
|
||||
fieldConfig: ({} as unknown) as FieldConfigSource,
|
||||
options: {
|
||||
@ -45,7 +45,7 @@ describe('textPanelMigrationHandler', () => {
|
||||
|
||||
For markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)
|
||||
`,
|
||||
mode: 'markdown',
|
||||
mode: TextMode.Markdown,
|
||||
},
|
||||
};
|
||||
|
||||
@ -62,7 +62,7 @@ describe('textPanelMigrationHandler', () => {
|
||||
describe('when invoked and previous version was using text mode', () => {
|
||||
it('then should switch to markdown', () => {
|
||||
const mode = ('text' as unknown) as TextMode;
|
||||
const panel: PanelModel<TextOptions> = {
|
||||
const panel: PanelModel<PanelOptions> = {
|
||||
id: 1,
|
||||
fieldConfig: ({} as unknown) as FieldConfigSource,
|
||||
options: {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { PanelModel } from '@grafana/data';
|
||||
import { TextMode, TextOptions } from './types';
|
||||
import { TextMode, PanelOptions } from './models.gen';
|
||||
|
||||
export const textPanelMigrationHandler = (panel: PanelModel<TextOptions>): Partial<TextOptions> => {
|
||||
export const textPanelMigrationHandler = (panel: PanelModel<PanelOptions>): Partial<PanelOptions> => {
|
||||
const previousVersion = parseFloat(panel.pluginVersion || '6.1');
|
||||
let options = panel.options;
|
||||
|
||||
@ -21,7 +21,7 @@ export const textPanelMigrationHandler = (panel: PanelModel<TextOptions>): Parti
|
||||
|
||||
// The 'text' mode has been removed so we need to update any panels still using it to markdown
|
||||
if (options.mode !== 'html' && options.mode !== 'markdown') {
|
||||
options = { ...options, mode: 'markdown' };
|
||||
options = { ...options, mode: TextMode.Markdown };
|
||||
}
|
||||
|
||||
return options;
|
||||
|
@ -1,5 +0,0 @@
|
||||
export type TextMode = 'html' | 'markdown';
|
||||
export interface TextOptions {
|
||||
mode: TextMode;
|
||||
content: string;
|
||||
}
|
Loading…
Reference in New Issue
Block a user