From daa3175f1c44e6f6fbc9baf0c22cb6830191bf37 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Thu, 29 Apr 2021 20:12:37 -0700 Subject: [PATCH] Models: add cue spec for text, news, and dashlist panels (#32777) --- cue/scuemata/panel-plugin.cue | 8 +++++- public/app/plugins/panel/dashlist/models.cue | 22 +++++++++++++++ .../app/plugins/panel/dashlist/models.gen.ts | 27 +++++++++++++++++++ public/app/plugins/panel/news/NewsPanel.tsx | 5 ++-- public/app/plugins/panel/news/models.cue | 17 ++++++++++++ public/app/plugins/panel/news/models.gen.ts | 13 +++++++++ public/app/plugins/panel/news/module.tsx | 8 +++--- public/app/plugins/panel/news/types.ts | 9 ------- public/app/plugins/panel/text/TextPanel.tsx | 12 ++++----- .../plugins/panel/text/TextPanelEditor.tsx | 6 ++--- public/app/plugins/panel/text/models.cue | 23 ++++++++++++++++ public/app/plugins/panel/text/models.gen.ts | 24 +++++++++++++++++ public/app/plugins/panel/text/module.tsx | 15 +++++------ .../text/textPanelMigrationHandler.test.ts | 8 +++--- .../panel/text/textPanelMigrationHandler.ts | 6 ++--- public/app/plugins/panel/text/types.ts | 5 ---- 16 files changed, 163 insertions(+), 45 deletions(-) create mode 100644 public/app/plugins/panel/dashlist/models.cue create mode 100644 public/app/plugins/panel/dashlist/models.gen.ts create mode 100644 public/app/plugins/panel/news/models.cue create mode 100644 public/app/plugins/panel/news/models.gen.ts create mode 100644 public/app/plugins/panel/text/models.cue create mode 100644 public/app/plugins/panel/text/models.gen.ts delete mode 100644 public/app/plugins/panel/text/types.ts diff --git a/cue/scuemata/panel-plugin.cue b/cue/scuemata/panel-plugin.cue index 98d010b44dd..748f99d6d15 100644 --- a/cue/scuemata/panel-plugin.cue +++ b/cue/scuemata/panel-plugin.cue @@ -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 diff --git a/public/app/plugins/panel/dashlist/models.cue b/public/app/plugins/panel/dashlist/models.cue new file mode 100644 index 00000000000..377cc998d20 --- /dev/null +++ b/public/app/plugins/panel/dashlist/models.cue @@ -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: [] +} diff --git a/public/app/plugins/panel/dashlist/models.gen.ts b/public/app/plugins/panel/dashlist/models.gen.ts new file mode 100644 index 00000000000..c42634e997b --- /dev/null +++ b/public/app/plugins/panel/dashlist/models.gen.ts @@ -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: [], +}; diff --git a/public/app/plugins/panel/news/NewsPanel.tsx b/public/app/plugins/panel/news/NewsPanel.tsx index 102969a47d2..47925667ff1 100755 --- a/public/app/plugins/panel/news/NewsPanel.tsx +++ b/public/app/plugins/panel/news/NewsPanel.tsx @@ -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 {} +interface Props extends PanelProps {} interface State { news?: DataFrameView; diff --git a/public/app/plugins/panel/news/models.cue b/public/app/plugins/panel/news/models.cue new file mode 100644 index 00000000000..2d4f2a07607 --- /dev/null +++ b/public/app/plugins/panel/news/models.cue @@ -0,0 +1,17 @@ +package grafanaschema + +Family: { + lineages: [ + [ + { + PanelOptions: { + // empty/missing will default to grafana blog + feedUrl?: string + useProxy?: bool + }, + PanelFieldConfig: {} + } + ] + ] + migrations: [] +} diff --git a/public/app/plugins/panel/news/models.gen.ts b/public/app/plugins/panel/news/models.gen.ts new file mode 100644 index 00000000000..be30b3707a3 --- /dev/null +++ b/public/app/plugins/panel/news/models.gen.ts @@ -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 = {}; diff --git a/public/app/plugins/panel/news/module.tsx b/public/app/plugins/panel/news/module.tsx index 38cad88c99b..c5e3245c54e 100755 --- a/public/app/plugins/panel/news/module.tsx +++ b/public/app/plugins/panel/news/module.tsx @@ -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(NewsPanel).setPanelOptions((builder) => { +export const plugin = new PanelPlugin(NewsPanel).setPanelOptions((builder) => { builder .addTextInput({ path: 'feedUrl', @@ -13,13 +13,15 @@ export const plugin = new PanelPlugin(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, }); }); diff --git a/public/app/plugins/panel/news/types.ts b/public/app/plugins/panel/news/types.ts index a86b973a053..aa5d79a1d93 100755 --- a/public/app/plugins/panel/news/types.ts +++ b/public/app/plugins/panel/news/types.ts @@ -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; diff --git a/public/app/plugins/panel/text/TextPanel.tsx b/public/app/plugins/panel/text/TextPanel.tsx index 7fc1cc13eeb..6828fba9a22 100644 --- a/public/app/plugins/panel/text/TextPanel.tsx +++ b/public/app/plugins/panel/text/TextPanel.tsx @@ -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 {} +interface Props extends PanelProps {} interface State { html: string; @@ -55,18 +55,18 @@ export class TextPanel extends PureComponent { 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() { diff --git a/public/app/plugins/panel/text/TextPanelEditor.tsx b/public/app/plugins/panel/text/TextPanelEditor.tsx index 5029732775e..6493c4c387b 100644 --- a/public/app/plugins/panel/text/TextPanelEditor.tsx +++ b/public/app/plugins/panel/text/TextPanelEditor.tsx @@ -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> = ({ value, onChange, context }) => { - const language = useMemo(() => context.options?.mode ?? 'markdown', [context]); +export const TextPanelEditor: FC> = ({ value, onChange, context }) => { + const language = useMemo(() => context.options?.mode ?? TextMode.Markdown, [context]); const theme = useTheme(); const styles = getStyles(theme); diff --git a/public/app/plugins/panel/text/models.cue b/public/app/plugins/panel/text/models.cue new file mode 100644 index 00000000000..a9b802b3957 --- /dev/null +++ b/public/app/plugins/panel/text/models.cue @@ -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: [] +} diff --git a/public/app/plugins/panel/text/models.gen.ts b/public/app/plugins/panel/text/models.gen.ts new file mode 100644 index 00000000000..5654a59f145 --- /dev/null +++ b/public/app/plugins/panel/text/models.gen.ts @@ -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/) + `, +}; diff --git a/public/app/plugins/panel/text/module.tsx b/public/app/plugins/panel/text/module.tsx index dbc9b3a6001..f30a4492ca7 100644 --- a/public/app/plugins/panel/text/module.tsx +++ b/public/app/plugins/panel/text/module.tsx @@ -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(TextPanel) +export const plugin = new PanelPlugin(TextPanel) .setPanelOptions((builder) => { builder .addRadio({ @@ -14,22 +14,19 @@ export const plugin = new PanelPlugin(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); diff --git a/public/app/plugins/panel/text/textPanelMigrationHandler.test.ts b/public/app/plugins/panel/text/textPanelMigrationHandler.test.ts index 009443a6caa..1537bcc349b 100644 --- a/public/app/plugins/panel/text/textPanelMigrationHandler.test.ts +++ b/public/app/plugins/panel/text/textPanelMigrationHandler.test.ts @@ -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 = { + const panel: PanelModel = { 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 = { + const panel: PanelModel = { id: 1, fieldConfig: ({} as unknown) as FieldConfigSource, options: { diff --git a/public/app/plugins/panel/text/textPanelMigrationHandler.ts b/public/app/plugins/panel/text/textPanelMigrationHandler.ts index 7c87f5fd1fe..23ffcaeb927 100644 --- a/public/app/plugins/panel/text/textPanelMigrationHandler.ts +++ b/public/app/plugins/panel/text/textPanelMigrationHandler.ts @@ -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): Partial => { +export const textPanelMigrationHandler = (panel: PanelModel): Partial => { const previousVersion = parseFloat(panel.pluginVersion || '6.1'); let options = panel.options; @@ -21,7 +21,7 @@ export const textPanelMigrationHandler = (panel: PanelModel): 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; diff --git a/public/app/plugins/panel/text/types.ts b/public/app/plugins/panel/text/types.ts deleted file mode 100644 index baff16c3534..00000000000 --- a/public/app/plugins/panel/text/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type TextMode = 'html' | 'markdown'; -export interface TextOptions { - mode: TextMode; - content: string; -}