From b2b0be7b939561541ece19f6679fad457f5fcdd1 Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Mon, 27 Jun 2022 14:23:29 +0200 Subject: [PATCH] Table panel: Add multiple data links support to Default, Image and JSONView cells (#51162) * Table panel: Support multiple data links in default cell * Table panel: Show data links for Image and JSONView cells * Simplify DataLinksContextMenu api * Betterer --- .betterer.results | 25 +++++------ .../DataLinks/DataLinksContextMenu.test.tsx | 20 --------- .../DataLinks/DataLinksContextMenu.tsx | 7 ++- .../src/components/Table/BarGaugeCell.tsx | 6 +-- .../src/components/Table/DefaultCell.tsx | 22 ++++++--- .../src/components/Table/ImageCell.tsx | 26 ++++++----- .../src/components/Table/JSONViewCell.tsx | 25 ++++++----- packages/grafana-ui/src/utils/dataLinks.ts | 3 +- packages/grafana-ui/src/utils/table.ts | 45 ++++++++++--------- .../plugins/panel/bargauge/BarGaugePanel.tsx | 4 +- public/app/plugins/panel/gauge/GaugePanel.tsx | 2 +- .../app/plugins/panel/piechart/PieChart.tsx | 2 +- public/app/plugins/panel/stat/StatPanel.tsx | 2 +- 13 files changed, 87 insertions(+), 102 deletions(-) diff --git a/.betterer.results b/.betterer.results index a0acad10818..1e56fc20c86 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2092,7 +2092,7 @@ exports[`better eslint`] = { "packages/grafana-ui/src/components/Switch/Switch.story.tsx:3337756944": [ [11, 15, 258, "Do not use any type assertions.", "1871090638"] ], - "packages/grafana-ui/src/components/Table/BarGaugeCell.tsx:2469721145": [ + "packages/grafana-ui/src/components/Table/BarGaugeCell.tsx:1481110243": [ [46, 13, 17, "Do not use any type assertions.", "3640560184"] ], "packages/grafana-ui/src/components/Table/CellActions.tsx:3266589396": [ @@ -2100,8 +2100,8 @@ exports[`better eslint`] = { [22, 10, 16, "Do not use any type assertions.", "737436615"], [23, 22, 25, "Do not use any type assertions.", "1478996352"] ], - "packages/grafana-ui/src/components/Table/DefaultCell.tsx:1844923424": [ - [14, 34, 40, "Do not use any type assertions.", "91092480"] + "packages/grafana-ui/src/components/Table/DefaultCell.tsx:3618905143": [ + [16, 34, 40, "Do not use any type assertions.", "91092480"] ], "packages/grafana-ui/src/components/Table/Filter.tsx:1102571026": [ [13, 10, 3, "Unexpected any. Specify a different type.", "193409811"] @@ -2121,8 +2121,8 @@ exports[`better eslint`] = { [53, 38, 13, "Do not use any type assertions.", "947160887"], [53, 48, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "packages/grafana-ui/src/components/Table/JSONViewCell.tsx:4022130242": [ - [11, 34, 40, "Do not use any type assertions.", "91092480"] + "packages/grafana-ui/src/components/Table/JSONViewCell.tsx:2181157412": [ + [12, 34, 40, "Do not use any type assertions.", "91092480"] ], "packages/grafana-ui/src/components/Table/Table.story.tsx:4272567078": [ [23, 15, 364, "Do not use any type assertions.", "4121186137"] @@ -2486,9 +2486,6 @@ exports[`better eslint`] = { "packages/grafana-ui/src/utils/colors.ts:349987544": [ [110, 25, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "packages/grafana-ui/src/utils/dataLinks.ts:2916992126": [ - [16, 12, 71, "Do not use any type assertions.", "1504235577"] - ], "packages/grafana-ui/src/utils/debug.ts:2900904491": [ [6, 56, 3, "Unexpected any. Specify a different type.", "193409811"] ], @@ -2516,9 +2513,9 @@ exports[`better eslint`] = { [38, 72, 3, "Unexpected any. Specify a different type.", "193409811"], [38, 85, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "packages/grafana-ui/src/utils/table.ts:3564715667": [ - [8, 52, 3, "Unexpected any. Specify a different type.", "193409811"], - [9, 22, 3, "Unexpected any. Specify a different type.", "193409811"] + "packages/grafana-ui/src/utils/table.ts:2798596296": [ + [7, 52, 3, "Unexpected any. Specify a different type.", "193409811"], + [8, 29, 3, "Unexpected any. Specify a different type.", "193409811"] ], "packages/grafana-ui/src/utils/useAsyncDependency.ts:4089662838": [ [3, 60, 3, "Unexpected any. Specify a different type.", "193409811"] @@ -10930,8 +10927,8 @@ exports[`better eslint`] = { [102, 16, 9, "Do not use any type assertions.", "3692209159"], [102, 22, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "public/app/plugins/panel/bargauge/BarGaugePanel.tsx:3184205061": [ - [114, 75, 3, "Unexpected any. Specify a different type.", "193409811"] + "public/app/plugins/panel/bargauge/BarGaugePanel.tsx:2584207123": [ + [112, 75, 3, "Unexpected any. Specify a different type.", "193409811"] ], "public/app/plugins/panel/candlestick/CandlestickPanel.tsx:3928129934": [ [116, 26, 33, "Do not use any type assertions.", "1940217301"], @@ -11877,7 +11874,7 @@ exports[`better eslint`] = { [194, 16, 3, "Unexpected any. Specify a different type.", "193409811"], [256, 16, 3, "Unexpected any. Specify a different type.", "193409811"] ], - "public/app/plugins/panel/piechart/PieChart.tsx:1361550264": [ + "public/app/plugins/panel/piechart/PieChart.tsx:287896203": [ [201, 12, 3, "Unexpected any. Specify a different type.", "193409811"], [217, 12, 3, "Unexpected any. Specify a different type.", "193409811"] ], diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.test.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.test.tsx index 8deb2ff2f50..e64e0460618 100644 --- a/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.test.tsx +++ b/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.test.tsx @@ -24,18 +24,6 @@ describe('DataLinksContextMenu', () => { origin: {}, }, ]} - config={{ - links: [ - { - title: 'Link1', - url: '/link1', - }, - { - title: 'Link2', - url: '/link2', - }, - ], - }} > {() => { return
; @@ -58,14 +46,6 @@ describe('DataLinksContextMenu', () => { origin: {}, }, ]} - config={{ - links: [ - { - title: 'Link1', - url: '/link1', - }, - ], - }} > {() => { return
; diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.tsx index 5a700355ae6..9524e497cad 100644 --- a/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.tsx +++ b/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.tsx @@ -1,7 +1,7 @@ import { css } from '@emotion/css'; import React from 'react'; -import { FieldConfig, LinkModel } from '@grafana/data'; +import { LinkModel } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { linkModelToContextMenuItems } from '../../utils/dataLinks'; @@ -12,7 +12,6 @@ import { MenuItem } from '../Menu/MenuItem'; interface DataLinksContextMenuProps { children: (props: DataLinksContextMenuApi) => JSX.Element; links: () => LinkModel[]; - config: FieldConfig; } export interface DataLinksContextMenuApi { @@ -20,9 +19,9 @@ export interface DataLinksContextMenuApi { targetClassName?: string; } -export const DataLinksContextMenu: React.FC = ({ children, links, config }) => { - const linksCounter = config.links!.length; +export const DataLinksContextMenu: React.FC = ({ children, links }) => { const itemsGroup: MenuItemsGroup[] = [{ items: linkModelToContextMenuItems(links), label: 'Data links' }]; + const linksCounter = itemsGroup[0].items.length; const renderMenuGroupItems = () => { return itemsGroup.map((group, index) => ( diff --git a/packages/grafana-ui/src/components/Table/BarGaugeCell.tsx b/packages/grafana-ui/src/components/Table/BarGaugeCell.tsx index cf63bc98f01..842a09ef47f 100644 --- a/packages/grafana-ui/src/components/Table/BarGaugeCell.tsx +++ b/packages/grafana-ui/src/components/Table/BarGaugeCell.tsx @@ -76,11 +76,7 @@ export const BarGaugeCell: FC = (props) => { return (
- {hasLinks && ( - - {(api) => renderComponent(api)} - - )} + {hasLinks && {(api) => renderComponent(api)}} {!hasLinks && ( = (props) => { const showActions = (showFilters && cell.value !== undefined) || inspectEnabled; const cellStyle = getCellStyle(tableStyles, field, displayValue, inspectEnabled); - const { link, onClick } = getCellLinks(field, row); + const hasLinks = Boolean(getCellLinks(field, row)?.length); return (
- {!link &&
{value}
} - {link && ( - - {value} - + {!hasLinks &&
{value}
} + + {hasLinks && ( + getCellLinks(field, row) || []}> + {(api) => { + return ( +
+ {value} +
+ ); + }} +
)} + {showActions && }
); diff --git a/packages/grafana-ui/src/components/Table/ImageCell.tsx b/packages/grafana-ui/src/components/Table/ImageCell.tsx index e9d9d42b981..01f4454b680 100644 --- a/packages/grafana-ui/src/components/Table/ImageCell.tsx +++ b/packages/grafana-ui/src/components/Table/ImageCell.tsx @@ -1,6 +1,8 @@ +import { cx } from '@emotion/css'; import React, { FC } from 'react'; import { getCellLinks } from '../../utils'; +import { DataLinksContextMenu } from '../DataLinks/DataLinksContextMenu'; import { TableCellProps } from './types'; @@ -9,21 +11,21 @@ export const ImageCell: FC = (props) => { const displayValue = field.display!(cell.value); - const { link, onClick } = getCellLinks(field, row); + const hasLinks = getCellLinks(field, row)?.length; return (
- {!link && } - {link && ( - - - + {!hasLinks && } + {hasLinks && ( + getCellLinks(field, row) || []}> + {(api) => { + return ( +
+ +
+ ); + }} +
)}
); diff --git a/packages/grafana-ui/src/components/Table/JSONViewCell.tsx b/packages/grafana-ui/src/components/Table/JSONViewCell.tsx index 6f2c62a8c9a..029dd2abd2d 100644 --- a/packages/grafana-ui/src/components/Table/JSONViewCell.tsx +++ b/packages/grafana-ui/src/components/Table/JSONViewCell.tsx @@ -3,6 +3,7 @@ import { isString } from 'lodash'; import React from 'react'; import { getCellLinks } from '../../utils'; +import { DataLinksContextMenu } from '../DataLinks/DataLinksContextMenu'; import { CellActions } from './CellActions'; import { TableCellProps, TableFieldOptions } from './types'; @@ -26,22 +27,22 @@ export function JSONViewCell(props: TableCellProps): JSX.Element { displayValue = JSON.stringify(value, null, ' '); } - const { link, onClick } = getCellLinks(field, row); + const hasLinks = getCellLinks(field, row)?.length; return (
- {!link &&
{displayValue}
} - {link && ( - - {displayValue} - + {!hasLinks &&
{displayValue}
} + {hasLinks && ( + getCellLinks(field, row) || []}> + {(api) => { + return ( +
+ {displayValue} +
+ ); + }} +
)}
{inspectEnabled && } diff --git a/packages/grafana-ui/src/utils/dataLinks.ts b/packages/grafana-ui/src/utils/dataLinks.ts index 42c57622e08..5d2a6db23fd 100644 --- a/packages/grafana-ui/src/utils/dataLinks.ts +++ b/packages/grafana-ui/src/utils/dataLinks.ts @@ -1,7 +1,6 @@ import { LinkModel } from '@grafana/data'; import { MenuItemProps } from '../components/Menu/MenuItem'; -import { IconName } from '../types'; /** * Delays creating links until we need to open the ContextMenu @@ -14,7 +13,7 @@ export const linkModelToContextMenuItems: (links: () => LinkModel[]) => MenuItem // TODO: rename to href url: link.href, target: link.target, - icon: `${link.target === '_self' ? 'link' : 'external-link-alt'}` as IconName, + icon: `${link.target === '_blank' ? 'external-link-alt' : 'link'}`, onClick: link.onClick, }; }); diff --git a/packages/grafana-ui/src/utils/table.ts b/packages/grafana-ui/src/utils/table.ts index 80d346ab27c..1fb03a6aa1b 100644 --- a/packages/grafana-ui/src/utils/table.ts +++ b/packages/grafana-ui/src/utils/table.ts @@ -1,4 +1,3 @@ -import { MouseEventHandler } from 'react'; import { Row } from 'react-table'; import { Field, LinkModel } from '@grafana/data'; @@ -7,29 +6,33 @@ import { Field, LinkModel } from '@grafana/data'; * @internal */ export const getCellLinks = (field: Field, row: Row) => { - let link: LinkModel | undefined; - let onClick: MouseEventHandler | undefined; + let links: Array> | undefined; if (field.getLinks) { - link = field.getLinks({ + links = field.getLinks({ valueRowIndex: row.index, - })[0]; + }); } - //const fieldLink = link?.onClick; - if (link?.onClick) { - onClick = (event) => { - // Allow opening in new tab - if (!(event.ctrlKey || event.metaKey || event.shiftKey)) { - event.preventDefault(); - link!.onClick!(event, { - field, - rowIndex: row.index, - }); - } - }; + if (!links) { + return; } - return { - link, - onClick, - }; + + for (let i = 0; i < links?.length; i++) { + if (links[i].onClick) { + const origOnClick = links[i].onClick; + + links[i].onClick = (event) => { + // Allow opening in new tab + if (!(event.ctrlKey || event.metaKey || event.shiftKey)) { + event.preventDefault(); + origOnClick!(event, { + field, + rowIndex: row.index, + }); + } + }; + } + } + + return links; }; diff --git a/public/app/plugins/panel/bargauge/BarGaugePanel.tsx b/public/app/plugins/panel/bargauge/BarGaugePanel.tsx index 3d8d04373a4..e044661b5a6 100644 --- a/public/app/plugins/panel/bargauge/BarGaugePanel.tsx +++ b/public/app/plugins/panel/bargauge/BarGaugePanel.tsx @@ -60,9 +60,7 @@ export class BarGaugePanel extends PureComponent> { if (hasLinks && getLinks) { return (
- - {(api) => this.renderComponent(valueProps, api)} - + {(api) => this.renderComponent(valueProps, api)}
); } diff --git a/public/app/plugins/panel/gauge/GaugePanel.tsx b/public/app/plugins/panel/gauge/GaugePanel.tsx index dcd70e76456..226fc47f33e 100644 --- a/public/app/plugins/panel/gauge/GaugePanel.tsx +++ b/public/app/plugins/panel/gauge/GaugePanel.tsx @@ -41,7 +41,7 @@ export class GaugePanel extends PureComponent> { if (hasLinks && getLinks) { return ( - + {(api) => { return this.renderComponent(valueProps, api); }} diff --git a/public/app/plugins/panel/piechart/PieChart.tsx b/public/app/plugins/panel/piechart/PieChart.tsx index 70c2adeb175..71a0c63c2db 100644 --- a/public/app/plugins/panel/piechart/PieChart.tsx +++ b/public/app/plugins/panel/piechart/PieChart.tsx @@ -118,7 +118,7 @@ export const PieChart: FC = ({ if (arc.data.hasLinks && arc.data.getLinks) { return ( - + {(api) => ( > { if (hasLinks && getLinks) { return ( - + {(api) => { return this.renderComponent(valueProps, api); }}