mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Add new PageInfo component (#58421)
This commit is contained in:
parent
f07da85d8b
commit
831ecb467c
@ -22,6 +22,11 @@ export interface PageProps extends HTMLAttributes<HTMLDivElement> {
|
|||||||
scrollTop?: number;
|
scrollTop?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PageInfoItem {
|
||||||
|
label: string;
|
||||||
|
value: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PageType extends FC<PageProps> {
|
export interface PageType extends FC<PageProps> {
|
||||||
Header: typeof PageHeader;
|
Header: typeof PageHeader;
|
||||||
OldNavOnly: typeof OldNavOnly;
|
OldNavOnly: typeof OldNavOnly;
|
||||||
|
62
public/app/core/components/PageInfo/PageInfo.test.tsx
Normal file
62
public/app/core/components/PageInfo/PageInfo.test.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { PageInfoItem } from '../Page/types';
|
||||||
|
|
||||||
|
import { PageInfo } from './PageInfo';
|
||||||
|
|
||||||
|
describe('PageInfo', () => {
|
||||||
|
it('renders the label and value for each info item', () => {
|
||||||
|
const info: PageInfoItem[] = [
|
||||||
|
{
|
||||||
|
label: 'label1',
|
||||||
|
value: 'value1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'label2',
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
render(<PageInfo info={info} />);
|
||||||
|
|
||||||
|
// Check labels are visible
|
||||||
|
expect(screen.getByText('label1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('label2')).toBeInTheDocument();
|
||||||
|
|
||||||
|
// Check values are visible
|
||||||
|
expect(screen.getByText('value1')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('2')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can render a custom element as a value', () => {
|
||||||
|
const info: PageInfoItem[] = [
|
||||||
|
{
|
||||||
|
label: 'label1',
|
||||||
|
value: <div data-testid="custom-value">value1</div>,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
render(<PageInfo info={info} />);
|
||||||
|
|
||||||
|
expect(screen.getByTestId('custom-value')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders separators between the info items', () => {
|
||||||
|
const info: PageInfoItem[] = [
|
||||||
|
{
|
||||||
|
label: 'label1',
|
||||||
|
value: 'value1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'label2',
|
||||||
|
value: 'value2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'label3',
|
||||||
|
value: 'value3',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
render(<PageInfo info={info} />);
|
||||||
|
|
||||||
|
expect(screen.getAllByTestId('page-info-separator')).toHaveLength(info.length - 1);
|
||||||
|
});
|
||||||
|
});
|
52
public/app/core/components/PageInfo/PageInfo.tsx
Normal file
52
public/app/core/components/PageInfo/PageInfo.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
|
import { useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
|
import { PageInfoItem } from '../Page/types';
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
info: PageInfoItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PageInfo({ info }: Props) {
|
||||||
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
{info.map((infoItem, index) => (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
<div className={styles.infoItem}>
|
||||||
|
<div className={styles.label}>{infoItem.label}</div>
|
||||||
|
{infoItem.value}
|
||||||
|
</div>
|
||||||
|
{index + 1 < info.length && <div data-testid="page-info-separator" className={styles.separator} />}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStyles = (theme: GrafanaTheme2) => {
|
||||||
|
return {
|
||||||
|
container: css({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: theme.spacing(1.5),
|
||||||
|
overflow: 'auto',
|
||||||
|
}),
|
||||||
|
infoItem: css({
|
||||||
|
...theme.typography.bodySmall,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: theme.spacing(0.5),
|
||||||
|
}),
|
||||||
|
label: css({
|
||||||
|
color: theme.colors.text.secondary,
|
||||||
|
}),
|
||||||
|
separator: css({
|
||||||
|
borderLeft: `1px solid ${theme.colors.border.weak}`,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user