mirror of
https://github.com/grafana/grafana.git
synced 2025-09-28 04:33:58 +08:00
Table panel: Add alt and title text options to image cell type (#89930)
* Various updates * Update form callbacks * Use defaultValue as opposed to value on input * Fix things up * Docs * Prettier * Update docs * Update label text * Prettier
This commit is contained in:
@ -209,6 +209,10 @@ If you have a field value that is an image URL or a base64 encoded image you can
|
|||||||
|
|
||||||
{{< figure src="/static/img/docs/v73/table_hover.gif" max-width="900px" caption="Table hover" >}}
|
{{< figure src="/static/img/docs/v73/table_hover.gif" max-width="900px" caption="Table hover" >}}
|
||||||
|
|
||||||
|
Use the **Alt text** option to set the alternative text of an image. The text will be available for screen readers and in cases when images can't be loaded.
|
||||||
|
|
||||||
|
Use the **Title text** option to set the text that's displayed when the image is hovered over with a cursor.
|
||||||
|
|
||||||
#### Sparkline
|
#### Sparkline
|
||||||
|
|
||||||
Shows values rendered as a sparkline. You can show sparklines using the [Time series to table transformation](ref:time-series-to-table-transformation) on data with multiple time series to process it into a format the table can show.
|
Shows values rendered as a sparkline. You can show sparklines using the [Time series to table transformation](ref:time-series-to-table-transformation) on data with multiple time series to process it into a format the table can show.
|
||||||
|
@ -771,6 +771,8 @@ export interface TableJsonViewCellOptions {
|
|||||||
* Json view cell options
|
* Json view cell options
|
||||||
*/
|
*/
|
||||||
export interface TableImageCellOptions {
|
export interface TableImageCellOptions {
|
||||||
|
alt?: string;
|
||||||
|
title?: string;
|
||||||
type: TableCellDisplayMode.Image;
|
type: TableCellDisplayMode.Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ TableJsonViewCellOptions: {
|
|||||||
// Json view cell options
|
// Json view cell options
|
||||||
TableImageCellOptions: {
|
TableImageCellOptions: {
|
||||||
type: TableCellDisplayMode & "image"
|
type: TableCellDisplayMode & "image"
|
||||||
|
alt?: string
|
||||||
|
title?: string
|
||||||
} @cuetsy(kind="interface")
|
} @cuetsy(kind="interface")
|
||||||
|
|
||||||
// Show data links in the cell
|
// Show data links in the cell
|
||||||
|
@ -3,41 +3,41 @@ import * as React from 'react';
|
|||||||
import { getCellLinks } from '../../utils';
|
import { getCellLinks } from '../../utils';
|
||||||
import { DataLinksContextMenu } from '../DataLinks/DataLinksContextMenu';
|
import { DataLinksContextMenu } from '../DataLinks/DataLinksContextMenu';
|
||||||
|
|
||||||
import { TableCellProps } from './types';
|
import { TableCellDisplayMode, TableCellProps } from './types';
|
||||||
|
import { getCellOptions } from './utils';
|
||||||
|
|
||||||
const DATALINKS_HEIGHT_OFFSET = 10;
|
const DATALINKS_HEIGHT_OFFSET = 10;
|
||||||
|
|
||||||
export const ImageCell = (props: TableCellProps) => {
|
export const ImageCell = (props: TableCellProps) => {
|
||||||
const { field, cell, tableStyles, row, cellProps } = props;
|
const { field, cell, tableStyles, row, cellProps } = props;
|
||||||
|
const cellOptions = getCellOptions(field);
|
||||||
|
const { title, alt } =
|
||||||
|
cellOptions.type === TableCellDisplayMode.Image ? cellOptions : { title: undefined, alt: undefined };
|
||||||
const displayValue = field.display!(cell.value);
|
const displayValue = field.display!(cell.value);
|
||||||
|
|
||||||
const hasLinks = Boolean(getCellLinks(field, row)?.length);
|
const hasLinks = Boolean(getCellLinks(field, row)?.length);
|
||||||
|
|
||||||
|
// The image element
|
||||||
|
const img = (
|
||||||
|
<img
|
||||||
|
style={{ height: tableStyles.cellHeight - DATALINKS_HEIGHT_OFFSET, width: 'auto' }}
|
||||||
|
src={displayValue.text}
|
||||||
|
className={tableStyles.imageCell}
|
||||||
|
alt={alt}
|
||||||
|
title={title}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div {...cellProps} className={tableStyles.cellContainer}>
|
<div {...cellProps} className={tableStyles.cellContainer}>
|
||||||
{!hasLinks && (
|
{/* If there are no links we simply render the image */}
|
||||||
<img
|
{!hasLinks && img}
|
||||||
style={{ height: tableStyles.cellHeight - DATALINKS_HEIGHT_OFFSET, width: 'auto' }}
|
{/* Otherwise render data links with image */}
|
||||||
src={displayValue.text}
|
|
||||||
className={tableStyles.imageCell}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{hasLinks && (
|
{hasLinks && (
|
||||||
<DataLinksContextMenu
|
<DataLinksContextMenu
|
||||||
style={{ height: tableStyles.cellHeight - DATALINKS_HEIGHT_OFFSET, width: 'auto' }}
|
style={{ height: tableStyles.cellHeight - DATALINKS_HEIGHT_OFFSET, width: 'auto' }}
|
||||||
links={() => getCellLinks(field, row) || []}
|
links={() => getCellLinks(field, row) || []}
|
||||||
>
|
>
|
||||||
{(api) => {
|
{(api) => {
|
||||||
const img = (
|
|
||||||
<img
|
|
||||||
style={{ height: tableStyles.cellHeight - DATALINKS_HEIGHT_OFFSET, width: 'auto' }}
|
|
||||||
src={displayValue.text}
|
|
||||||
className={tableStyles.imageCell}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
if (api.openMenu) {
|
if (api.openMenu) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -9,6 +9,7 @@ import { Field, Select, TableCellDisplayMode, useStyles2 } from '@grafana/ui';
|
|||||||
import { AutoCellOptionsEditor } from './cells/AutoCellOptionsEditor';
|
import { AutoCellOptionsEditor } from './cells/AutoCellOptionsEditor';
|
||||||
import { BarGaugeCellOptionsEditor } from './cells/BarGaugeCellOptionsEditor';
|
import { BarGaugeCellOptionsEditor } from './cells/BarGaugeCellOptionsEditor';
|
||||||
import { ColorBackgroundCellOptionsEditor } from './cells/ColorBackgroundCellOptionsEditor';
|
import { ColorBackgroundCellOptionsEditor } from './cells/ColorBackgroundCellOptionsEditor';
|
||||||
|
import { ImageCellOptionsEditor } from './cells/ImageCellOptionsEditor';
|
||||||
import { SparklineCellOptionsEditor } from './cells/SparklineCellOptionsEditor';
|
import { SparklineCellOptionsEditor } from './cells/SparklineCellOptionsEditor';
|
||||||
|
|
||||||
// The props that any cell type editor are expected
|
// The props that any cell type editor are expected
|
||||||
@ -73,6 +74,9 @@ export const TableCellOptionEditor = ({ value, onChange }: Props) => {
|
|||||||
{cellType === TableCellDisplayMode.Sparkline && (
|
{cellType === TableCellDisplayMode.Sparkline && (
|
||||||
<SparklineCellOptionsEditor cellOptions={value} onChange={onCellOptionsChange} />
|
<SparklineCellOptionsEditor cellOptions={value} onChange={onCellOptionsChange} />
|
||||||
)}
|
)}
|
||||||
|
{cellType === TableCellDisplayMode.Image && (
|
||||||
|
<ImageCellOptionsEditor cellOptions={value} onChange={onCellOptionsChange} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
import { FormEvent } from 'react';
|
||||||
|
|
||||||
|
import { TableImageCellOptions } from '@grafana/schema';
|
||||||
|
import { Field, Input } from '@grafana/ui';
|
||||||
|
|
||||||
|
import { TableCellEditorProps } from '../TableCellOptionEditor';
|
||||||
|
|
||||||
|
export const ImageCellOptionsEditor = ({ cellOptions, onChange }: TableCellEditorProps<TableImageCellOptions>) => {
|
||||||
|
const onAltChange = (e: FormEvent<HTMLInputElement>) => {
|
||||||
|
cellOptions.alt = e.currentTarget.value;
|
||||||
|
onChange(cellOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTitleChange = (e: FormEvent<HTMLInputElement>) => {
|
||||||
|
cellOptions.title = e.currentTarget.value;
|
||||||
|
onChange(cellOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Field
|
||||||
|
label="Alt text"
|
||||||
|
description="Alternative text that will be displayed if an image can't be displayed or for users who use a screen reader"
|
||||||
|
>
|
||||||
|
<Input onChange={onAltChange} defaultValue={cellOptions.alt} />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field label="Title text" description="Text that will be displayed when the image is hovered by a cursor">
|
||||||
|
<Input onChange={onTitleChange} defaultValue={cellOptions.title} />
|
||||||
|
</Field>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
Reference in New Issue
Block a user