diff --git a/dashboard/package.json b/dashboard/package.json index d0cc9999..73d12c75 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -16,6 +16,7 @@ "pypush": "cd .. && cd backend && sh pre-push" }, "dependencies": { + "@date-fns/tz": "^1.0.1", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@mui/material": "^5.16.7", @@ -42,6 +43,7 @@ "class-variance-authority": "^0.7.0", "classnames": "^2.5.1", "clsx": "^2.1.1", + "date-fns": "^4.0.0", "eslint-import-resolver-typescript": "^3.6.3", "lucide-react": "^0.396.0", "react": "^18.3.1", diff --git a/dashboard/pnpm-lock.yaml b/dashboard/pnpm-lock.yaml index 93aa2c0b..f2c19096 100644 --- a/dashboard/pnpm-lock.yaml +++ b/dashboard/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@date-fns/tz': + specifier: ^1.0.1 + version: 1.0.1 '@emotion/react': specifier: ^11.13.3 version: 11.13.3(@types/react@18.3.6)(react@18.3.1) @@ -86,6 +89,9 @@ importers: clsx: specifier: ^2.1.1 version: 2.1.1 + date-fns: + specifier: ^4.0.0 + version: 4.0.0 eslint-import-resolver-typescript: specifier: ^3.6.3 version: 3.6.3(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.6.2))(eslint-import-resolver-webpack@0.13.9)(eslint-plugin-import@2.30.0)(eslint@8.57.0) @@ -420,6 +426,9 @@ packages: resolution: {integrity: sha512-vYQ+TcfktEE3GHnLZXHCzXF/sN9dw+KivH8a5cmPyd9YtQs7fZtHrEgsIjWpYycXiweKMo1Lm1RZsjxk8DH3rA==} engines: {node: '>=16.0.0', yarn: '>=1.22.18'} + '@date-fns/tz@1.0.1': + resolution: {integrity: sha512-xaoJsguTUTPgafdT+u6TQNb4xcXQqaroeQSJL/7VCEWxQLTd//+ywV90u0VfkeKXfq1E9GRm5waS3bgIfUNu0g==} + '@emotion/babel-plugin@11.12.0': resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==} @@ -2529,6 +2538,9 @@ packages: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} + date-fns@4.0.0: + resolution: {integrity: sha512-6K33+I8fQ5otvHgLIvKK1xmMbLAh0pduyrx7dwMXKiGYeoWhmk6M3Zoak9n7bXHMJQlHq1yqmdGy1QxKddJjUA==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -4903,6 +4915,8 @@ snapshots: - '@chromatic-com/playwright' - react + '@date-fns/tz@1.0.1': {} + '@emotion/babel-plugin@11.12.0': dependencies: '@babel/helper-module-imports': 7.24.7 @@ -7196,6 +7210,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.1 + date-fns@4.0.0: {} + debug@2.6.9: dependencies: ms: 2.0.0 diff --git a/dashboard/src/components/Accordion/Accordion.tsx b/dashboard/src/components/Accordion/Accordion.tsx index c5e9a33d..7c6c9ec0 100644 --- a/dashboard/src/components/Accordion/Accordion.tsx +++ b/dashboard/src/components/Accordion/Accordion.tsx @@ -28,6 +28,8 @@ import { CollapsibleTrigger, } from '@/components/ui/collapsible'; +import { TooltipDateTime } from '@/components/TooltipDateTime'; + import AccordionBuildContent from './BuildAccordionContent'; export interface IAccordion { @@ -165,7 +167,18 @@ const AccordionBuildsTrigger = ({ <> {triggerInfo.config} {triggerInfo.compiler} - {triggerInfo.date} + + {triggerInfo.date ? ( + + ) : ( + '-' + )} + { > {test.path} {test.status} - {test.start_time ?? '-'} + + + {test.duration ?? '-'} diff --git a/dashboard/src/components/Table/BootsTable.tsx b/dashboard/src/components/Table/BootsTable.tsx index f96fc9c9..a13ec8fe 100644 --- a/dashboard/src/components/Table/BootsTable.tsx +++ b/dashboard/src/components/Table/BootsTable.tsx @@ -5,6 +5,7 @@ import { useNavigate, useSearch } from '@tanstack/react-router'; import { MdChevronRight } from 'react-icons/md'; import BaseTable from '@/components/Table/BaseTable'; +import { TooltipDateTime } from '@/components/TooltipDateTime'; import { TableInfo } from '@/components/Table/TableInfo'; import { TableCell, TableRow } from '@/components/ui/table'; import { usePagination } from '@/hooks/usePagination'; @@ -124,7 +125,14 @@ const BootsTable = ({ treeId, testHistory }: ITestsTable): JSX.Element => { onClickName(test.id)} key={test.id}> {test.path} {test.status} - {test.startTime ?? '-'} + + + {test.duration ?? '-'} diff --git a/dashboard/src/components/Table/TreeTable.tsx b/dashboard/src/components/Table/TreeTable.tsx index f98bc1a5..60586579 100644 --- a/dashboard/src/components/Table/TreeTable.tsx +++ b/dashboard/src/components/Table/TreeTable.tsx @@ -18,6 +18,8 @@ import { TreeTableBody, zOrigin } from '@/types/tree/Tree'; import { TableRow, TableCell, TableBody } from '@/components/ui/table'; +import { TooltipDateTime } from '@/components/TooltipDateTime'; + import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/Tooltip'; import HeaderWithInfo from '@/pages/TreeDetails/Tabs/HeaderWithInfo'; @@ -101,10 +103,6 @@ const TreeTableRow = (row: TreeTableBody): JSX.Element => { ], ); - const dateObj = new Date(row.date); - const date = dateObj.toLocaleDateString(); - const time = dateObj.toLocaleTimeString(); - return ( { onClick={navigateToTreeDetailPage} data-target="treeDetails.builds" > - - -
{date}
-
- -
- {date} -
- {time} -
-
-
+
{ + const dateObj = new Date(dateTime); + if (!isValid(dateObj)) return
-
; + + const date = dateFormat + ? format(dateObj, dateFormat) + : dateObj.toLocaleDateString(); + const time = timeFormat + ? format(dateObj, timeFormat) + : dateObj.toLocaleTimeString(); + const tz = getDateOffset(dateObj); + + return ( + + +
+ {date} {showLabelTime ? time : ''} {showLabelTZ ? tz : ''} +
+
+ {showTooltip && ( + +
+ {date} + {lineBreak ?
: ' '} + {time} {tz} +
+
+ )} +
+ ); +}; + +export default TooltipDateTime; diff --git a/dashboard/src/components/TooltipDateTime/index.tsx b/dashboard/src/components/TooltipDateTime/index.tsx new file mode 100644 index 00000000..761f6c4e --- /dev/null +++ b/dashboard/src/components/TooltipDateTime/index.tsx @@ -0,0 +1,3 @@ +import TooltipDateTime from './TooltipDateTime'; + +export { TooltipDateTime }; diff --git a/dashboard/src/pages/BuildDetails/BuildDetails.tsx b/dashboard/src/pages/BuildDetails/BuildDetails.tsx index 96e380a2..f9d660b8 100644 --- a/dashboard/src/pages/BuildDetails/BuildDetails.tsx +++ b/dashboard/src/pages/BuildDetails/BuildDetails.tsx @@ -14,6 +14,8 @@ import { ISection } from '@/components/Section/Section'; import { useBuildDetails } from '@/api/BuildDetails'; import UnexpectedError from '@/components/UnexpectedError/UnexpectedError'; +import { formatDate } from '@/utils/utils'; + import { Breadcrumb, BreadcrumbItem, @@ -85,7 +87,7 @@ const BuildDetails = (): JSX.Element => { }, { title: intl.formatMessage({ id: 'global.date' }), - linkText: valueOrEmpty(data.timestamp), + linkText: formatDate(valueOrEmpty(data.start_time)), }, { title: intl.formatMessage({ id: 'global.defconfig' }), diff --git a/dashboard/src/pages/TreeDetails/Tabs/Build/BuildTab.tsx b/dashboard/src/pages/TreeDetails/Tabs/Build/BuildTab.tsx index edafa262..07d6090f 100644 --- a/dashboard/src/pages/TreeDetails/Tabs/Build/BuildTab.tsx +++ b/dashboard/src/pages/TreeDetails/Tabs/Build/BuildTab.tsx @@ -156,7 +156,7 @@ const BuildTab = ({ treeDetailsData }: BuildTab): JSX.Element => { ) : ( '-' ), - date: row.date?.split('T')[0], + date: row.date, })); }, [treeDetailsData?.builds]); diff --git a/dashboard/src/utils/utils.ts b/dashboard/src/utils/utils.ts index 97e2a670..81344584 100644 --- a/dashboard/src/utils/utils.ts +++ b/dashboard/src/utils/utils.ts @@ -1,3 +1,5 @@ +import { format } from 'date-fns'; + export function formatDate(date: Date | string): string { const options: Intl.DateTimeFormatOptions = { year: 'numeric', @@ -14,3 +16,7 @@ export function formatDate(date: Date | string): string { return new Intl.DateTimeFormat('en-US', options).format(date); } + +export const getDateOffset = (date: Date): string => { + return format(date, 'z'); +};