1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: licensed users chart (#8844)

Currently showing 2 lines, because backend is not sorting the data.


![image](https://github.com/user-attachments/assets/905001fb-2020-45b2-a1f4-ba497b594e61)
This commit is contained in:
Jaanus Sellin 2024-11-25 10:03:21 +02:00 committed by GitHub
parent f985cb1deb
commit 9a269e3597
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 104 additions and 18 deletions

View File

@ -0,0 +1,54 @@
import type { FC } from 'react';
import 'chartjs-adapter-date-fns';
import type { LicensedUsersSchema } from 'openapi';
import { LineChart } from 'component/insights/components/LineChart/LineChart';
import { useTheme } from '@mui/material';
interface ILicensedUsersChartProps {
licensedUsers: LicensedUsersSchema['licensedUsers']['history'];
}
export const LicensedUsersChart: FC<ILicensedUsersChartProps> = ({
licensedUsers,
}) => {
const theme = useTheme();
const data = {
datasets: [
{
label: 'Licensed users',
data: licensedUsers,
borderColor: theme.palette.primary.main,
backgroundColor: theme.palette.primary.main,
fill: false,
},
],
};
return (
<LineChart
data={data}
overrideOptions={{
parsing: {
yAxisKey: 'count',
xAxisKey: 'date',
},
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
time: {
unit: 'month',
tooltipFormat: 'MMM yyyy',
displayFormats: {
month: 'MMM',
},
},
},
},
}}
/>
);
};

View File

@ -1,6 +1,8 @@
import { Alert, Button, styled, Typography } from '@mui/material';
import { DynamicSidebarModal } from 'component/common/SidebarModal/SidebarModal';
import type React from 'react';
import { LicensedUsersChart } from './LicensedUsersChart';
import { useLicensedUsers } from 'hooks/useLicensedUsers';
const ModalContentContainer = styled('section')(({ theme }) => ({
minHeight: '100vh',
maxWidth: 700,
@ -74,6 +76,7 @@ export const LicensedUsersSidebar = ({
open,
close,
}: LicensedUsersSidebarProps) => {
const { data } = useLicensedUsers();
return (
<DynamicSidebarModal
open={open}
@ -94,7 +97,10 @@ export const LicensedUsersSidebar = ({
<RowHeader>Last 30 days</RowHeader>
<InfoRow>
<LicenceBox>
<Typography fontWeight='bold'>11/25</Typography>
<Typography fontWeight='bold'>
{data.licensedUsers.current}/
{data.seatCount}
</Typography>
<Typography variant='body2'>
Used seats last 30 days
</Typography>
@ -108,7 +114,9 @@ export const LicensedUsersSidebar = ({
</Row>
<Row>
<RowHeader>Last year</RowHeader>
<div>this will be great grid</div>
<LicensedUsersChart
licensedUsers={data.licensedUsers.history}
/>
</Row>
</WidgetContainer>
<CloseRow>

View File

@ -24,6 +24,7 @@ import {
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { styled } from '@mui/material';
import { createOptions } from './createChartOptions';
import merge from 'deepmerge';
const StyledContainer = styled('div')(({ theme }) => ({
position: 'relative',
@ -81,6 +82,10 @@ const customHighlightPlugin = {
},
};
function mergeAll<T>(objects: Partial<T>[]): T {
return merge.all<T>(objects.filter((i) => i));
}
const LineChartComponent: FC<{
data: ChartData<'line', unknown>;
aspectRatio?: number;
@ -100,16 +105,18 @@ const LineChartComponent: FC<{
const { locationSettings } = useLocationSettings();
const [tooltip, setTooltip] = useState<null | TooltipState>(null);
const options = useMemo(
() => ({
...createOptions(
theme,
locationSettings,
setTooltip,
Boolean(cover),
),
...overrideOptions,
}),
() =>
mergeAll([
createOptions(
theme,
locationSettings,
setTooltip,
Boolean(cover),
),
overrideOptions ?? {},
]),
[theme, locationSettings, overrideOptions, cover],
);

View File

@ -3,13 +3,14 @@ import type { ILocationSettings } from 'hooks/useLocationSettings';
import type { TooltipState } from './ChartTooltip/ChartTooltip';
import { createTooltip } from './createTooltip';
import { legendOptions } from './legendOptions';
import type { ChartOptions } from 'chart.js';
export const createOptions = (
theme: Theme,
locationSettings: ILocationSettings,
setTooltip: React.Dispatch<React.SetStateAction<TooltipState | null>>,
isPlaceholder?: boolean,
) =>
): ChartOptions<'line'> =>
({
responsive: true,
...(isPlaceholder
@ -27,10 +28,6 @@ export const createOptions = (
tooltip: {
enabled: false,
position: 'nearest',
interaction: {
axis: 'xy',
mode: 'nearest',
},
external: createTooltip(setTooltip),
},
},
@ -46,8 +43,6 @@ export const createOptions = (
hitRadius: 15,
},
},
// cubicInterpolationMode: 'monotone',
tension: 0.1,
color: theme.palette.text.secondary,
scales: {
y: {

View File

@ -0,0 +1,22 @@
import type { LicensedUsersSchema } from '../openapi';
import { useApiGetter, fetcher } from './api/getters/useApiGetter/useApiGetter';
import { formatApiPath } from '../utils/formatPath';
const path = `api/admin/licensed-users`;
const placeholderData: LicensedUsersSchema = {
seatCount: 0,
licensedUsers: {
current: 0,
history: [],
},
};
export const useLicensedUsers = () => {
const { data, refetch, loading, error } = useApiGetter<LicensedUsersSchema>(
formatApiPath(path),
() => fetcher(formatApiPath(path), 'Licensed users'),
);
return { data: data || placeholderData, refetch, loading, error };
};