DataLinks: Bring back single click links for Stat, Gauge and BarGauge panel (#31692)

* Bring back clickable Stat, Gauge and BarGauge panels

* Demo dashboard

* Add DataLinksContextMenu tests

* Only use new UI for data links, revert panel links logic
This commit is contained in:
Dominik Prokop 2021-03-05 10:29:19 +01:00 committed by GitHub
parent bbee7da3e0
commit fdc6f2cc6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 1307 additions and 15 deletions

File diff suppressed because it is too large Load Diff

View File

@ -181,4 +181,7 @@ export const Components = {
CallToActionCard: { CallToActionCard: {
button: (name: string) => `Call to action button ${name}`, button: (name: string) => `Call to action button ${name}`,
}, },
DataLinksContextMenu: {
singleLink: 'Data link',
},
}; };

View File

@ -0,0 +1,77 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { DataLinksContextMenu } from './DataLinksContextMenu';
import { selectors } from '@grafana/e2e-selectors';
const fakeAriaLabel = 'fake aria label';
describe('DataLinksContextMenu', () => {
it('renders context menu when there are more than one data links', () => {
render(
<DataLinksContextMenu
links={() => [
{
href: '/link1',
title: 'Link1',
target: '_blank',
origin: {},
},
{
href: '/link2',
title: 'Link2',
target: '_blank',
origin: {},
},
]}
config={{
links: [
{
title: 'Link1',
url: '/link1',
},
{
title: 'Link2',
url: '/link2',
},
],
}}
>
{() => {
return <div aria-label="fake aria label" />;
}}
</DataLinksContextMenu>
);
expect(screen.getByLabelText(fakeAriaLabel)).toBeInTheDocument();
expect(screen.queryAllByLabelText(selectors.components.DataLinksContextMenu.singleLink)).toHaveLength(0);
});
it('renders link when there is a single data link', () => {
render(
<DataLinksContextMenu
links={() => [
{
href: '/link1',
title: 'Link1',
target: '_blank',
origin: {},
},
]}
config={{
links: [
{
title: 'Link1',
url: '/link1',
},
],
}}
>
{() => {
return <div aria-label="fake aria label" />;
}}
</DataLinksContextMenu>
);
expect(screen.getByLabelText(fakeAriaLabel)).toBeInTheDocument();
expect(screen.getByLabelText(selectors.components.DataLinksContextMenu.singleLink)).toBeInTheDocument();
});
});

View File

@ -1,12 +1,14 @@
import React from 'react'; import React from 'react';
import { WithContextMenu } from '../ContextMenu/WithContextMenu'; import { FieldConfig, LinkModel } from '@grafana/data';
import { LinkModel } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors';
import { linkModelToContextMenuItems } from '../../utils/dataLinks';
import { css } from 'emotion'; import { css } from 'emotion';
import { WithContextMenu } from '../ContextMenu/WithContextMenu';
import { linkModelToContextMenuItems } from '../../utils/dataLinks';
interface DataLinksContextMenuProps { interface DataLinksContextMenuProps {
children: (props: DataLinksContextMenuApi) => JSX.Element; children: (props: DataLinksContextMenuApi) => JSX.Element;
links: () => LinkModel[]; links: () => LinkModel[];
config: FieldConfig;
} }
export interface DataLinksContextMenuApi { export interface DataLinksContextMenuApi {
@ -14,7 +16,8 @@ export interface DataLinksContextMenuApi {
targetClassName?: string; targetClassName?: string;
} }
export const DataLinksContextMenu: React.FC<DataLinksContextMenuProps> = ({ children, links }) => { export const DataLinksContextMenu: React.FC<DataLinksContextMenuProps> = ({ children, links, config }) => {
const linksCounter = config.links!.length;
const getDataLinksContextMenuItems = () => { const getDataLinksContextMenuItems = () => {
return [{ items: linkModelToContextMenuItems(links), label: 'Data links' }]; return [{ items: linkModelToContextMenuItems(links), label: 'Data links' }];
}; };
@ -24,6 +27,7 @@ export const DataLinksContextMenu: React.FC<DataLinksContextMenuProps> = ({ chil
cursor: context-menu; cursor: context-menu;
`; `;
if (linksCounter > 1) {
return ( return (
<WithContextMenu getContextMenuItems={getDataLinksContextMenuItems}> <WithContextMenu getContextMenuItems={getDataLinksContextMenuItems}>
{({ openMenu }) => { {({ openMenu }) => {
@ -31,4 +35,19 @@ export const DataLinksContextMenu: React.FC<DataLinksContextMenuProps> = ({ chil
}} }}
</WithContextMenu> </WithContextMenu>
); );
} else {
const linkModel = links()[0];
return (
<a
href={linkModel.href}
onClick={linkModel.onClick}
target={linkModel.target}
title={linkModel.title}
style={{ display: 'flex' }}
aria-label={selectors.components.DataLinksContextMenu.singleLink}
>
{children({})}
</a>
);
}
}; };

View File

@ -57,14 +57,13 @@ export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> {
if (hasLinks && getLinks) { if (hasLinks && getLinks) {
return ( return (
<DataLinksContextMenu links={getLinks}> <DataLinksContextMenu links={getLinks} config={value.field}>
{(api) => { {(api) => {
return this.renderComponent(valueProps, api); return this.renderComponent(valueProps, api);
}} }}
</DataLinksContextMenu> </DataLinksContextMenu>
); );
} }
return this.renderComponent(valueProps, {}); return this.renderComponent(valueProps, {});
}; };

View File

@ -39,7 +39,7 @@ export class GaugePanel extends PureComponent<PanelProps<GaugeOptions>> {
if (hasLinks && getLinks) { if (hasLinks && getLinks) {
return ( return (
<DataLinksContextMenu links={getLinks}> <DataLinksContextMenu links={getLinks} config={value.field}>
{(api) => { {(api) => {
return this.renderComponent(valueProps, api); return this.renderComponent(valueProps, api);
}} }}

View File

@ -69,7 +69,7 @@ export class StatPanel extends PureComponent<PanelProps<StatPanelOptions>> {
if (hasLinks && getLinks) { if (hasLinks && getLinks) {
return ( return (
<DataLinksContextMenu links={getLinks}> <DataLinksContextMenu links={getLinks} config={value.field}>
{(api) => { {(api) => {
return this.renderComponent(valueProps, api); return this.renderComponent(valueProps, api);
}} }}