2022-07-06 10:00:56 -05:00
|
|
|
import { css } from '@emotion/css';
|
|
|
|
import React from 'react';
|
|
|
|
|
|
|
|
import { NavModelItem, GrafanaTheme2 } from '@grafana/data';
|
|
|
|
import { useStyles2 } from '@grafana/ui';
|
|
|
|
|
2022-11-09 03:05:01 -06:00
|
|
|
import { PageInfo } from '../PageInfo/PageInfo';
|
2022-10-11 05:45:58 -05:00
|
|
|
|
2023-05-31 11:03:54 -05:00
|
|
|
import { EditableTitle } from './EditableTitle';
|
2023-04-24 10:41:32 -05:00
|
|
|
import { PageInfoItem } from './types';
|
|
|
|
|
2022-07-06 10:00:56 -05:00
|
|
|
export interface Props {
|
|
|
|
navItem: NavModelItem;
|
2022-11-09 03:05:01 -06:00
|
|
|
renderTitle?: (title: string) => React.ReactNode;
|
|
|
|
actions?: React.ReactNode;
|
|
|
|
info?: PageInfoItem[];
|
2022-07-19 10:46:04 -05:00
|
|
|
subTitle?: React.ReactNode;
|
2023-05-31 11:03:54 -05:00
|
|
|
onEditTitle?: (newValue: string) => Promise<void>;
|
2022-07-06 10:00:56 -05:00
|
|
|
}
|
|
|
|
|
2023-05-31 11:03:54 -05:00
|
|
|
export function PageHeader({ navItem, renderTitle, actions, info, subTitle, onEditTitle }: Props) {
|
2022-07-06 10:00:56 -05:00
|
|
|
const styles = useStyles2(getStyles);
|
2023-02-08 07:15:37 -06:00
|
|
|
const sub = subTitle ?? navItem.subTitle;
|
2022-07-06 10:00:56 -05:00
|
|
|
|
2023-05-31 11:03:54 -05:00
|
|
|
const titleElement = onEditTitle ? (
|
|
|
|
<EditableTitle value={navItem.text} onEdit={onEditTitle} />
|
|
|
|
) : (
|
|
|
|
<div className={styles.title}>
|
|
|
|
{navItem.img && <img className={styles.img} src={navItem.img} alt={`logo for ${navItem.text}`} />}
|
|
|
|
{renderTitle ? renderTitle(navItem.text) : <h1>{navItem.text}</h1>}
|
|
|
|
</div>
|
|
|
|
);
|
2022-11-09 03:05:01 -06:00
|
|
|
|
2022-07-06 10:00:56 -05:00
|
|
|
return (
|
2022-11-09 03:05:01 -06:00
|
|
|
<div className={styles.pageHeader}>
|
|
|
|
<div className={styles.topRow}>
|
|
|
|
<div className={styles.titleInfoContainer}>
|
2023-05-31 11:03:54 -05:00
|
|
|
{titleElement}
|
2022-11-09 03:05:01 -06:00
|
|
|
{info && <PageInfo info={info} />}
|
|
|
|
</div>
|
|
|
|
<div className={styles.actions}>{actions}</div>
|
|
|
|
</div>
|
|
|
|
{sub && <div className={styles.subTitle}>{sub}</div>}
|
|
|
|
</div>
|
2022-07-06 10:00:56 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const getStyles = (theme: GrafanaTheme2) => {
|
|
|
|
return {
|
2022-11-09 03:05:01 -06:00
|
|
|
topRow: css({
|
2023-05-31 11:03:54 -05:00
|
|
|
alignItems: 'flex-start',
|
2022-11-09 03:05:01 -06:00
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'row',
|
|
|
|
flexWrap: 'wrap',
|
2023-05-23 08:18:00 -05:00
|
|
|
gap: theme.spacing(1, 3),
|
2022-11-09 03:05:01 -06:00
|
|
|
}),
|
|
|
|
title: css({
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'row',
|
2023-05-03 10:19:56 -05:00
|
|
|
h1: {
|
|
|
|
display: 'flex',
|
|
|
|
marginBottom: 0,
|
|
|
|
},
|
2022-11-09 03:05:01 -06:00
|
|
|
}),
|
|
|
|
actions: css({
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'row',
|
|
|
|
gap: theme.spacing(1),
|
|
|
|
}),
|
|
|
|
titleInfoContainer: css({
|
|
|
|
display: 'flex',
|
|
|
|
label: 'title-info-container',
|
|
|
|
flex: 1,
|
|
|
|
flexWrap: 'wrap',
|
|
|
|
gap: theme.spacing(1, 4),
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
maxWidth: '100%',
|
2023-05-31 11:03:54 -05:00
|
|
|
minWidth: '300px',
|
2022-11-09 03:05:01 -06:00
|
|
|
}),
|
|
|
|
pageHeader: css({
|
|
|
|
label: 'page-header',
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'column',
|
|
|
|
gap: theme.spacing(1),
|
2022-11-11 08:43:11 -06:00
|
|
|
marginBottom: theme.spacing(2),
|
2022-11-09 03:05:01 -06:00
|
|
|
}),
|
|
|
|
subTitle: css({
|
2022-07-06 10:00:56 -05:00
|
|
|
position: 'relative',
|
|
|
|
color: theme.colors.text.secondary,
|
|
|
|
}),
|
2022-11-09 03:05:01 -06:00
|
|
|
img: css({
|
2022-07-06 10:00:56 -05:00
|
|
|
width: '32px',
|
|
|
|
height: '32px',
|
|
|
|
marginRight: theme.spacing(2),
|
|
|
|
}),
|
|
|
|
};
|
|
|
|
};
|