Skip to content

Commit c4e2760

Browse files
committed
Merge branch '636-branches-crash-fix' into 'master'
fix: date formatting errors with invalid (empty) dates (#636) Closes #636 See merge request postgres-ai/database-lab!1049
2 parents faa278e + 0fb107a commit c4e2760

File tree

8 files changed

+61
-87
lines changed

8 files changed

+61
-87
lines changed

ui/packages/shared/components/ResetCloneModal/index.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
import { useEffect, useState } from 'react'
99
import { makeStyles } from '@material-ui/core'
10-
import { formatDistanceToNowStrict } from 'date-fns'
11-
1210
import { Clone } from '@postgres.ai/shared/types/api/entities/clone'
1311
import { Snapshot } from '@postgres.ai/shared/types/api/entities/snapshot'
1412
import { Text } from '@postgres.ai/shared/components/Text'
@@ -18,7 +16,7 @@ import { ImportantText } from '@postgres.ai/shared/components/ImportantText'
1816
import { Spinner } from '@postgres.ai/shared/components/Spinner'
1917
import { SimpleModalControls } from '@postgres.ai/shared/components/SimpleModalControls'
2018
import { compareSnapshotsDesc } from '@postgres.ai/shared/utils/snapshot'
21-
import { isValidDate } from '@postgres.ai/shared/utils/date'
19+
import { formatDateWithDistance } from '@postgres.ai/shared/utils/date'
2220

2321
type Props = {
2422
isOpen: boolean
@@ -111,12 +109,7 @@ export const ResetCloneModal = (props: Props) => {
111109
value: snapshot.id,
112110
children: (
113111
<>
114-
{snapshot.dataStateAt} (
115-
{isValidDate(snapshot.dataStateAtDate) &&
116-
formatDistanceToNowStrict(snapshot.dataStateAtDate, {
117-
addSuffix: true,
118-
})}
119-
)
112+
{formatDateWithDistance(snapshot.dataStateAt, snapshot.dataStateAtDate)}
120113
{isLatest && (
121114
<span className={classes.snapshotTag}>Latest</span>
122115
)}

ui/packages/shared/pages/Branches/components/BranchesTable/index.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ import { useEffect, useState } from 'react'
1010
import copy from 'copy-to-clipboard'
1111
import { makeStyles } from '@material-ui/core'
1212
import { useHistory } from 'react-router-dom'
13-
import { formatDistanceToNowStrict } from 'date-fns'
14-
15-
import { isValidDate } from '@postgres.ai/shared/utils/date'
13+
import { formatDateWithDistance } from '@postgres.ai/shared/utils/date'
1614
import { ArrowDropDownIcon } from '@postgres.ai/shared/icons/ArrowDropDown'
1715
import { Branch } from '@postgres.ai/shared/types/api/endpoints/getBranches'
1816
import { HorizontalScrollContainer } from '@postgres.ai/shared/components/HorizontalScrollContainer'
@@ -168,13 +166,7 @@ export const BranchesTable = ({
168166
<TableBodyCell>{branch.name}</TableBodyCell>
169167
<TableBodyCell>{branch.parent}</TableBodyCell>
170168
<TableBodyCell>
171-
{branch.dataStateAt} (
172-
{isValidDate(new Date(branch.dataStateAt))
173-
? formatDistanceToNowStrict(new Date(branch.dataStateAt), {
174-
addSuffix: true,
175-
})
176-
: '-'}
177-
)
169+
{formatDateWithDistance(branch.dataStateAt, new Date(branch.dataStateAt))}
178170
</TableBodyCell>
179171
<TableBodyCell>{branch.snapshotID}</TableBodyCell>
180172
<TableBodyCell>{branch.numSnapshots}</TableBodyCell>

ui/packages/shared/pages/Instance/Clones/ClonesList/index.tsx

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import { useState } from 'react'
99
import cn from 'classnames'
10-
import { formatDistanceToNowStrict } from 'date-fns'
1110
import { useHistory } from 'react-router-dom'
1211

1312
import {
@@ -32,7 +31,7 @@ import {
3231
getCloneStatusText,
3332
} from '@postgres.ai/shared/utils/clone'
3433
import { formatBytesIEC } from '@postgres.ai/shared/utils/units'
35-
import { isValidDate } from '@postgres.ai/shared/utils/date'
34+
import { formatDateWithDistance } from '@postgres.ai/shared/utils/date'
3635

3736
import { MenuCell } from './MenuCell'
3837
import { ConnectionModal } from './ConnectionModal'
@@ -217,13 +216,7 @@ export const ClonesList = (props: Props) => {
217216
)}
218217
</TableBodyCell>
219218
<TableBodyCell>
220-
{clone.createdAt} (
221-
{isValidDate(clone.createdAtDate)
222-
? formatDistanceToNowStrict(clone.createdAtDate, {
223-
addSuffix: true,
224-
})
225-
: '-'}
226-
)
219+
{formatDateWithDistance(clone.createdAt, clone.createdAtDate)}
227220
</TableBodyCell>
228221
<TableBodyCell>{clone.db.port}</TableBodyCell>
229222
<TableBodyCell>{clone.db.username}</TableBodyCell>
@@ -232,22 +225,7 @@ export const ClonesList = (props: Props) => {
232225
</TableBodyCell>
233226
<TableBodyCell>{clone.snapshot?.pool ?? '-'}</TableBodyCell>
234227
<TableBodyCell>
235-
{clone.snapshot ? (
236-
<>
237-
{clone.snapshot.dataStateAt} (
238-
{isValidDate(clone.snapshot.dataStateAtDate)
239-
? formatDistanceToNowStrict(
240-
clone.snapshot.dataStateAtDate,
241-
{
242-
addSuffix: true,
243-
},
244-
)
245-
: '-'}
246-
)
247-
</>
248-
) : (
249-
'-'
250-
)}
228+
{clone.snapshot ? formatDateWithDistance(clone.snapshot.dataStateAt, clone.snapshot.dataStateAtDate) : '-'}
251229
</TableBodyCell>
252230
</TableRow>
253231
)

ui/packages/shared/pages/Instance/InactiveInstance/index.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Tooltip } from '@material-ui/core'
22
import { makeStyles } from '@material-ui/core'
3-
import { formatDistanceToNowStrict } from 'date-fns'
3+
import { formatDistanceSafe } from '@postgres.ai/shared/utils/date'
44

55
import { Link } from '@postgres.ai/shared/components/Link2'
66
import { Instance } from '@postgres.ai/shared/types/api/entities/instance'
@@ -95,10 +95,7 @@ export const InactiveInstance = ({
9595
classes={{ tooltip: classes.toolTip }}
9696
>
9797
<span>
98-
{instance?.createdAt &&
99-
formatDistanceToNowStrict(new Date(instance?.createdAt), {
100-
addSuffix: true,
101-
})}
98+
{instance?.createdAt ? formatDistanceSafe(new Date(instance?.createdAt)) : '-'}
10299
</span>
103100
</Tooltip>
104101
</span>
@@ -114,12 +111,7 @@ export const InactiveInstance = ({
114111
classes={{ tooltip: classes.toolTip }}
115112
>
116113
<span>
117-
{formatDistanceToNowStrict(
118-
new Date(instance?.telemetryLastReportedAt),
119-
{
120-
addSuffix: true,
121-
},
122-
)}
114+
{instance?.telemetryLastReportedAt ? formatDistanceSafe(new Date(instance?.telemetryLastReportedAt)) : '-'}
123115
</span>
124116
</Tooltip>
125117
</span>

ui/packages/shared/pages/Instance/Snapshots/components/SnapshotsList/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
generateSnapshotPageId,
1515
groupSnapshotsByCreatedAtDate,
1616
} from '@postgres.ai/shared/pages/Instance/Snapshots/utils'
17-
import { format, formatDistanceToNowStrict } from 'date-fns'
17+
import { format } from 'date-fns'
18+
import { formatDistanceSafe } from '@postgres.ai/shared/utils/date'
1819
import { formatBytesIEC } from '@postgres.ai/shared/utils/units'
1920
import { useHistory } from 'react-router'
2021
import { DestroySnapshot } from '@postgres.ai/shared/types/api/endpoints/destroySnapshot'
@@ -129,7 +130,7 @@ const SnapshotListItem = ({
129130
setSnapshotModal: (modal: { isOpen: boolean; snapshotId: string }) => void
130131
}) => {
131132
const classes = useStyles()
132-
const timeAgo = formatDistanceToNowStrict(snapshot.createdAtDate)
133+
const timeAgo = formatDistanceSafe(snapshot.createdAtDate)
133134

134135
const history = useHistory()
135136
const host = useHost()

ui/packages/shared/pages/Instance/Snapshots/components/SnapshotsTable/index.tsx

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import React from 'react'
99
import cn from 'classnames'
1010
import { observer } from 'mobx-react-lite'
1111
import { makeStyles } from '@material-ui/core'
12-
import { formatDistanceToNowStrict } from 'date-fns'
1312
import copy from 'copy-to-clipboard'
1413
import { useHistory } from 'react-router-dom'
1514

@@ -19,7 +18,7 @@ import { DestroySnapshotModal } from '@postgres.ai/shared/pages/Snapshots/Snapsh
1918
import { useStores } from '@postgres.ai/shared/pages/Instance/context'
2019
import { ArrowDropDownIcon } from '@postgres.ai/shared/icons/ArrowDropDown'
2120
import { formatBytesIEC } from '@postgres.ai/shared/utils/units'
22-
import { isSameDayUTC, isValidDate } from '@postgres.ai/shared/utils/date'
21+
import { isSameDayUTC, formatDateWithDistance } from '@postgres.ai/shared/utils/date'
2322
import {
2423
Table,
2524
TableHead,
@@ -190,22 +189,10 @@ export const SnapshotsTable: React.FC<SnapshotsTableProps> = observer(
190189
]}
191190
/>
192191
<TableBodyCell>
193-
{snapshot.dataStateAt} (
194-
{isValidDate(snapshot.dataStateAtDate)
195-
? formatDistanceToNowStrict(snapshot.dataStateAtDate, {
196-
addSuffix: true,
197-
})
198-
: '-'}
199-
)
192+
{formatDateWithDistance(snapshot.dataStateAt, snapshot.dataStateAtDate)}
200193
</TableBodyCell>
201194
<TableBodyCell>
202-
{snapshot.createdAt} (
203-
{isValidDate(snapshot.createdAtDate)
204-
? formatDistanceToNowStrict(snapshot.createdAtDate, {
205-
addSuffix: true,
206-
})
207-
: '-'}
208-
)
195+
{formatDateWithDistance(snapshot.createdAt, snapshot.createdAtDate)}
209196
</TableBodyCell>
210197
<TableBodyCell>{snapshot.pool ?? '-'}</TableBodyCell>
211198
<TableBodyCell>{snapshot.numClones ?? '-'}</TableBodyCell>

ui/packages/shared/pages/Instance/SnapshotsModal/index.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import { observer } from 'mobx-react-lite'
99
import { makeStyles } from '@material-ui/core'
10-
import { formatDistanceToNowStrict } from 'date-fns'
1110
import copy from 'copy-to-clipboard'
1211

1312
import { useStores } from '@postgres.ai/shared/pages/Instance/context'
@@ -24,7 +23,7 @@ import {
2423
TableBodyCellMenu,
2524
} from '@postgres.ai/shared/components/Table'
2625
import { formatBytesIEC } from '@postgres.ai/shared/utils/units'
27-
import { isSameDayUTC } from '@postgres.ai/shared/utils/date'
26+
import { isSameDayUTC, formatDateWithDistance } from '@postgres.ai/shared/utils/date'
2827

2928
import { Tags } from '@postgres.ai/shared/pages/Instance/components/Tags'
3029
import { ModalReloadButton } from '@postgres.ai/shared/pages/Instance/components/ModalReloadButton'
@@ -137,18 +136,10 @@ export const SnapshotsModal = observer(() => {
137136
]}
138137
/>
139138
<TableBodyCell>
140-
{snapshot.dataStateAt} (
141-
{formatDistanceToNowStrict(snapshot.dataStateAtDate, {
142-
addSuffix: true,
143-
})}
144-
)
139+
{formatDateWithDistance(snapshot.dataStateAt, snapshot.dataStateAtDate)}
145140
</TableBodyCell>
146141
<TableBodyCell>
147-
{snapshot.createdAt} (
148-
{formatDistanceToNowStrict(snapshot.createdAtDate, {
149-
addSuffix: true,
150-
})}
151-
)
142+
{formatDateWithDistance(snapshot.createdAt, snapshot.createdAtDate)}
152143
</TableBodyCell>
153144
<TableBodyCell>{snapshot.pool ?? '-'}</TableBodyCell>
154145
<TableBodyCell>

ui/packages/shared/utils/date.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,24 @@ import {
2222
} from 'date-fns'
2323

2424
export const formatDateToISO = (dateString: string) => {
25-
const parsedDate = parse(dateString, 'yyyyMMddHHmmss', new Date())
26-
return format(parsedDate, "yyyy-MM-dd'T'HH:mm:ssXXX")
25+
// Handle empty or invalid date strings
26+
if (!dateString || dateString.trim() === '') {
27+
return ''
28+
}
29+
30+
try {
31+
const parsedDate = parse(dateString, 'yyyyMMddHHmmss', new Date())
32+
33+
// Additional validation of parsed date
34+
if (!isValidDate(parsedDate) || isNaN(parsedDate.getTime())) {
35+
return ''
36+
}
37+
38+
return format(parsedDate, "yyyy-MM-dd'T'HH:mm:ssXXX")
39+
} catch (error) {
40+
// Return empty string for invalid date formats
41+
return ''
42+
}
2743
}
2844

2945
// parseDate parses date of both format: '2006-01-02 15:04:05 UTC' and `2006-01-02T15:04:05Z` (RFC3339).
@@ -94,3 +110,27 @@ export const formatDateStd = (
94110
export const isValidDate = (dateObject: Date) => {
95111
return new Date(dateObject).toString() !== 'Invalid Date'
96112
}
113+
114+
// Safe date formatting with distance
115+
export const formatDateWithDistance = (dateString: string, dateObject: Date) => {
116+
if (!dateString || !isValidDate(dateObject)) return '-'
117+
118+
try {
119+
return `${dateString} (${formatDistanceToNowStrict(dateObject, { addSuffix: true })})`
120+
} catch (error) {
121+
console.warn('Error formatting date distance:', error, 'date:', dateObject)
122+
return '-'
123+
}
124+
}
125+
126+
// Safe distance formatting only
127+
export const formatDistanceSafe = (dateObject: Date) => {
128+
if (!isValidDate(dateObject)) return '-'
129+
130+
try {
131+
return formatDistanceToNowStrict(dateObject, { addSuffix: true })
132+
} catch (error) {
133+
console.warn('Error formatting distance:', error, 'date:', dateObject)
134+
return '-'
135+
}
136+
}

0 commit comments

Comments
 (0)