Models: add cue spec for text, news, and dashlist panels (#32777)

This commit is contained in:
Ryan McKinley 2021-04-29 20:12:37 -07:00 committed by GitHub
parent 33cfc3d9c2
commit daa3175f1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 163 additions and 45 deletions

View File

@ -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

View 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: []
}

View 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: [],
};

View File

@ -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>;

View File

@ -0,0 +1,17 @@
package grafanaschema
Family: {
lineages: [
[
{
PanelOptions: {
// empty/missing will default to grafana blog
feedUrl?: string
useProxy?: bool
},
PanelFieldConfig: {}
}
]
]
migrations: []
}

View 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 = {};

View File

@ -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,
});
});

View File

@ -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;

View File

@ -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() {

View File

@ -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);

View 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: []
}

View 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/)
`,
};

View File

@ -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);

View File

@ -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: {

View File

@ -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;

View File

@ -1,5 +0,0 @@
export type TextMode = 'html' | 'markdown';
export interface TextOptions {
mode: TextMode;
content: string;
}