Skip to content

Commit b4dd391

Browse files
authored
feat: added Outage UI to the History page
2 parents 607c603 + 758a61f commit b4dd391

File tree

12 files changed

+497
-150
lines changed

12 files changed

+497
-150
lines changed

thingconnect.pulse.client/obj/Debug/package.g.props

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<PackageJsonDependenciesDateFns Condition="$(PackageJsonDependenciesDateFns) == ''">^4.1.0</PackageJsonDependenciesDateFns>
2222
<PackageJsonDependenciesLodash Condition="$(PackageJsonDependenciesLodash) == ''">^4.17.21</PackageJsonDependenciesLodash>
2323
<PackageJsonDependenciesLucideReact Condition="$(PackageJsonDependenciesLucideReact) == ''">^0.541.0</PackageJsonDependenciesLucideReact>
24-
<PackageJsonDependenciesLuxon Condition="$(PackageJsonDependenciesLuxon) == ''">^3.7.1</PackageJsonDependenciesLuxon>
24+
<PackageJsonDependenciesLuxon Condition="$(PackageJsonDependenciesLuxon) == ''">^3.7.2</PackageJsonDependenciesLuxon>
2525
<PackageJsonDependenciesMixpanelBrowser Condition="$(PackageJsonDependenciesMixpanelBrowser) == ''">^2.70.0</PackageJsonDependenciesMixpanelBrowser>
2626
<PackageJsonDependenciesMonacoEditor Condition="$(PackageJsonDependenciesMonacoEditor) == ''">^0.52.2</PackageJsonDependenciesMonacoEditor>
2727
<PackageJsonDependenciesNextThemes Condition="$(PackageJsonDependenciesNextThemes) == ''">^0.4.6</PackageJsonDependenciesNextThemes>
@@ -36,6 +36,7 @@
3636
<PackageJsonDevdependenciesTanstackEslintPluginQuery Condition="$(PackageJsonDevdependenciesTanstackEslintPluginQuery) == ''">^5.83.1</PackageJsonDevdependenciesTanstackEslintPluginQuery>
3737
<PackageJsonDevdependenciesTanstackReactQueryDevtools Condition="$(PackageJsonDevdependenciesTanstackReactQueryDevtools) == ''">^5.85.5</PackageJsonDevdependenciesTanstackReactQueryDevtools>
3838
<PackageJsonDevdependenciesTypesLodash Condition="$(PackageJsonDevdependenciesTypesLodash) == ''">^4.17.20</PackageJsonDevdependenciesTypesLodash>
39+
<PackageJsonDevdependenciesTypesLuxon Condition="$(PackageJsonDevdependenciesTypesLuxon) == ''">^3.7.1</PackageJsonDevdependenciesTypesLuxon>
3940
<PackageJsonDevdependenciesTypesNode Condition="$(PackageJsonDevdependenciesTypesNode) == ''">^22</PackageJsonDevdependenciesTypesNode>
4041
<PackageJsonDevdependenciesTypesReact Condition="$(PackageJsonDevdependenciesTypesReact) == ''">^19.1.10</PackageJsonDevdependenciesTypesReact>
4142
<PackageJsonDevdependenciesTypesReactDom Condition="$(PackageJsonDevdependenciesTypesReactDom) == ''">^19.1.7</PackageJsonDevdependenciesTypesReactDom>

thingconnect.pulse.client/package-lock.json

Lines changed: 22 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

thingconnect.pulse.client/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"date-fns": "^4.1.0",
2323
"lodash": "^4.17.21",
2424
"lucide-react": "^0.541.0",
25-
"luxon": "^3.7.1",
25+
"luxon": "^3.7.2",
2626
"mixpanel-browser": "^2.70.0",
2727
"monaco-editor": "^0.52.2",
2828
"next-themes": "^0.4.6",
@@ -39,6 +39,7 @@
3939
"@tanstack/eslint-plugin-query": "^5.83.1",
4040
"@tanstack/react-query-devtools": "^5.85.5",
4141
"@types/lodash": "^4.17.20",
42+
"@types/luxon": "^3.7.1",
4243
"@types/node": "^22",
4344
"@types/react": "^19.1.10",
4445
"@types/react-dom": "^19.1.7",

thingconnect.pulse.client/src/components/AvailabilityChart.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
import { useMemo, useRef, useState, useLayoutEffect } from 'react';
22
import { Box, Text, VStack, Skeleton } from '@chakra-ui/react';
3-
import type { RollupBucket, DailyBucket, RawCheck } from '@/api/types';
3+
import type { HistoryResponse } from '@/api/types';
44
import type { BucketType } from '@/types/bucket';
55

66
export interface AvailabilityChartProps {
7-
data:
8-
| {
9-
raw: RawCheck[];
10-
rollup15m: RollupBucket[];
11-
rollupDaily: DailyBucket[];
12-
}
13-
| null
14-
| undefined;
7+
data: HistoryResponse | null | undefined;
158
bucket: BucketType;
169
height?: number;
1710
showResponseTime?: boolean;
Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { Text, VStack, Badge, HStack, Card } from '@chakra-ui/react';
1+
import { Text, VStack, Badge, HStack, Card, Skeleton } from '@chakra-ui/react';
22
import { CloudOff } from 'lucide-react';
33
import { formatDistanceToNow } from 'date-fns';
44
import type { Outage } from '@/api/types';
55

66
interface OutagesListProps {
7-
outages: Outage[];
7+
outages: Outage[] | undefined;
8+
isLoading: boolean;
89
}
910

1011
function formatDuration(seconds?: number | null): string {
@@ -18,8 +19,8 @@ function formatDuration(seconds?: number | null): string {
1819
return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
1920
}
2021

21-
export function OutagesList({ outages }: OutagesListProps) {
22-
if (outages.length === 0) {
22+
export function OutagesList({ outages, isLoading }: OutagesListProps) {
23+
if (outages?.length === 0) {
2324
return (
2425
<VStack
2526
justify='center'
@@ -38,44 +39,59 @@ export function OutagesList({ outages }: OutagesListProps) {
3839
);
3940
}
4041

42+
function capitalizeFirstLetter(text: string) {
43+
if (!text) return '';
44+
return text.charAt(0).toUpperCase() + text.slice(1);
45+
}
46+
47+
const sortedOutages = outages
48+
? [...outages].sort((a, b) => {
49+
if (!a.endedTs && b.endedTs) return -1;
50+
if (a.endedTs && !b.endedTs) return 1;
51+
return new Date(b.startedTs).getTime() - new Date(a.startedTs).getTime();
52+
})
53+
: [];
54+
4155
return (
4256
<VStack gap={4} align='stretch'>
43-
{outages.slice(0, 5).map((outage, index) => (
44-
<Card.Root key={`${outage.startedTs}-${index}`} variant='outline'>
45-
<Card.Body>
46-
<VStack gap={2} align='stretch'>
47-
<HStack justify='space-between'>
48-
<Text fontSize='sm' fontWeight='medium'>
49-
{formatDistanceToNow(new Date(outage.startedTs), { addSuffix: true })}
50-
</Text>
51-
<Badge colorPalette={outage.endedTs ? 'gray' : 'red'} size='sm'>
52-
{outage.endedTs ? 'Resolved' : 'Ongoing'}
53-
</Badge>
54-
</HStack>
55-
<HStack justify='space-between'>
56-
<Text fontSize='sm' color='gray.600'>
57-
Duration: {formatDuration(outage.durationS)}
58-
</Text>
59-
{outage.endedTs && (
57+
{sortedOutages.map((outage, index) => (
58+
<Skeleton loading={isLoading}>
59+
<Card.Root key={`${outage.startedTs}-${index}`} size={'sm'}>
60+
<Card.Body p={3}>
61+
<VStack gap={2} align='stretch'>
62+
<HStack justify='space-between'>
63+
<Text fontSize='sm' fontWeight='medium'>
64+
{capitalizeFirstLetter(
65+
formatDistanceToNow(new Date(outage.startedTs), { addSuffix: true })
66+
)}
67+
</Text>
68+
<Badge colorPalette={outage.endedTs ? 'green' : 'red'} size='sm'>
69+
{outage.endedTs ? 'Resolved' : 'Ongoing'}
70+
</Badge>
71+
</HStack>
72+
<HStack justify='space-between'>
6073
<Text fontSize='sm' color='gray.600'>
61-
Ended: {formatDistanceToNow(new Date(outage.endedTs), { addSuffix: true })}
74+
Duration: {formatDuration(outage.durationS)}
75+
</Text>
76+
<Text fontSize='sm' color='gray.600'>
77+
Ended:{' '}
78+
{outage.endedTs
79+
? capitalizeFirstLetter(
80+
formatDistanceToNow(new Date(outage.endedTs), { addSuffix: true })
81+
)
82+
: 'Unknown'}
83+
</Text>
84+
</HStack>
85+
{outage.lastError && (
86+
<Text fontSize='sm' color='red.600' _dark={{ color: 'red.400' }} lineClamp={2}>
87+
{outage.lastError}
6288
</Text>
6389
)}
64-
</HStack>
65-
{outage.lastError && (
66-
<Text fontSize='sm' color='red.600' _dark={{ color: 'red.400' }} lineClamp={2}>
67-
{outage.lastError}
68-
</Text>
69-
)}
70-
</VStack>
71-
</Card.Body>
72-
</Card.Root>
90+
</VStack>
91+
</Card.Body>
92+
</Card.Root>
93+
</Skeleton>
7394
))}
74-
{outages.length > 5 && (
75-
<Text fontSize='sm' color='gray.500' textAlign='center'>
76-
Showing 5 of {outages.length} recent outages
77-
</Text>
78-
)}
7995
</VStack>
8096
);
8197
}

0 commit comments

Comments
 (0)