1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-23 00:22:19 +01:00

feat: last usage metrics in project table (#6692)

![image](https://github.com/Unleash/unleash/assets/964450/342f43ed-ab81-4875-b855-5e59329288d8)
This commit is contained in:
Jaanus Sellin 2024-03-26 14:50:37 +02:00 committed by GitHub
parent d065905e73
commit dc64a81bb9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 96 additions and 22 deletions

View File

@ -1,10 +1,10 @@
import React, { type VFC } from 'react';
import { FeatureEnvironmentSeen } from 'component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen';
import type { FeatureEnvironmentSchema } from 'openapi';
import type { FeatureSearchEnvironmentSchema } from 'openapi';
interface IFeatureSeenCellProps {
feature: {
environments?: FeatureEnvironmentSchema[];
environments?: FeatureSearchEnvironmentSchema[];
lastSeenAt?: string | null;
};
}

View File

@ -0,0 +1,9 @@
import { screen } from '@testing-library/react';
import { render } from 'utils/testRenderer';
import { LastSeenProgress } from './LastSeenProgress';
test('Show last seen progress bar', async () => {
render(<LastSeenProgress yes={5} no={5} />);
await screen.findByText('50%');
});

View File

@ -0,0 +1,52 @@
import { styled, CircularProgress, Box } from '@mui/material';
const ProgressContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
gap: theme.spacing(1),
width: '20%',
justifyContent: 'flex-end',
}));
const BackgroundCircularProgress = styled(CircularProgress)(({ theme }) => ({
color: theme.palette.divider,
}));
const MainCircularProgress = styled(CircularProgress)(({ theme }) => ({
color: theme.palette.primary.main,
position: 'absolute',
left: 0,
}));
interface ILastSeenProgressProps {
yes: number | undefined;
no: number | undefined;
}
export const LastSeenProgress = ({ yes, no }: ILastSeenProgressProps) => {
const noData = yes === undefined || no === undefined || yes + no === 0;
if (noData) {
return <Box />;
}
const progress = (yes / (yes + no)) * 100;
return (
<ProgressContainer>
<Box sx={{ position: 'relative' }}>
<BackgroundCircularProgress
variant='determinate'
size={18}
thickness={11}
value={100}
/>
<MainCircularProgress
variant='determinate'
size={18}
thickness={11}
value={progress}
/>
</Box>
<Box>{progress}%</Box>
</ProgressContainer>
);
};

View File

@ -3,6 +3,7 @@ import TimeAgo from 'react-timeago';
import type { ILastSeenEnvironments } from 'interfaces/featureToggle';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useLastSeenColors } from 'component/feature/FeatureView/FeatureEnvironmentSeen/useLastSeenColors';
import { LastSeenProgress } from './LastSeenProgress/LastSeenProgress';
const StyledDescription = styled(
'div',
@ -17,15 +18,14 @@ const StyledDescription = styled(
borderRadius: theme.shape.borderRadiusMedium,
}));
const StyledDescriptionBlock = styled('div')({
const StyledDescriptionBlock = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
});
flexWrap: 'wrap',
}));
const StyledDescriptionHeader = styled('p')(({ theme }) => ({
color: theme.palette.text.primary,
fontSize: theme.fontSizes.smallBody,
fontWeight: theme.fontWeight.bold,
marginBottom: theme.spacing(1),
}));
@ -34,18 +34,18 @@ const StyledDescriptionBlockHeader = styled('p')(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
fontWeight: theme.fontWeight.bold,
marginBottom: theme.spacing(1),
width: '50%',
width: '40%',
justifyContent: 'flex-start',
}));
const StyledValueContainer = styled('div')({
width: '40%',
justifyContent: 'center',
});
const StyledDescriptionSubHeader = styled('p')(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
margin: theme.spacing(2, 0),
}));
const StyledValueContainer = styled('div')({
width: '50%',
});
const StyledValue = styled('div', {
shouldForwardProp: (prop) => prop !== 'color',
})(({ color }) => ({
@ -54,6 +54,12 @@ const StyledValue = styled('div', {
color: color,
}));
const StyledListContainer = styled('div')(({ theme }) => ({
maxHeight: theme.spacing(24.5),
overflowY: 'auto',
paddingRight: theme.spacing(2),
}));
interface ILastSeenTooltipProps {
featureLastSeen: string;
environments?: ILastSeenEnvironments[];
@ -73,19 +79,16 @@ export const LastSeenTooltip = ({
);
return (
<StyledDescription {...rest} data-loading>
<StyledDescriptionHeader sx={{ mb: 0 }}>
<StyledDescriptionHeader>
Last usage reported
</StyledDescriptionHeader>
<StyledDescriptionSubHeader>
Usage is reported from connected applications through metrics
</StyledDescriptionSubHeader>
<ConditionallyRender
condition={
Boolean(environments) && Boolean(environmentsHaveLastSeen)
}
show={
<>
{environments?.map(({ name, lastSeenAt }) => (
<StyledListContainer>
{environments?.map(({ name, lastSeenAt, yes, no }) => (
<StyledDescriptionBlock key={name}>
<StyledDescriptionBlockHeader>
{name}
@ -128,9 +131,10 @@ export const LastSeenTooltip = ({
}
/>
</StyledValueContainer>
<LastSeenProgress yes={yes} no={no} />
</StyledDescriptionBlock>
))}
</>
</StyledListContainer>
}
elseShow={
<TimeAgo
@ -156,6 +160,9 @@ export const LastSeenTooltip = ({
/>
}
/>
<StyledDescriptionSubHeader>
Usage is reported from connected applications through metrics
</StyledDescriptionSubHeader>
</StyledDescription>
);
};

View File

@ -46,6 +46,10 @@ const StyledIconWrapper = styled('div')(({ theme }) => ({
margin: '0 auto',
}));
const StyledTooltipResolver = styled(TooltipResolver)(({ theme }) => ({
maxWidth: theme.spacing(47.5),
}));
const TooltipContainer: FC<{
color?: string;
tooltip: ReactElement | string;
@ -53,7 +57,7 @@ const TooltipContainer: FC<{
}> = ({ sx, tooltip, color, children }) => {
return (
<StyledContainer sx={sx}>
<TooltipResolver
<StyledTooltipResolver
variant='custom'
titleComponent={tooltip}
arrow
@ -64,7 +68,7 @@ const TooltipContainer: FC<{
{children}
</StyledIconWrapper>
</StyledBox>
</TooltipResolver>
</StyledTooltipResolver>
</StyledContainer>
);
};

View File

@ -23,11 +23,13 @@ export interface IEnvironments {
type?: string;
hasStrategies?: boolean;
hasEnabledStrategies?: boolean;
yes?: number;
no?: number;
}
export type ILastSeenEnvironments = Pick<
IEnvironments,
'name' | 'enabled' | 'lastSeenAt'
'name' | 'enabled' | 'lastSeenAt' | 'yes' | 'no'
>;
export interface IFeatureToggle {