123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- import { css } from '@emotion/css';
- import React, { useEffect, useState, useCallback, useMemo } from 'react';
- import { GrafanaTheme2 } from '@grafana/data';
- import { Icon, IconButton, IconName, useStyles2, useTheme2 } from '@grafana/ui';
- import { appEvents } from 'app/core/core';
- import { PageBannerDisplayEvent, PageBannerEventPayload, PageBannerSeverity } from './types';
- export function PageBanner(): React.ReactElement | null {
- const [banner, setBanner] = useState<PageBannerEventPayload | undefined>();
- const severityStyling = useStylingBySeverity(banner?.severity);
- const styles = useStyles2((theme) => getStyles(theme, severityStyling));
- useEffect(() => {
- const sub = appEvents.subscribe(PageBannerDisplayEvent, (event) => {
- setBanner(event.payload);
- });
- return sub.unsubscribe;
- }, [setBanner]);
- const onClose = useCallback(() => {
- setBanner(undefined);
- if (banner?.onClose) {
- banner.onClose();
- }
- }, [banner]);
- if (!banner) {
- return null;
- }
- const BannerBody = banner.body;
- return (
- <div className={styles.banner}>
- <div className={styles.icon}>
- <Icon size="xl" name={severityStyling.icon} />
- </div>
- <div className={styles.content}>
- <BannerBody severity={banner.severity ?? PageBannerSeverity.info} />
- </div>
- {banner?.onClose && (
- <div className={styles.icon}>
- <IconButton size="xl" name="times" onClick={onClose} className={styles.close} />
- </div>
- )}
- </div>
- );
- }
- type SeverityStyling = {
- text: string;
- background: string;
- icon: IconName;
- };
- function useStylingBySeverity(severity: PageBannerSeverity | undefined): SeverityStyling {
- const theme = useTheme2();
- return useMemo(() => {
- switch (severity) {
- case PageBannerSeverity.error:
- return {
- icon: 'exclamation-triangle',
- background: theme.colors.error.main,
- text: theme.colors.error.contrastText,
- };
- case PageBannerSeverity.warning:
- return {
- icon: 'exclamation-triangle',
- background: theme.colors.warning.main,
- text: theme.colors.warning.contrastText,
- };
- case PageBannerSeverity.info:
- default:
- return {
- icon: 'info-circle',
- background: theme.colors.info.main,
- text: theme.colors.info.contrastText,
- };
- }
- }, [theme, severity]);
- }
- function getStyles(theme: GrafanaTheme2, severityStyling: SeverityStyling) {
- return {
- banner: css`
- flex-grow: 0;
- flex-shrink: 0;
- display: flex;
- align-items: center;
- background-color: ${severityStyling.background};
- border-radius: 2px;
- height: 52px;
- `,
- icon: css`
- padding: ${theme.spacing(0, 2)};
- color: ${severityStyling.text};
- display: flex;
- `,
- content: css`
- flex-grow: 1;
- display: flex;
- align-items: center;
- color: ${severityStyling.text};
- `,
- close: css`
- color: ${severityStyling.text};
- `,
- };
- }
- // Uncomment to test this banner
- // setTimeout(() => {
- // appEvents.publish(
- // new PageBannerDisplayEvent({
- // onClose: () => {},
- // body: function test() {
- // return (
- // <div>
- // This is a warning that you will be suspended{' '}
- // <Button fill="outline" variant="secondary">
- // Upgrade to Pro
- // </Button>
- // </div>
- // );
- // },
- // })
- // );
- // }, 3000);
|