Skip to content

Commit

Permalink
Add fallback image (#90)
Browse files Browse the repository at this point in the history
* Add fallback image

* Update denpendencies

* Update documentation
  • Loading branch information
Dalvany authored Apr 16, 2024
1 parent 3b1b9ab commit a4e6fee
Show file tree
Hide file tree
Showing 8 changed files with 1,218 additions and 1,094 deletions.
116 changes: 59 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# Grafana image panel

[![Marketplace](https://img.shields.io/badge/dynamic/json?logo=grafana&color=205AD4&label=marketplace&prefix=v&query=%24.items%5B%3F%28%40.slug%20%3D%3D%20%22dalvany-image-panel%22%29%5D.version&url=https%3A%2F%2Fgrafana.com%2Fapi%2Fplugins)](https://grafana.com/grafana/plugins/dalvany-image-panel)
[![Downloads](https://img.shields.io/badge/dynamic/json?logo=grafana&color=205AD4&label=downloads&query=%24.items%5B%3F%28%40.slug%20%3D%3D%20%22dalvany-image-panel%22%29%5D.downloads&url=https%3A%2F%2Fgrafana.com%2Fapi%2Fplugins)](https://grafana.com/grafana/plugins/dalvany-image-panel)
[![CI](https://github.com/Dalvany/dalvany-image-panel/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/Dalvany/dalvany-image-panel/actions/workflows/ci.yml)
[![CodeQL](https://github.com/Dalvany/dalvany-image-panel/actions/workflows/codeql-analysis.yml/badge.svg?branch=master)](https://github.com/Dalvany/dalvany-image-panel/actions/workflows/codeql-analysis.yml)

# Grafana image panel

Display an image by concatenation of a URL, a metric and a suffix.
The result will be : baseURL + icon field + suffix.

Note :

* version 3.0.0 requires at least Grafana 10.0.3
* Version 2.8.0 requires at least Grafana 9.0.0
* version 2.6.0 requires at least Grafana 8.5.0
Expand All @@ -19,136 +20,137 @@ variable)
* If there is a discrepancy in the tooltip between `elapsed` mode and the real date, if you're using a MySQL database,
please read [this issue](https://github.com/Dalvany/dalvany-image-panel/issues/74) as it might solve the problem.

# Configuration
## Configuration

If queries select multiple fields, use the outer join transform.

## URL
### URL

![configuration panel](https://github.com/Dalvany/dalvany-image-panel/raw/main/src/img/configuration_url.png)

Options for building image URL :

- Base URL (optional) : the start of the URL where to fetch image. Can be left empty if `icon field` already contains
* Base URL (optional) : the start of the URL where to fetch image. Can be left empty if `icon field` already contains
the base URL. This option support variable.
- Icon field : field that contains the name of the image. The special value
* Icon field : field that contains the name of the image. The special value
`First non time field` will use the first non-time field it finds. This is the default value.
- Suffix (optional) : string to add at the end. This option support variable.
* Suffix (optional) : string to add at the end. This option support variable.
* Fallback URL (optional) : image to display if there is an error while loading the "metric" image.

## Image options
### Image options

![configuration panel](https://github.com/Dalvany/dalvany-image-panel/raw/main/src/img/configuration_image.png)

Options that allow to choose how the image will be displayed :

- Image width : the width of the image. This option support variable (beware that it needs to be a number)
- Image height : the height of the image. This option support variable (beware that it needs to be a number)
- Single fill : if the query have a unique result, allow to fill the panel instead of using width and height above
- Alt field : field to use as `alt`. The special value `Use icon field`
* Image width : the width of the image. This option support variable (beware that it needs to be a number)
* Image height : the height of the image. This option support variable (beware that it needs to be a number)
* Single fill : if the query have a unique result, allow to fill the panel instead of using width and height above
* Alt field : field to use as `alt`. The special value `Use icon field`
will use the same field as `Icon field`. This is the default value.

## Shared crosshair options
### Shared crosshair options

![configuration panel](https://github.com/Dalvany/dalvany-image-panel/raw/main/src/img/configuration_shared_crosshair.png)

These options allow to set a background and border when mouse is over in image. It is also used to highlight image if
`shared crosshair` or `shared tooltip` is enabled in the dashboard.

- Background highlight color : the color to use as background image for shared crosshair (default to white with transparency)
- Border highlight color : the border color to use for shared crosshair.
* Background highlight color : the color to use as background image for shared crosshair (default to white with transparency)
* Border highlight color : the border color to use for shared crosshair.

Notes :

- You must enable tooltip in the plugin configuration for `shared tooltip` to actually show a tooltip
- `shared tooltip` doesn't work in slideshow mode (though `shared crosshair` did work), that means tooltip won't show
* You must enable tooltip in the plugin configuration for `shared tooltip` to actually show a tooltip
* `shared tooltip` doesn't work in slideshow mode (though `shared crosshair` did work), that means tooltip won't show
up when hoovering over another panel
- It correlates on time, and work with `timeseries` and `candlestick` panels.
* It correlates on time, and work with `timeseries` and `candlestick` panels.

## Slideshow options
### Slideshow options

![configuration panel](https://github.com/Dalvany/dalvany-image-panel/raw/main/src/img/configuration_slideshow.png)

Options for slideshow :

- Enable slideshow : enable the slideshow.
- Duration : configure how long (in milliseconds) an image will be shown. Can't be `0`.
- Transition : which transition animation to use
- Transition duration : how long the transition will take (in milliseconds). Can't be `0`.
- Pause on hover : when enabled, if the mouse is over an image, the slideshow will pause.
- Infinite : when enabled, slideshow continues from start when finished
* Enable slideshow : enable the slideshow.
* Duration : configure how long (in milliseconds) an image will be shown. Can't be `0`.
* Transition : which transition animation to use
* Transition duration : how long the transition will take (in milliseconds). Can't be `0`.
* Pause on hover : when enabled, if the mouse is over an image, the slideshow will pause.
* Infinite : when enabled, slideshow continues from start when finished

## Image tooltip options
### Image tooltip options

![configuration panel](https://github.com/Dalvany/dalvany-image-panel/raw/main/src/img/configuration_tooltip.png)

Options to add and customize a tooltip :

- Include tooltip : a tooltip will be display when the mouse hovers over the image
- Include field : include a field value in the tooltip text
- Tooltip field : select the field values to display in the tooltip. The special value `Use icon field` will use the
* Include tooltip : a tooltip will be display when the mouse hovers over the image
* Include field : include a field value in the tooltip text
* Tooltip field : select the field values to display in the tooltip. The special value `Use icon field` will use the
same field as `Icon field`. This is the default value.
- Include date : the tooltip will include the date and time
- As elapsed : the date will be displayed as an elapsed date (i.e. 4h hours ago)
* Include date : the tooltip will include the date and time
* As elapsed : the date will be displayed as an elapsed date (i.e. 4h hours ago)

## Image link options
### Image link options

![configuration panel](https://github.com/Dalvany/dalvany-image-panel/raw/main/src/img/configuration_link.png)

It allows to open a link into a new tab. It works like the image URL : it concatenates 3 elements (a base URL, a metric
value and a suffix).

- Click to open : enable link support.
- Open in new tab : allow to open link in a new tab. Default is enable.
- Base URL (optional) : the start of the URL where to fetch image. Can be left empty if `icon field` already contains
* Click to open : enable link support.
* Open in new tab : allow to open link in a new tab. Default is enable.
* Base URL (optional) : the start of the URL where to fetch image. Can be left empty if `icon field` already contains
the base URL. This option support variable.
- Link field : field that contains the value. The special value `Don't use a field` allow not to use any field, the
* Link field : field that contains the value. The special value `Don't use a field` allow not to use any field, the
result will be the same link for all images. This is the default value.
- Suffix (optional) : string to add at the end. This option support variable.
* Suffix (optional) : string to add at the end. This option support variable.

## Overlay options
### Overlay options

![configuration panel](https://github.com/Dalvany/dalvany-image-panel/raw/main/src/img/configuration_overlay.png)

Allow adding colored square as overlay on the corner of each image. Color is bound from values. By default, color is
light transparent grey.
Binding behaves this way :

- If all values declared in binding are numbers AND guess value type from data are also numbers, then it acts like
* If all values declared in binding are numbers AND guess value type from data are also numbers, then it acts like
grafana's threshold.
- Otherwise, it is a simple mapping.
* Otherwise, it is a simple mapping.

Note : when leave an input field, values are sorted and empty input are removed so beware that when choosing the color
bindings are not reordered.

Options for binding :

- Overlay field : select the data field to use for binding (time fields are removed). If `No overlay` is selected,
* Overlay field : select the data field to use for binding (time fields are removed). If `No overlay` is selected,
overlay will not be shown.
- Position : select the position of the overlay.
- Width : allow to select the width of the overlay (in pixel or percent of the image size).
- Height : allow to select the height of the overlay (in pixel or percent of the image size).
- Binding : allow to choose the color for each value. Allow also to choose color for unmapped values.
* Position : select the position of the overlay.
* Width : allow to select the width of the overlay (in pixel or percent of the image size).
* Height : allow to select the height of the overlay (in pixel or percent of the image size).
* Binding : allow to choose the color for each value. Allow also to choose color for unmapped values.

Note : when leave an input field, values are sorted and empty input are removed so beware that when choosing the color
bindings are not reordered.

## Underline options
### Underline options

![configuration panel](https://github.com/Dalvany/dalvany-image-panel/raw/main/src/img/configuration_underline.png)

Add a field value as underline. If text is wider than image then it will be truncated.

- Underline field : field to use as underline. If `No underline` is selected, then underline will not be displayed.
- Text size : size of the text.
- Text align : horizontal underline alignment. Default to `left`.
- Binding field : allow to use a field to bind text color.
- Binding : this configuration will appear if `Underline`'s `Binding field` is set to a field. It will allow to
* Underline field : field to use as underline. If `No underline` is selected, then underline will not be displayed.
* Text size : size of the text.
* Text align : horizontal underline alignment. Default to `left`.
* Binding field : allow to use a field to bind text color.
* Binding : this configuration will appear if `Underline`'s `Binding field` is set to a field. It will allow to
map values to color.

Note : when leave an input field, values are sorted and empty input are removed so beware that when choosing the color
bindings are not reordered.

# Screenshot
## Screenshot

Multiple results

Expand Down Expand Up @@ -178,23 +180,23 @@ Shared tooltip support

![screenshot](https://github.com/Dalvany/dalvany-image-panel/raw/main/src/img/screenshot07.png)

# Install
## Install

Follow instructions from
[grafana plugin web page](https://grafana.com/grafana/plugins/dalvany-image-panel/?tab=installation)

# License
## License

- Color binding component is a modification of grafana's ThresholdsEditor thus under Apache 2.0 license.
* Color binding component is a modification of grafana's ThresholdsEditor thus under Apache 2.0 license.

# Credits
## Credits

Logo for the plugin was found [here](https://www.iconfinder.com/icons/211677/image_icon) and is under MIT license.
[Slideshow](https://github.com/femioladeji/react-slideshow) is under Apache 2.0 license.

GitHub's workflows are from [grafana](https://github.com/grafana/plugin-workflows) and under Apache 2.0 license

# Plugin development : resources
## Plugin development : resources

* [Documentation](https://grafana.com/docs/grafana/latest/developers/plugins/?pg=docs)
* ["Storybook"](https://developers.grafana.com/ui/latest/index.html)
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@
},
"dependencies": {
"@emotion/css": "^11.1.3",
"@grafana/data": "10.0.9",
"@grafana/runtime": "10.0.9",
"@grafana/ui": "10.0.9",
"@grafana/data": "^10.0.9",
"@grafana/runtime": "^10.0.9",
"@grafana/ui": "^10.0.9",
"conditional-wrap": "^1.0.2",
"react": "17.0.2",
"react-dom": "17.0.2",
Expand Down
6 changes: 6 additions & 0 deletions src/components/DynamicImagePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ export function DynamicImagePanel(props: Props) {
}
}

let fallback = options.fallback;
if (fallback?.trim() === "") {
fallback = undefined;
}

let start = options.baseUrl === undefined ? '' : options.baseUrl;
start = props.replaceVariables(start);
let end = options.suffix === undefined ? '' : options.suffix;
Expand Down Expand Up @@ -425,6 +430,7 @@ export function DynamicImagePanel(props: Props) {
const imageData: ImageDataProps = {
time: value.time,
url: start + value.icon + end,
fallback: fallback,
alt: value.alt,
width: w,
height: h,
Expand Down
27 changes: 24 additions & 3 deletions src/components/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Bindings, Position, Size, TEXT_UNBOUNDED_DEFAULT_COLOR } from 'types';
import { Property } from 'csstype';
import { Tooltip, usePanelContext } from '@grafana/ui';
import React, { useCallback } from 'react';
import React, { useCallback, useState } from 'react';
import { DataHoverClearEvent, DataHoverEvent } from '@grafana/data';
import ConditionalWrap from 'conditional-wrap';

function handleError(e: React.SyntheticEvent<HTMLImageElement, Event>) {
console.warn('Error loading image' + e.target);
console.warn('Error loading image ' + e.target);
}

function findBindingColorFromNumber(value: number, binding: Bindings): string {
Expand Down Expand Up @@ -41,6 +41,7 @@ export interface CreateImageProps {
w: string;
tooltip: string | undefined;
url: string;
fallback: string | undefined;
alt: string;
overlay_value: string | number | undefined;
classname: string;
Expand All @@ -60,6 +61,7 @@ export function CreateImage(props: CreateImageProps) {
w,
tooltip,
url,
fallback,
alt,
overlay_value,
classname,
Expand All @@ -72,6 +74,11 @@ export function CreateImage(props: CreateImageProps) {
slideshow,
forceShowTooltip,
} = props;

// "errored" is here to prevent infinite loading in case
// fallback image raise also raise an error
const [errored, setErrored] = useState(false);

const { eventBus } = usePanelContext();
const publishEventEnter = useCallback(
(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
Expand Down Expand Up @@ -135,7 +142,18 @@ export function CreateImage(props: CreateImageProps) {
pointerEvents: 'auto',
}}
title={tl}
onError={(e) => handleError(e)}
onError={(e) => {
handleError(e);
// "errored" is here to prevent infinite loading in case
// fallback image raise also raise an error
if (!errored && fallback !== undefined) {
setErrored(true);
e.currentTarget.src = fallback
}
}}
onLoad={(e) => {
setErrored(false);
}}
src={url}
alt={alt}
/>
Expand Down Expand Up @@ -204,6 +222,8 @@ export interface HighlightProps {
export interface ImageDataProps {
/** Image URL **/
url: string;
/** Fallback URL **/
fallback?: string;
/** Tooltip text, if null no tooltip **/
tooltip?: string | undefined;
/** Alternative **/
Expand Down Expand Up @@ -315,6 +335,7 @@ export function Image(props: ImageProps) {
w={w}
tooltip={image.tooltip}
url={image.url}
fallback={image.fallback}
alt={image.alt}
overlay_value={overlay.overlay_value}
classname={cl + ' ' + va}
Expand Down
Binary file modified src/img/configuration_url.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/module.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ export const plugin = new PanelPlugin<DynamicImageOptions>(DynamicImagePanel).se
description: 'To append at the end of the URL',
category: ['URL'],
})
.addTextInput({
path: 'fallback',
name: 'Fallback URL',
description: "Fallback image to display if URL doesn't work. Leave empty to disable fallback.",
category: ['URL'],
})
.addTextInput({
path: 'width',
name: 'Image width',
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export interface SharedCrossSupport {
export interface DynamicImageOptions {
baseUrl?: string;
suffix?: string;
fallback?: string;
singleFill: boolean;
width: string;
height: string;
Expand Down
Loading

0 comments on commit a4e6fee

Please sign in to comment.