Commit 2c4899a4 by Alex Khomenko Committed by GitHub

Grafana UI: Card API refactor (#29034)

* Refactor API

* Fix types

* Cleanup

* Remove useMemo

* Update actions

* Update story

* Align secondary actions

* Replace snapshot tests

* Update docs

* Update packages/grafana-ui/src/components/Card/Card.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Allow overriding child props

* Fix types and remove alpha tags

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
parent 6d0a98b2
import React from 'react';
import { boolean } from '@storybook/addon-knobs';
import { action } from '@storybook/addon-actions';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { Card } from './Card';
import mdx from './Card.mdx';
import { Button } from '../Button';
import { IconButton } from '../IconButton/IconButton';
import { TagList } from '../Tags/TagList';
const logo = 'https://grafana.com/static/assets/img/apple-touch-icon.png';
......@@ -63,58 +65,57 @@ export const WithTooltip = () => {
export const WithTags = () => {
const { disabled } = getKnobs();
return (
<Card
heading="Elasticsearch – Custom Templated Query"
metadata="Elastic Search"
tags={['elasticsearch', 'test', 'testdata']}
disabled={disabled}
/>
<Card heading="Elasticsearch – Custom Templated Query" disabled={disabled}>
<Card.Meta>Elastic Search</Card.Meta>
<Card.Tags>
<TagList tags={['elasticsearch', 'test', 'testdata']} onClick={tag => console.log('tag', tag)} />
</Card.Tags>
</Card>
);
};
export const WithMedia = () => {
const { disabled } = getKnobs();
return (
<Card
href="https://ops-us-east4.grafana.net/api/prom"
heading="1-ops-tools1-fallback"
metadata={[
'Prometheus',
<Card href="https://ops-us-east4.grafana.net/api/prom" heading="1-ops-tools1-fallback" disabled={disabled}>
<Card.Meta>
Prometheus
<a key="link2" href="https://ops-us-east4.grafana.net/api/prom">
https://ops-us-east4.grafana.net/api/prom
</a>,
]}
disabled={disabled}
image={<img src={logo} alt="Prometheus Logo" />}
/>
</a>
</Card.Meta>
<Card.Figure>
<img src={logo} alt="Prometheus Logo" />
</Card.Figure>
</Card>
);
};
export const WithActions = () => {
const { disabled } = getKnobs();
return (
<Card
heading="1-ops-tools1-fallback"
metadata={[
'Prometheus',
<a key="link" href="https://ops-us-east4.grafana.net/api/prom">
<Card heading="1-ops-tools1-fallback" disabled={disabled}>
<Card.Meta>
Prometheus
<a key="link2" href="https://ops-us-east4.grafana.net/api/prom">
https://ops-us-east4.grafana.net/api/prom
</a>,
]}
disabled={disabled}
image={<img src={logo} alt="Prometheus Logo" />}
actions={[
</a>
</Card.Meta>
<Card.Figure>
<img src={logo} alt="Prometheus Logo" />
</Card.Figure>
<Card.Actions>
<Button key="settings" variant="secondary">
Settings
</Button>,
</Button>
<Button key="explore" variant="secondary">
Explore
</Button>,
]}
secondaryActions={[
<IconButton key="showAll" name="apps" tooltip="Show all dashboards for this data source" />,
<IconButton key="delete" name="trash-alt" tooltip="Delete this data source" />,
]}
/>
</Button>
</Card.Actions>
<Card.SecondaryActions>
<IconButton key="showAll" name="apps" tooltip="Show all dashboards for this data source" />
<IconButton key="delete" name="trash-alt" tooltip="Delete this data source" />
</Card.SecondaryActions>
</Card>
);
};
......@@ -124,33 +125,36 @@ export const Full = () => {
return (
<Card
heading="Card title"
metadata={[
'Subtitle',
'Meta info 1',
'Meta info 2',
<a key="link" href="https://ops-us-east4.grafana.net/api/prom">
https://ops-us-east4.grafana.net/api/prom
</a>,
]}
disabled={disabled}
image={<img src={logo} alt="Prometheus Logo" />}
tags={['firing', 'active', 'test', 'testdata', 'prometheus']}
description="Description, body text. Greetings! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
actions={[
>
<Card.Meta>
{['Subtitle', 'Meta info 1', 'Meta info 2']}
<a key="link" href="https://ops-us-east4.grafana.net/api/prom">
https://ops-us-east4.grafana.net/api/prom
</a>
</Card.Meta>
<Card.Figure>
<img src={logo} alt="Prometheus Logo" />
</Card.Figure>
<Card.Tags>
<TagList tags={['firing', 'active', 'test', 'testdata', 'prometheus']} onClick={action('Clicked tag')} />
</Card.Tags>
<Card.Actions>
<Button key="settings" variant="secondary">
Main action
</Button>,
</Button>
<Button key="explore" variant="secondary">
2nd action
</Button>,
]}
secondaryActions={[
<IconButton key="comment-alt" name="comment-alt" tooltip="Tooltip content" />,
<IconButton key="copy" name="copy" tooltip="Tooltip content" />,
<IconButton key="link" name="link" tooltip="Tooltip content" />,
<IconButton key="star" name="star" tooltip="Tooltip content" />,
<IconButton key="delete" name="trash-alt" tooltip="Delete this data source" />,
]}
/>
</Button>
</Card.Actions>
<Card.SecondaryActions>
<IconButton key="comment-alt" name="comment-alt" tooltip="Tooltip content" />
<IconButton key="copy" name="copy" tooltip="Tooltip content" />
<IconButton key="link" name="link" tooltip="Tooltip content" />
<IconButton key="star" name="star" tooltip="Tooltip content" />
<IconButton key="delete" name="trash-alt" tooltip="Delete this data source" />
</Card.SecondaryActions>
</Card>
);
};
import React from 'react';
import { shallow } from 'enzyme';
import { render, screen, fireEvent } from '@testing-library/react';
import AlertRuleItem, { Props } from './AlertRuleItem';
jest.mock('react-redux', () => ({
connect: () => (params: any) => params,
}));
const setup = (propOverrides?: object) => {
const props: Props = {
rule: {
......@@ -26,13 +22,20 @@ const setup = (propOverrides?: object) => {
Object.assign(props, propOverrides);
return shallow(<AlertRuleItem {...props} />);
return render(<AlertRuleItem {...props} />);
};
describe('Render', () => {
describe('AlertRuleItem', () => {
it('should render component', () => {
const wrapper = setup();
const mockToggle = jest.fn();
setup({ onTogglePause: mockToggle });
expect(screen.getByText('Some rule')).toBeInTheDocument();
expect(screen.getByText('state text')).toBeInTheDocument();
expect(screen.getByText('Pause')).toBeInTheDocument();
expect(screen.getByText('Edit alert')).toBeInTheDocument();
expect(wrapper).toMatchSnapshot();
fireEvent.click(screen.getByText('Pause'));
expect(mockToggle).toHaveBeenCalled();
});
});
......@@ -31,21 +31,20 @@ const AlertRuleItem = ({ rule, search, onTogglePause }: Props) => {
width: 100%;
`}
>
<Card
heading={<a href={ruleUrl}>{renderText(rule.name)}</a>}
image={
<Card heading={<a href={ruleUrl}>{renderText(rule.name)}</a>}>
<Card.Figure>
<Icon size="xl" name={rule.stateIcon as IconName} className={`alert-rule-item__icon ${rule.stateClass}`} />
}
metadata={[
</Card.Figure>
<Card.Meta>
<span key="state">
<span key="text" className={`${rule.stateClass}`}>
{renderText(rule.stateText)}{' '}
</span>
for {rule.stateAge}
</span>,
rule.info ? renderText(rule.info) : null,
]}
actions={[
</span>
{rule.info ? renderText(rule.info) : null}
</Card.Meta>
<Card.Actions>
<Button
key="play"
variant="secondary"
......@@ -53,12 +52,12 @@ const AlertRuleItem = ({ rule, search, onTogglePause }: Props) => {
onClick={onTogglePause}
>
{rule.state === 'paused' ? 'Resume' : 'Pause'}
</Button>,
</Button>
<LinkButton key="edit" variant="secondary" href={ruleUrl} icon="cog">
Edit alert
</LinkButton>,
]}
/>
</LinkButton>
</Card.Actions>
</Card>
</li>
);
};
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render component 1`] = `
<li
className="css-1aih96i"
>
<Component
actions={
Array [
<Button
icon="pause"
onClick={[MockFunction]}
variant="secondary"
>
Pause
</Button>,
<LinkButton
href="https://something.something.darkside?editPanel=1&tab=alert"
icon="cog"
variant="secondary"
>
Edit alert
</LinkButton>,
]
}
heading={
<a
href="https://something.something.darkside?editPanel=1&tab=alert"
>
<Highlighter
highlightClassName="highlight-search-match"
searchWords={
Array [
"",
]
}
textToHighlight="Some rule"
/>
</a>
}
image={
<Icon
className="alert-rule-item__icon state class"
name="icon"
size="xl"
/>
}
metadata={
Array [
<span>
<span
className="state class"
>
<Highlighter
highlightClassName="highlight-search-match"
searchWords={
Array [
"",
]
}
textToHighlight="state text"
/>
</span>
for
age
</span>,
null,
]
}
/>
</li>
`;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment