1
0
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:
Thomas Heartman 2025-06-10 11:35:32 +02:00 committed by GitHub
parent 6d7a344ca3
commit 45d48d12a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 22 additions and 12 deletions

View File

@ -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 (

View File

@ -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>
);
));

View File

@ -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