mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Icon Panel: add new alpha panel to show an icon (#40355)
This commit is contained in:
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -92,6 +92,7 @@ go.sum @grafana/backend-platform
|
||||
/public/app/plugins/panel/timeseries @grafana/grafana-bi-squad
|
||||
/public/app/plugins/panel/geomap @grafana/grafana-edge-squad
|
||||
/public/app/plugins/panel/canvas @grafana/grafana-edge-squad
|
||||
/public/app/plugins/panel/icon @grafana/grafana-edge-squad
|
||||
/scripts/build/release-packages.sh @grafana/plugins-platform
|
||||
/scripts/circle-release-next-packages.sh @grafana/plugins-platform
|
||||
/scripts/ci-frontend-metrics.sh @grafana/user-essentials @grafana/plugins-platform @grafana/grafana-bi-squad
|
||||
|
||||
@@ -14,7 +14,7 @@ import { isString } from 'lodash';
|
||||
import { LineConfig } from '../types';
|
||||
import { DimensionContext } from 'app/features/dimensions/context';
|
||||
|
||||
interface IconConfig {
|
||||
export interface IconConfig {
|
||||
path?: ResourceDimensionConfig;
|
||||
fill?: ColorDimensionConfig;
|
||||
stroke?: LineConfig;
|
||||
|
||||
@@ -71,6 +71,7 @@ import * as alertGroupsPanel from 'app/plugins/panel/alertGroups/module';
|
||||
// Async loaded panels
|
||||
const geomapPanel = async () => await import(/* webpackChunkName: "geomapPanel" */ 'app/plugins/panel/geomap/module');
|
||||
const canvasPanel = async () => await import(/* webpackChunkName: "canvasPanel" */ 'app/plugins/panel/canvas/module');
|
||||
const iconPanel = async () => await import(/* webpackChunkName: "iconPanel" */ 'app/plugins/panel/icon/module');
|
||||
|
||||
const builtInPlugins: any = {
|
||||
'app/plugins/datasource/graphite/module': graphitePlugin,
|
||||
@@ -102,6 +103,7 @@ const builtInPlugins: any = {
|
||||
'app/plugins/panel/xychart/module': xyChartPanel,
|
||||
'app/plugins/panel/geomap/module': geomapPanel,
|
||||
'app/plugins/panel/canvas/module': canvasPanel,
|
||||
'app/plugins/panel/icon/module': iconPanel,
|
||||
'app/plugins/panel/dashlist/module': dashListPanel,
|
||||
'app/plugins/panel/pluginlist/module': pluginsListPanel,
|
||||
'app/plugins/panel/alertlist/module': alertListPanel,
|
||||
|
||||
@@ -89,7 +89,7 @@ export class CanvasPanel extends Component<Props, State> {
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
const { width, height, data, renderCounter } = this.props;
|
||||
const { width, height, data } = this.props;
|
||||
let changed = false;
|
||||
|
||||
if (width !== nextProps.width || height !== nextProps.height) {
|
||||
@@ -110,10 +110,6 @@ export class CanvasPanel extends Component<Props, State> {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (renderCounter !== nextProps.renderCounter) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
67
public/app/plugins/panel/icon/IconPanel.tsx
Normal file
67
public/app/plugins/panel/icon/IconPanel.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import React, { Component } from 'react';
|
||||
import { PanelProps } from '@grafana/data';
|
||||
import { PanelOptions } from './models.gen';
|
||||
import { ElementState } from 'app/features/canvas/runtime/element';
|
||||
import { iconItem } from 'app/features/canvas/elements/icon';
|
||||
import {
|
||||
ColorDimensionConfig,
|
||||
DimensionContext,
|
||||
getColorDimensionFromData,
|
||||
getResourceDimensionFromData,
|
||||
getScaleDimensionFromData,
|
||||
getTextDimensionFromData,
|
||||
ResourceDimensionConfig,
|
||||
ScaleDimensionConfig,
|
||||
TextDimensionConfig,
|
||||
} from 'app/features/dimensions';
|
||||
|
||||
interface Props extends PanelProps<PanelOptions> {}
|
||||
|
||||
export class IconPanel extends Component<Props> {
|
||||
private element: ElementState;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.element = this.initElement(props);
|
||||
}
|
||||
|
||||
initElement = (props: Props) => {
|
||||
this.element = new ElementState(iconItem, props.options.root as any);
|
||||
this.element.updateSize(props.width, props.height);
|
||||
this.element.updateData(this.dims);
|
||||
return this.element;
|
||||
};
|
||||
|
||||
dims: DimensionContext = {
|
||||
getColor: (color: ColorDimensionConfig) => getColorDimensionFromData(this.props.data, color),
|
||||
getScale: (scale: ScaleDimensionConfig) => getScaleDimensionFromData(this.props.data, scale),
|
||||
getText: (text: TextDimensionConfig) => getTextDimensionFromData(this.props.data, text),
|
||||
getResource: (res: ResourceDimensionConfig) => getResourceDimensionFromData(this.props.data, res),
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
const { width, height, data } = this.props;
|
||||
let changed = false;
|
||||
|
||||
if (width !== nextProps.width || height !== nextProps.height) {
|
||||
this.element.updateSize(nextProps.width, nextProps.height);
|
||||
changed = true;
|
||||
}
|
||||
if (data !== nextProps.data) {
|
||||
this.element.updateData(this.dims);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Reload the element when options change
|
||||
if (this.props.options?.root !== nextProps.options?.root) {
|
||||
this.initElement(nextProps);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { width, height } = this.props;
|
||||
return <div style={{ width, height, overflow: 'hidden', position: 'relative' }}>{this.element.render()}</div>;
|
||||
}
|
||||
}
|
||||
3
public/app/plugins/panel/icon/README.md
Normal file
3
public/app/plugins/panel/icon/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Icon panel - Native Plugin
|
||||
|
||||
The icon panel is **included** with Grafana.
|
||||
4
public/app/plugins/panel/icon/img/icn-icon.svg
Normal file
4
public/app/plugins/panel/icon/img/icn-icon.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<defs><style>.cls-1{fill:#84aff1;}.cls-2{fill:url(#linear-gradient);}.cls-3{fill:#3865ab;}</style><linearGradient id="linear-gradient" y1="40.18" x2="82.99" y2="40.18" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f2cc0c"/><stop offset="1" stop-color="#ff9830"/></linearGradient></defs>
|
||||
<path class="cls-3" d="M21.92,6.62a1,1,0,0,0-.54-.54A1,1,0,0,0,21,6H16a1,1,0,0,0,0,2h2.59L13,13.59l-3.29-3.3a1,1,0,0,0-1.42,0l-6,6a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0L9,12.41l3.29,3.3a1,1,0,0,0,1.42,0L20,9.41V12a1,1,0,0,0,2,0V7A1,1,0,0,0,21.92,6.62Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 629 B |
23
public/app/plugins/panel/icon/models.gen.ts
Normal file
23
public/app/plugins/panel/icon/models.gen.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NOTE: This file will be auto generated from models.cue
|
||||
// It is currenty hand written but will serve as the target for cuetsy
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
import { CanvasElementOptions } from 'app/features/canvas';
|
||||
import { IconConfig } from 'app/features/canvas/elements/icon';
|
||||
import { ResourceDimensionMode } from 'app/features/dimensions';
|
||||
|
||||
export interface PanelOptions {
|
||||
root: Omit<CanvasElementOptions<IconConfig>, 'type'>; // type is forced
|
||||
}
|
||||
|
||||
export const defaultPanelOptions: PanelOptions = {
|
||||
root: {
|
||||
config: {
|
||||
path: {
|
||||
mode: ResourceDimensionMode.Fixed,
|
||||
fixed: 'img/icons/unicons/analysis.svg',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
27
public/app/plugins/panel/icon/module.tsx
Normal file
27
public/app/plugins/panel/icon/module.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
|
||||
import { IconPanel } from './IconPanel';
|
||||
import { defaultPanelOptions, PanelOptions } from './models.gen';
|
||||
import { IconConfig, iconItem } from 'app/features/canvas/elements/icon';
|
||||
import { optionBuilder } from '../canvas/editor/options';
|
||||
import { CanvasElementOptions } from 'app/features/canvas';
|
||||
|
||||
export const plugin = new PanelPlugin<PanelOptions>(IconPanel)
|
||||
.setNoPadding() // extend to panel edges
|
||||
.useFieldConfig()
|
||||
.setPanelOptions((builder) => {
|
||||
builder.addNestedOptions<CanvasElementOptions<IconConfig>>({
|
||||
category: ['Icon'],
|
||||
path: 'root',
|
||||
|
||||
// Dynamically fill the selected element
|
||||
build: (builder, ctx) => {
|
||||
iconItem.registerOptionsUI!(builder, ctx);
|
||||
|
||||
optionBuilder.addBackground(builder, ctx);
|
||||
optionBuilder.addBorder(builder, ctx);
|
||||
},
|
||||
|
||||
defaultValue: defaultPanelOptions.root as any,
|
||||
});
|
||||
});
|
||||
18
public/app/plugins/panel/icon/plugin.json
Normal file
18
public/app/plugins/panel/icon/plugin.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"type": "panel",
|
||||
"name": "Icon",
|
||||
"id": "icon",
|
||||
"state": "alpha",
|
||||
|
||||
"info": {
|
||||
"description": "Show icon based on data",
|
||||
"author": {
|
||||
"name": "Grafana Labs",
|
||||
"url": "https://grafana.com"
|
||||
},
|
||||
"logos": {
|
||||
"small": "img/icn-icon.svg",
|
||||
"large": "img/icn-icon.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user