mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-27 01:19:00 +02:00
Chore: add skeleton loaders for lifecycle trend numbers (#10103)
Adds skeleton loading indicators for the lifecycle trend tile numbers: - total flag count - median stats In doing so, I have added the `data-loading` attribute to the PrettifyLargeNumber component (to avoid having to wrap it in a separate element for that alone), and have added refs to the InsightsSection component. The loading indicators look better in dark mode than in light mode, because they use the same background color as the text box in light mode, so only the big number is visible. There is a task in Linear to look into fixing this. <img width="1548" alt="image" src="https://github.com/user-attachments/assets/9e58d681-724e-45cb-baa1-b824dda48008" /> <img width="1554" alt="image" src="https://github.com/user-attachments/assets/7738fac0-5660-464f-8d10-1bf2eacc9ca0" /> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
6d7a344ca3
commit
45d48d12a9
@ -19,6 +19,10 @@ interface IPrettifyLargeNumberProps {
|
||||
* @default 2
|
||||
*/
|
||||
precision?: number;
|
||||
/**
|
||||
* Data attribute for loading state
|
||||
*/
|
||||
'data-loading'?: string;
|
||||
}
|
||||
|
||||
export const prettifyLargeNumber =
|
||||
@ -34,12 +38,15 @@ export const PrettifyLargeNumber: FC<IPrettifyLargeNumberProps> = ({
|
||||
value,
|
||||
threshold = 1_000_000,
|
||||
precision = 2,
|
||||
'data-loading': dataLoading,
|
||||
}) => {
|
||||
const prettyValue = prettifyLargeNumber(threshold, precision)(value);
|
||||
const showTooltip = value > threshold;
|
||||
|
||||
const valueSpan = (
|
||||
<span data-testid={LARGE_NUMBER_PRETTIFIED}>{prettyValue}</span>
|
||||
<span data-loading={dataLoading} data-testid={LARGE_NUMBER_PRETTIFIED}>
|
||||
{prettyValue}
|
||||
</span>
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { styled } from '@mui/material';
|
||||
import type { FC, PropsWithChildren, ReactNode } from 'react';
|
||||
import { forwardRef, type PropsWithChildren, type ReactNode } from 'react';
|
||||
|
||||
const StyledSection = styled('section')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
@ -21,14 +21,15 @@ const SectionTitleRow = styled('div')(({ theme }) => ({
|
||||
rowGap: theme.spacing(2),
|
||||
}));
|
||||
|
||||
export const InsightsSection: FC<
|
||||
export const InsightsSection = forwardRef<
|
||||
HTMLElement,
|
||||
PropsWithChildren<{ title: string; filters?: ReactNode }>
|
||||
> = ({ title, children, filters: HeaderActions }) => (
|
||||
<StyledSection>
|
||||
>(({ title, children, filters: HeaderActions }, ref) => (
|
||||
<StyledSection ref={ref}>
|
||||
<SectionTitleRow>
|
||||
<h2>{title}</h2>
|
||||
{HeaderActions}
|
||||
</SectionTitleRow>
|
||||
{children}
|
||||
</StyledSection>
|
||||
);
|
||||
));
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
} from 'component/common/PrettifyLargeNumber/PrettifyLargeNumber.tsx';
|
||||
import { FeatureLifecycleStageIcon } from 'component/common/FeatureLifecycle/FeatureLifecycleStageIcon.tsx';
|
||||
import { normalizeDays } from './normalize-days.ts';
|
||||
import useLoading from 'hooks/useLoading.ts';
|
||||
|
||||
type LifecycleTrend = {
|
||||
totalFlags: number;
|
||||
@ -128,14 +129,17 @@ export const LifecycleInsights: FC = () => {
|
||||
stateConfig,
|
||||
);
|
||||
|
||||
// todo: use data from the actual endpoint when we have something useful to return
|
||||
const loadingLabel = 'lifecycle-trend-charts';
|
||||
// todo (lifecycleMetrics): use data from the actual endpoint when we have something useful to return
|
||||
const projects = state[`${statePrefix}project`]?.values ?? [allOption.id];
|
||||
const { insights, loading } = useInsights();
|
||||
const loadingRef = useLoading(loading, `[data-loading="${loadingLabel}"]`);
|
||||
|
||||
const { lifecycleTrends } = insights;
|
||||
|
||||
return (
|
||||
<InsightsSection
|
||||
ref={loadingRef}
|
||||
title='Flags lifecycle currently'
|
||||
filters={
|
||||
<InsightsFilters
|
||||
@ -152,6 +156,7 @@ export const LifecycleInsights: FC = () => {
|
||||
<TileHeader>
|
||||
<HeaderNumber>
|
||||
<PrettifyLargeNumber
|
||||
data-loading={loadingLabel}
|
||||
value={data.totalFlags ?? 0}
|
||||
threshold={1000}
|
||||
precision={1}
|
||||
@ -175,7 +180,7 @@ export const LifecycleInsights: FC = () => {
|
||||
<dt>
|
||||
Median time for flags currently in stage
|
||||
</dt>
|
||||
<dd data-loading-project-lifecycle-summary>
|
||||
<dd data-loading={loadingLabel}>
|
||||
{normalizeDays(
|
||||
data.averageTimeInStageDays,
|
||||
)}
|
||||
@ -186,7 +191,7 @@ export const LifecycleInsights: FC = () => {
|
||||
Historical median time for flags in
|
||||
stage
|
||||
</dt>
|
||||
<dd data-loading-project-lifecycle-summary>
|
||||
<dd data-loading={loadingLabel}>
|
||||
{normalizeDays(
|
||||
data.averageTimeInStageDays,
|
||||
)}
|
||||
@ -247,9 +252,6 @@ const Chart: React.FC<{ stage: string; data: LifecycleTrend }> = ({
|
||||
labels: {
|
||||
value: {
|
||||
formatter: (value, context) => {
|
||||
// todo (lifecycleMetrics): use a nice
|
||||
// formatter here, so that 1,000,000
|
||||
// flags are instead formatted as 1M
|
||||
if (
|
||||
context.chart.legend
|
||||
?.legendItems?.[1].hidden
|
||||
|
Loading…
Reference in New Issue
Block a user