1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-31 13:47:02 +02:00

Insights UI improvements (#6433)

- improved page header
- added help text to health and metrics
- updated style for flag stats widget
- fixed users widget shadow
This commit is contained in:
Tymoteusz Czech 2024-03-06 12:19:27 +01:00 committed by GitHub
parent 2185742b1d
commit 85e9c934a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 105 additions and 37 deletions

View File

@ -49,7 +49,7 @@ export const ExecutiveDashboard: VFC = () => {
const stateConfig = { const stateConfig = {
projects: withDefault(ArrayParam, [allOption.id]), projects: withDefault(ArrayParam, [allOption.id]),
}; };
const [state, setState] = usePersistentTableState(`insights`, stateConfig); const [state, setState] = usePersistentTableState('insights', stateConfig);
const setProjects = (projects: string[]) => { const setProjects = (projects: string[]) => {
setState({ projects }); setState({ projects });
}; };
@ -79,7 +79,7 @@ export const ExecutiveDashboard: VFC = () => {
selectedProjects={projects} selectedProjects={projects}
onChange={setProjects} onChange={setProjects}
dataTestId={'DASHBOARD_PROJECT_SELECT'} dataTestId={'DASHBOARD_PROJECT_SELECT'}
sx={{ flex: 1, maxWidth: '360px' }} sx={{ flex: 1, maxWidth: '360px', width: '100%' }}
/> />
} }
/> />
@ -157,7 +157,10 @@ export const ExecutiveDashboard: VFC = () => {
</ChartWidget> </ChartWidget>
} }
/> />
<Widget title='Average health'> <Widget
title='Average health'
tooltip='Average health is a percentage of flags that are not stale nor potencially stale.'
>
<HealthStats <HealthStats
value={summary.averageHealth} value={summary.averageHealth}
healthy={summary.active} healthy={summary.active}
@ -185,7 +188,10 @@ export const ExecutiveDashboard: VFC = () => {
<TimeToProductionChart projectFlagTrends={projectsData} /> <TimeToProductionChart projectFlagTrends={projectsData} />
</ChartWidget> */} </ChartWidget> */}
</StyledGrid> </StyledGrid>
<Widget title='Metrics'> <Widget
title='Metrics'
tooltip='Summary of all flag evaluations reported by SDKs.'
>
<MetricsSummaryChart metricsSummaryTrends={metricsData} /> <MetricsSummaryChart metricsSummaryTrends={metricsData} />
</Widget> </Widget>
</> </>

View File

@ -2,17 +2,57 @@ import { ReactNode, VFC } from 'react';
import { useUiFlag } from 'hooks/useUiFlag'; import { useUiFlag } from 'hooks/useUiFlag';
import { useFeedback } from 'component/feedbackNew/useFeedback'; import { useFeedback } from 'component/feedbackNew/useFeedback';
import { ReviewsOutlined } from '@mui/icons-material'; import { ReviewsOutlined } from '@mui/icons-material';
import { Button, Typography } from '@mui/material'; import {
Button,
Typography,
styled,
useMediaQuery,
useTheme,
} from '@mui/material';
import { PageHeader } from 'component/common/PageHeader/PageHeader'; import { PageHeader } from 'component/common/PageHeader/PageHeader';
import { Badge } from 'component/common/Badge/Badge'; import { Badge } from 'component/common/Badge/Badge';
import { ShareLink } from './ShareLink/ShareLink'; import { ShareLink } from './ShareLink/ShareLink';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
type DashboardHeaderProps = { type DashboardHeaderProps = {
actions?: ReactNode; actions?: ReactNode;
}; };
const StyledActionsContainer = styled('div')(({ theme }) => ({
display: 'flex',
gap: theme.spacing(1),
[theme.breakpoints.down('md')]: {
flexDirection: 'column',
gap: theme.spacing(1),
},
}));
const StyledActionButtons = styled('div')(({ theme }) => ({
display: 'flex',
gap: theme.spacing(1),
}));
const StyledExternalActionsContainer = styled('div')(({ theme }) => ({
display: 'flex',
gap: theme.spacing(1),
width: 300,
[theme.breakpoints.down('md')]: {
width: '100%',
},
}));
const StyledActionsSmallScreen = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-end',
gap: theme.spacing(1),
marginTop: theme.spacing(2),
}));
export const DashboardHeader: VFC<DashboardHeaderProps> = ({ actions }) => { export const DashboardHeader: VFC<DashboardHeaderProps> = ({ actions }) => {
const showInactiveUsers = useUiFlag('showInactiveUsers'); const showInactiveUsers = useUiFlag('showInactiveUsers');
const theme = useTheme();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
const { openFeedback } = useFeedback( const { openFeedback } = useFeedback(
'insights', 'insights',
@ -29,6 +69,7 @@ export const DashboardHeader: VFC<DashboardHeaderProps> = ({ actions }) => {
}; };
return ( return (
<>
<PageHeader <PageHeader
titleElement={ titleElement={
<Typography <Typography
@ -40,12 +81,21 @@ export const DashboardHeader: VFC<DashboardHeaderProps> = ({ actions }) => {
gap: theme.spacing(1), gap: theme.spacing(1),
})} })}
> >
<span>Insights</span> <Badge color='success'>Beta</Badge> <span>Insights</span>{' '}
<Badge color='success'>Beta</Badge>
</Typography> </Typography>
} }
actions={ actions={
<> <StyledActionsContainer>
<ConditionallyRender
condition={!isSmallScreen}
show={
<StyledExternalActionsContainer>
{actions} {actions}
</StyledExternalActionsContainer>
}
/>
<StyledActionButtons>
<ShareLink /> <ShareLink />
<Button <Button
startIcon={<ReviewsOutlined />} startIcon={<ReviewsOutlined />}
@ -54,8 +104,18 @@ export const DashboardHeader: VFC<DashboardHeaderProps> = ({ actions }) => {
> >
Provide feedback Provide feedback
</Button> </Button>
</> </StyledActionButtons>
</StyledActionsContainer>
} }
/> />
<ConditionallyRender
condition={isSmallScreen}
show={
<StyledActionsSmallScreen>
{actions}
</StyledActionsSmallScreen>
}
/>
</>
); );
}; };

View File

@ -33,9 +33,9 @@ const StyledRingContent = styled(Box)(({ theme }) => ({
const StyledInsightsContainer = styled(Box)(({ theme }) => ({ const StyledInsightsContainer = styled(Box)(({ theme }) => ({
marginTop: theme.spacing(4), marginTop: theme.spacing(4),
padding: theme.spacing(1.5), padding: theme.spacing(1.5, 2),
background: theme.palette.background.elevation2, background: theme.palette.background.elevation2,
borderRadius: `${theme.shape.borderRadius}px`, borderRadius: `${theme.shape.borderRadiusMedium}px`,
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
})); }));
@ -43,6 +43,7 @@ const StyledInsightsContainer = styled(Box)(({ theme }) => ({
const StyledHeaderContainer = styled(Box)(({ theme }) => ({ const StyledHeaderContainer = styled(Box)(({ theme }) => ({
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
marginBottom: theme.spacing(0.5),
})); }));
const StyledTextContainer = styled(Box)(({ theme }) => ({ const StyledTextContainer = styled(Box)(({ theme }) => ({

View File

@ -13,22 +13,23 @@ const StyledUserContainer = styled(Box)(({ theme }) => ({
const StyledUserBox = styled(Box)(({ theme }) => ({ const StyledUserBox = styled(Box)(({ theme }) => ({
borderRadius: `${theme.shape.borderRadiusExtraLarge}px`, borderRadius: `${theme.shape.borderRadiusExtraLarge}px`,
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.background.alternative,
maxWidth: 300, maxWidth: 300,
padding: theme.spacing(2), padding: theme.spacing(2),
marginBottom: theme.spacing(3), margin: `0 auto ${theme.spacing(3)}`,
position: 'relative', position: 'relative',
zIndex: 2, zIndex: 2,
})); }));
const StyledCustomShadow = styled(Box)(({ theme }) => ({ const StyledCustomShadow = styled(Box)(({ theme }) => ({
width: '220px', maxWidth: 270,
height: '54px', height: '54px',
backgroundColor: 'rgba(108, 101, 229, 0.30)', backgroundColor: 'rgba(108, 101, 229, 0.30)',
position: 'absolute', position: 'absolute',
margin: '0 auto', margin: '0 auto',
top: '45px', top: '45px',
left: '15px', left: '15px',
right: '15px',
borderRadius: `${theme.shape.borderRadiusExtraLarge}px`, borderRadius: `${theme.shape.borderRadiusExtraLarge}px`,
zIndex: 1, zIndex: 1,
})); }));