Skip to content

Commit e169d5a

Browse files
committed
styles: Endpoint details updated the ui for Recent checks table and add loading state
1 parent 5476df3 commit e169d5a

File tree

2 files changed

+62
-31
lines changed

2 files changed

+62
-31
lines changed

thingconnect.pulse.client/src/components/ui/empty-state.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as React from 'react';
33

44
export interface EmptyStateProps extends ChakraEmptyState.RootProps {
55
title: string;
6-
description?: string;
6+
description?: React.ReactElement;
77
icon?: React.ReactNode;
88
}
99

thingconnect.pulse.client/src/pages/EndpointDetail.tsx

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,15 @@ import {
3030
CircleCheckBig,
3131
CircleAlert,
3232
CloudOff,
33+
SearchX,
3334
} from 'lucide-react';
3435
import { Page } from '@/components/layout/Page';
3536
import { useQuery } from '@tanstack/react-query';
3637
import { EndpointService } from '@/api/services/endpoint.service';
3738
import { formatDistanceToNow } from 'date-fns';
3839
import type { RawCheck, Outage } from '@/api/types';
40+
import { Skeleton } from '@/components/ui/skeleton';
41+
import { EmptyState } from '@/components/ui/empty-state';
3942

4043
function getStatusColor(status: string) {
4144
switch (status.toLowerCase()) {
@@ -218,10 +221,7 @@ function OutagesList({ outages }: OutagesListProps) {
218221

219222
export default function EndpointDetail() {
220223
const { id } = useParams<{ id: string }>();
221-
222-
if (!id) {
223-
return <Navigate to='/' replace />;
224-
}
224+
if (!id) return <Navigate to='/' replace />;
225225

226226
const {
227227
data: endpointDetail,
@@ -233,26 +233,66 @@ export default function EndpointDetail() {
233233
refetchInterval: 10000, // Refresh every 10 seconds
234234
});
235235

236-
if (!endpointDetail && !isLoading && !error) {
236+
const backButton = (
237+
<RouterLink to='/'>
238+
<Button variant='ghost' size='sm' h='32px' mt={-4} mr={7}>
239+
<ArrowLeft size={16} />
240+
Back to Dashboard
241+
</Button>
242+
</RouterLink>
243+
);
244+
245+
if (isLoading) {
237246
return (
238-
<Page
239-
title='Endpoint Not Found'
240-
description={`The endpoint with ID "${id}" was not found`}
241-
actions={
242-
<RouterLink to='/'>
243-
<Button variant='ghost' size='sm'>
244-
<ArrowLeft size={16} />
245-
Back to Dashboard
246-
</Button>
247-
</RouterLink>
248-
}
249-
>
250-
<Text>The endpoint with ID "{id}" was not found.</Text>
247+
<Page title='Loading endpoint...' actions={backButton}>
248+
<VStack gap={4} align='stretch'>
249+
<Skeleton w='full' minH='150px' />
250+
<Heading size='md'>Recent Performance</Heading>
251+
<StatGroup w='full' gap={2}>
252+
{Array(4)
253+
.fill(0)
254+
.map((_, i) => (
255+
<Stat.Root key={i} borderWidth='1px' p='4' rounded='md' h='full' w='25%'>
256+
<HStack w='full' gap={3}>
257+
<Skeleton boxSize='12' borderRadius='full' />
258+
<VStack align='start' gap={1} w='full'>
259+
<Skeleton minH='12px' w='60px' />
260+
<Skeleton minH='16px' w='80px' />
261+
<Skeleton minH='12px' w='100px' />
262+
</VStack>
263+
</HStack>
264+
</Stat.Root>
265+
))}
266+
</StatGroup>
267+
<SimpleGrid columns={{ base: 1, lg: 2 }} gap={2}>
268+
<Skeleton w='full' minH='50vh' />
269+
<Skeleton w='full' minH='50vh' />
270+
</SimpleGrid>
271+
</VStack>
251272
</Page>
252273
);
253274
}
254275

255-
if (!endpointDetail) return null;
276+
if (error || !endpointDetail) {
277+
return (
278+
<Page title='Endpoint Not Found' actions={backButton}>
279+
<EmptyState
280+
icon={<SearchX />}
281+
title='Endpoint Not Found'
282+
description={
283+
<>
284+
<Text>The endpoint with ID "{id}" does not exist.</Text>
285+
{error && (
286+
<Text color='red.500' mt={2} fontSize='sm'>
287+
Error: {(error as Error).message}
288+
</Text>
289+
)}
290+
</>
291+
}
292+
/>
293+
</Page>
294+
);
295+
}
256296

257297
const { endpoint, recent, outages } = endpointDetail;
258298

@@ -271,15 +311,6 @@ export default function EndpointDetail() {
271311
const latestCheck = recent.length > 0 ? recent[0] : null;
272312
const currentStatus = latestCheck?.status || 'unknown';
273313

274-
const backButton = (
275-
<RouterLink to='/'>
276-
<Button variant='ghost' size='sm' h='32px' mt={-4} mr={7}>
277-
<ArrowLeft size={16} />
278-
Back to Dashboard
279-
</Button>
280-
</RouterLink>
281-
);
282-
283314
return (
284315
<Page
285316
title={endpoint.name}
@@ -506,9 +537,9 @@ export default function EndpointDetail() {
506537
<Card.Header p={4} pb={0}>
507538
<HStack justify='space-between' align='center'>
508539
<Heading size='md'>Recent Checks</Heading>
509-
<Text color='blue' fontSize={'xs'}>
540+
<Badge fontSize={'xs'} colorPalette={'blue'}>
510541
Last 60 minutes
511-
</Text>
542+
</Badge>
512543
</HStack>
513544
</Card.Header>
514545
<Card.Body p={4}>

0 commit comments

Comments
 (0)