diff --git a/web-server/src/content/DoraMetrics/DoraCards/SkeletalCard.tsx b/web-server/src/content/DoraMetrics/DoraCards/SkeletalCard.tsx new file mode 100644 index 000000000..def45db67 --- /dev/null +++ b/web-server/src/content/DoraMetrics/DoraCards/SkeletalCard.tsx @@ -0,0 +1,182 @@ +import { Paper, Grid, Divider, useTheme } from '@mui/material'; +import Link from 'next/link'; +import { FC, useEffect } from 'react'; + +import { FlexBox } from '@/components/FlexBox'; +import { Line } from '@/components/Text'; +import { useBoolState } from '@/hooks/useEasyState'; +import { OPEN_IN_NEW_TAB_PROPS } from '@/utils/url'; + +import { LoaderCore } from '../DoraMetricsBody'; + +const ANIMATON_DURATION = 1000; + +export const DataStillSyncing = () => { + const flickerAnimation = useBoolState(); + + useEffect(() => { + const flickerInterval = setInterval( + flickerAnimation.toggle, + ANIMATON_DURATION + ); + + return () => { + clearInterval(flickerInterval); + }; + }, [flickerAnimation.toggle]); + return ( + + + + + + + + + + + + + + + + + + + + ); +}; + +const SkeletalCard: FC<{ animation?: boolean }> = ({ animation }) => { + return ( + + + + + + + + + + + + + + + + + ); +}; + +const ScoreSkeleton: FC<{ animation?: boolean }> = ({ animation }) => { + const theme = useTheme(); + const stats = { + avg: 2, + standard: 6.3, + lt: 4, + df: 5, + cfr: 6, + mttr: 7 + }; + + return ( + + + + + Your DORA + + + Performance + + + + + + + + + + + Industry + + + Standard + + + + + + {stats.standard}{' '} + + / 10 + + + + + + + Based on data available + + + at{' '} + + + dora.dev + + + + + + + ); +}; + +const Skeleton: FC<{ width?: string; height?: string }> = ({ + width = '150px', + height = '30px' +}) => ( + +); diff --git a/web-server/src/content/DoraMetrics/DoraMetricsBody.tsx b/web-server/src/content/DoraMetrics/DoraMetricsBody.tsx index c652668c3..ae3d70eb8 100644 --- a/web-server/src/content/DoraMetrics/DoraMetricsBody.tsx +++ b/web-server/src/content/DoraMetrics/DoraMetricsBody.tsx @@ -1,6 +1,6 @@ import { Grid, Divider, Button } from '@mui/material'; import Link from 'next/link'; -import { useEffect, useMemo } from 'react'; +import { FC, useEffect, useMemo } from 'react'; import { DoraMetricsConfigurationSettings } from '@/components/DoraMetricsConfigurationSettings'; import { DoraScore } from '@/components/DoraScore'; @@ -30,6 +30,7 @@ import { ClassificationPills } from './ClassificationPills'; import { ChangeFailureRateCard } from './DoraCards/ChangeFailureRateCard'; import { ChangeTimeCard } from './DoraCards/ChangeTimeCard'; import { MeanTimeToRestoreCard } from './DoraCards/MeanTimeToRestoreCard'; +import { DataStillSyncing } from './DoraCards/SkeletalCard'; import { WeeklyDeliveryVolumeCard } from './DoraCards/WeeklyDeliveryVolumeCard'; export const DoraMetricsBody = () => { @@ -103,22 +104,7 @@ export const DoraMetricsBody = () => { ); if (!firstLoadDone) return ; if (isTeamInsightsEmpty) - if (isSyncing) - return ( - - - - } - > - - - ); + if (isSyncing) return ; else return ( { }; }; -const ANIMATON_DURATION = 700; +const ANIMATON_DURATION = 1000; -const Syncing = () => { +export const Syncing = () => { const flickerAnimation = useBoolState(false); const { isSyncing } = useSyncedRepos(); @@ -240,11 +226,26 @@ const Syncing = () => { return ( + + + ); +}; + +export const LoaderCore: FC<{ + animation?: boolean; +}> = ({ animation }) => { + return ( + @@ -267,7 +268,7 @@ const Syncing = () => { height={'100%'} /> - {isSyncing && } + {} Calculating Dora diff --git a/web-server/src/slices/dora_metrics.ts b/web-server/src/slices/dora_metrics.ts index 4956aa69a..14dc1e0ac 100644 --- a/web-server/src/slices/dora_metrics.ts +++ b/web-server/src/slices/dora_metrics.ts @@ -133,6 +133,12 @@ export const doraMetricsSlice = createSlice({ 'deploymentPrs', (state, action) => (state.deploymentPrs = action.payload) ); + addFetchCasesToReducer( + builder, + getSyncedRepos, + 'bookmarkedRepos', + (state, action) => (state.bookmarkedRepos = action.payload) + ); } }); @@ -207,3 +213,12 @@ export const fetchDeploymentPRs = createAsyncThunk( return await handleApi(`/internal/deployments/prs`, { params }); } ); + +export const getSyncedRepos = createAsyncThunk( + 'dora_metrics/getSyncedRepos', + async (params: { team_id: ID }) => { + return await handleApi( + `/resources/teams/${params.team_id}/bookmarked_repos` + ); + } +);