Commit 55f304f1 by Hugo Häggmark Committed by GitHub

TextPanel: Removes Angular Text Panel (#25504)

* TextPanel: Removes Angular Text Panel

* Tests: updates snapshots
parent aa3d8930
......@@ -78,7 +78,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......@@ -191,7 +191,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......@@ -285,7 +285,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......@@ -434,7 +434,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......@@ -547,7 +547,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......@@ -641,7 +641,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......@@ -741,7 +741,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......
......@@ -235,7 +235,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......@@ -477,7 +477,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......@@ -719,7 +719,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......@@ -961,7 +961,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
],
"refresh": undefined,
"revision": undefined,
"schemaVersion": 25,
"schemaVersion": 26,
"snapshot": undefined,
"style": "dark",
"tags": Array [],
......
......@@ -132,7 +132,7 @@ describe('DashboardModel', () => {
});
it('dashboard schema version should be set to latest', () => {
expect(model.schemaVersion).toBe(25);
expect(model.schemaVersion).toBe(26);
});
it('graph thresholds should be migrated', () => {
......@@ -715,6 +715,89 @@ describe('DashboardModel', () => {
]);
});
});
describe('when migrating to new Text Panel', () => {
let model: DashboardModel;
beforeEach(() => {
model = new DashboardModel({
panels: [
{
id: 2,
type: 'text',
title: 'Angular Text Panel',
content:
'# Angular Text Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n\n',
mode: 'markdown',
},
{
id: 3,
type: 'text2',
title: 'React Text Panel from scratch',
options: {
mode: 'markdown',
content:
'# React Text Panel from scratch\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text',
},
},
{
id: 4,
type: 'text2',
title: 'React Text Panel from Angular Panel',
options: {
mode: 'markdown',
content:
'# React Text Panel from Angular Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text',
angular: {
content:
'# React Text Panel from Angular Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n',
mode: 'markdown',
options: {},
},
},
},
],
});
});
it('should have 3 panels after migration', () => {
expect(model.panels.length).toBe(3);
});
it('should not migrate panel with old Text Panel id', () => {
const oldAngularPanel: any = model.panels[0];
expect(oldAngularPanel.id).toEqual(2);
expect(oldAngularPanel.type).toEqual('text');
expect(oldAngularPanel.title).toEqual('Angular Text Panel');
expect(oldAngularPanel.content).toEqual(
'# Angular Text Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n\n'
);
expect(oldAngularPanel.mode).toEqual('markdown');
});
it('should migrate panels with new Text Panel id', () => {
const reactPanel: any = model.panels[1];
expect(reactPanel.id).toEqual(3);
expect(reactPanel.type).toEqual('text');
expect(reactPanel.title).toEqual('React Text Panel from scratch');
expect(reactPanel.options.content).toEqual(
'# React Text Panel from scratch\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text'
);
expect(reactPanel.options.mode).toEqual('markdown');
});
it('should clean up old angular options for panels with new Text Panel id', () => {
const reactPanel: any = model.panels[2];
expect(reactPanel.id).toEqual(4);
expect(reactPanel.type).toEqual('text');
expect(reactPanel.title).toEqual('React Text Panel from Angular Panel');
expect(reactPanel.options.content).toEqual(
'# React Text Panel from Angular Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text'
);
expect(reactPanel.options.mode).toEqual('markdown');
expect(reactPanel.options.angular).toBeUndefined();
});
});
});
function createRow(options: any, panelDescriptions: any[]) {
......
......@@ -31,7 +31,7 @@ export class DashboardMigrator {
let i, j, k, n;
const oldVersion = this.dashboard.schemaVersion;
const panelUpgrades = [];
this.dashboard.schemaVersion = 25;
this.dashboard.schemaVersion = 26;
if (oldVersion === this.dashboard.schemaVersion) {
return;
......@@ -564,6 +564,18 @@ export class DashboardMigrator {
}
}
if (oldVersion < 26) {
panelUpgrades.push((panel: any) => {
const wasReactText = panel.type === 'text2';
if (!wasReactText) {
return;
}
panel.type = 'text';
delete panel.options.angular;
});
}
if (panelUpgrades.length === 0) {
return;
}
......
......@@ -37,7 +37,6 @@ const azureMonitorPlugin = async () =>
);
import * as textPanel from 'app/plugins/panel/text/module';
import * as text2Panel from 'app/plugins/panel/text2/module';
import * as graph2Panel from 'app/plugins/panel/graph2/module';
import * as graphPanel from 'app/plugins/panel/graph/module';
import * as dashListPanel from 'app/plugins/panel/dashlist/module';
......@@ -79,7 +78,6 @@ const builtInPlugins: any = {
'app/plugins/datasource/grafana-azure-monitor-datasource/module': azureMonitorPlugin,
'app/plugins/panel/text/module': textPanel,
'app/plugins/panel/text2/module': text2Panel,
'app/plugins/panel/graph2/module': graph2Panel,
'app/plugins/panel/graph/module': graphPanel,
'app/plugins/panel/dashlist/module': dashListPanel,
......
<div class="gf-form-inline">
<div class="gf-form">
<span class="gf-form-label">Mode</span>
<span class="gf-form-select-wrapper">
<select class="gf-form-input" ng-model="ctrl.panel.mode" ng-options="f for f in ['html','markdown']"></select>
</span>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form gf-form--grow">
<code-editor content="ctrl.panel.content" on-change="ctrl.render()" data-mode="markdown" data-max-lines=20>
</code-editor>
</div>
</div>
<p class="markdown-html panel-text-content" ng-bind-html="ctrl.content" ng-show="ctrl.content">
</p>
import _ from 'lodash';
import { PanelCtrl } from 'app/plugins/sdk';
import config from 'app/core/config';
import { auto, ISCEService } from 'angular';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { PanelEvents, textUtil } from '@grafana/data';
import { renderMarkdown } from '@grafana/data';
const defaultContent = `
# Title
For markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)
`;
export class TextPanelCtrl extends PanelCtrl {
static templateUrl = `public/app/plugins/panel/text/module.html`;
static scrollable = true;
content: string;
// Set and populate defaults
panelDefaults = {
mode: 'markdown', // 'html', 'markdown', 'text'
content: defaultContent,
};
/** @ngInject */
constructor(
$scope: any,
$injector: auto.IInjectorService,
private templateSrv: TemplateSrv,
private $sce: ISCEService
) {
super($scope, $injector);
_.defaults(this.panel, this.panelDefaults);
this.events.on(PanelEvents.editModeInitialized, this.onInitEditMode.bind(this));
this.events.on(PanelEvents.refresh, this.onRefresh.bind(this));
this.events.on(PanelEvents.render, this.onRender.bind(this));
const renderWhenChanged = (scope: any) => {
const { panel } = scope.ctrl;
return [panel.content, panel.mode].join();
};
$scope.$watch(
renderWhenChanged,
_.throttle(() => {
this.render();
}, 100)
);
}
onInitEditMode() {
this.addEditorTab('Options', 'public/app/plugins/panel/text/editor.html');
if (this.panel.mode === 'text') {
this.panel.mode = 'markdown';
}
}
onRefresh() {
this.render();
}
onRender() {
if (this.panel.mode === 'markdown') {
this.renderMarkdown(this.panel.content);
} else if (this.panel.mode === 'html') {
this.updateContent(this.panel.content);
}
this.renderingCompleted();
}
renderText(content: string) {
const safeContent = textUtil.escapeHtml(content).replace(/\n/g, '<br/>');
this.updateContent(safeContent);
}
renderMarkdown(content: string) {
this.$scope.$applyAsync(() => {
this.updateContent(renderMarkdown(content));
});
}
updateContent(html: string) {
try {
html = this.templateSrv.replace(html, this.panel.scopedVars, 'html');
} catch (e) {
console.log('Text panel error: ', e);
}
this.content = this.$sce.trustAsHtml(config.disableSanitizeHtml ? html : textUtil.sanitize(html));
}
}
export { TextPanelCtrl as PanelCtrl };
import { PanelModel, PanelPlugin } from '@grafana/data';
import { PanelPlugin } from '@grafana/data';
import { TextPanel } from './TextPanel';
import { TextOptions } from './types';
import { textPanelMigrationHandler } from './textPanelMigrationHandler';
export const plugin = new PanelPlugin<TextOptions>(TextPanel)
.setPanelOptions(builder => {
......@@ -33,9 +34,4 @@ For markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)
`,
});
})
.setPanelChangeHandler((panel: PanelModel<TextOptions>, prevPluginId: string, prevOptions: any) => {
if (prevPluginId === 'text') {
return prevOptions as TextOptions;
}
return panel.options;
});
.setMigrationHandler(textPanelMigrationHandler);
import { textPanelMigrationHandler } from './textPanelMigrationHandler';
import { TextOptions } from './types';
import { FieldConfigSource, PanelModel } from '@grafana/data';
describe('textPanelMigrationHandler', () => {
describe('when invoked and previous version was old Angular text panel', () => {
it('then should migrate options', () => {
const panel: any = {
content: '<span>Hello World<span>',
mode: 'html',
};
const result = textPanelMigrationHandler(panel);
expect(result.content).toEqual('<span>Hello World<span>');
expect(result.mode).toEqual('html');
});
});
describe('when invoked and previous version was not old Angular text panel', () => {
it('then should just pass options through', () => {
const panel: PanelModel<TextOptions> = {
id: 1,
fieldConfig: ({} as unknown) as FieldConfigSource,
options: {
content: `# Title
For markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)
`,
mode: 'markdown',
},
};
const result = textPanelMigrationHandler(panel);
expect(result.content).toEqual(`# Title
For markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)
`);
expect(result.mode).toEqual('markdown');
});
});
});
import { PanelModel } from '@grafana/data';
import { TextMode, TextOptions } from './types';
export const textPanelMigrationHandler = (panel: PanelModel<TextOptions>): Partial<TextOptions> => {
// Migrates old Angular based text panel props to new props
if (panel.hasOwnProperty('content') && panel.hasOwnProperty('mode')) {
const oldTextPanel: { content: string; mode: string } = (panel as unknown) as any;
const content = oldTextPanel.content;
const mode = (oldTextPanel.mode as unknown) as TextMode;
return { content, mode };
}
return panel.options as TextOptions;
};
# Text Panel - Native Plugin
The Text Panel is **included** with Grafana.
The Text Panel is a very simple panel that displays text. The source text is written in the Markdown syntax meaning you can format the text. Read [GitHub's Mastering Markdown](https://guides.github.com/features/mastering-markdown/) to learn more.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 84.72 84.72"><defs><style>.cls-1{fill:#3865ab;}.cls-2{fill:#84aff1;}.cls-3{fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="23.44" y1="42.36" x2="61.28" y2="42.36" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f2cc0c"/><stop offset="1" stop-color="#ff9830"/></linearGradient></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><rect class="cls-1" x="8.53" y="8.53" width="67.66" height="67.66" rx="1"/><path class="cls-2" d="M83.72,84.72H1a1,1,0,0,1-1-1V1A1,1,0,0,1,1,0H83.72a1,1,0,0,1,1,1V83.72A1,1,0,0,1,83.72,84.72ZM5,80.72H79.72a1,1,0,0,0,1-1V5a1,1,0,0,0-1-1H5A1,1,0,0,0,4,5V79.72A1,1,0,0,0,5,80.72Z"/><path class="cls-3" d="M60.28,21.25H24.44a1,1,0,0,0-1,1V29a1,1,0,0,0,1,1H37a1,1,0,0,1,1,1V62.47a1,1,0,0,0,1,1h6.78a1,1,0,0,0,1-1V31a1,1,0,0,1,1-1H60.28a1,1,0,0,0,1-1V22.25A1,1,0,0,0,60.28,21.25Z"/></g></g></svg>
\ No newline at end of file
{
"type": "panel",
"name": "Text v2",
"id": "text2",
"state": "alpha",
"skipDataQuery": true,
"info": {
"author": {
"name": "Grafana Labs",
"url": "https://grafana.com"
},
"logos": {
"small": "img/icn-text-panel.svg",
"large": "img/icn-text-panel.svg"
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment