Skip to content

Commit

Permalink
chore(frontend): refactor time utils to have separate functions for h…
Browse files Browse the repository at this point in the history
…uman readable datetime, date only and time only

closes #1223
  • Loading branch information
anupcowkur committed Sep 11, 2024
1 parent e2a1af5 commit 55c1b5a
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 26 deletions.
66 changes: 61 additions & 5 deletions frontend/dashboard/__tests__/utils/time_utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { formatChartFormatTimestampToHumanReadable, formatDateToHumanReadable, formatIsoDateForDateTimeInputField, formatMillisToHumanReadable, formatTimestampToChartFormat, formatUserInputDateToServerFormat, isValidTimestamp } from '@/app/utils/time_utils'
import { formatChartFormatTimestampToHumanReadable, formatDateToHumanReadableDate, formatDateToHumanReadableDateTime, formatDateToHumanReadableTime, formatIsoDateForDateTimeInputField, formatMillisToHumanReadable, formatTimestampToChartFormat, formatUserInputDateToServerFormat, isValidTimestamp } from '@/app/utils/time_utils'
import { expect, it, describe, beforeEach, afterEach } from '@jest/globals'
import { Settings, DateTime } from "luxon"

Expand Down Expand Up @@ -40,7 +40,7 @@ describe('formatMillisToHumanReadable', () => {
})
})

describe('formatDateToHumanReadable', () => {
describe('formatDateToHumanReadableDateTime', () => {
beforeEach(() => {
Settings.now = () => 0
Settings.defaultZone = "Asia/Kolkata"
Expand All @@ -53,18 +53,74 @@ describe('formatDateToHumanReadable', () => {
it('should format a UTC timestamp to a human readable date', () => {
const timestamp = '2024-04-16T12:00:00Z'
const expected = '16 Apr, 2024, 5:30:00 PM'
expect(formatDateToHumanReadable(timestamp)).toBe(expected)
expect(formatDateToHumanReadableDateTime(timestamp)).toBe(expected)
})

it('should format a UTC timestamp to a human readable date', () => {
const timestamp = '2024-04-15T03:44:00Z'
const expected = '15 Apr, 2024, 9:14:00 AM'
expect(formatDateToHumanReadable(timestamp)).toBe(expected)
expect(formatDateToHumanReadableDateTime(timestamp)).toBe(expected)
})

it('should throw on invalid timestamps', () => {
const timestamp = 'invalid-timestamp'
expect(() => formatDateToHumanReadable(timestamp)).toThrow()
expect(() => formatDateToHumanReadableDateTime(timestamp)).toThrow()
})
})

describe('formatDateToHumanReadableDate', () => {
beforeEach(() => {
Settings.now = () => 0
Settings.defaultZone = "Asia/Kolkata"
})

afterEach(() => {
Settings.now = () => DateTime.now().valueOf()
})

it('should format a UTC timestamp to a human readable date', () => {
const timestamp = '2024-04-16T12:00:00Z'
const expected = '16 Apr, 2024'
expect(formatDateToHumanReadableDate(timestamp)).toBe(expected)
})

it('should format a UTC timestamp to a human readable date', () => {
const timestamp = '2024-04-15T03:44:00Z'
const expected = '15 Apr, 2024'
expect(formatDateToHumanReadableDate(timestamp)).toBe(expected)
})

it('should throw on invalid timestamps', () => {
const timestamp = 'invalid-timestamp'
expect(() => formatDateToHumanReadableDate(timestamp)).toThrow()
})
})

describe('formatDateToHumanReadableTime', () => {
beforeEach(() => {
Settings.now = () => 0
Settings.defaultZone = "Asia/Kolkata"
})

afterEach(() => {
Settings.now = () => DateTime.now().valueOf()
})

it('should format a UTC timestamp to a human readable date', () => {
const timestamp = '2024-04-16T12:00:00Z'
const expected = '5:30:00 PM'
expect(formatDateToHumanReadableTime(timestamp)).toBe(expected)
})

it('should format a UTC timestamp to a human readable date', () => {
const timestamp = '2024-04-15T03:44:00Z'
const expected = '9:14:00 AM'
expect(formatDateToHumanReadableTime(timestamp)).toBe(expected)
})

it('should throw on invalid timestamps', () => {
const timestamp = 'invalid-timestamp'
expect(() => formatDateToHumanReadableTime(timestamp)).toThrow()
})
})

Expand Down
6 changes: 3 additions & 3 deletions frontend/dashboard/app/[teamId]/sessions/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { emptySessionsOverviewResponse, SessionsOverviewApiStatus, fetchSessions
import Filters, { AppVersionsInitialSelectionType, defaultSelectedFilters } from '@/app/components/filters';
import Paginator, { PaginationDirection } from '@/app/components/paginator';
import SessionsOverviewPlot from '@/app/components/sessions_overview_plot';
import { formatDateToHumanReadable, formatMillisToHumanReadable } from '@/app/utils/time_utils';
import { formatDateToHumanReadableDate, formatDateToHumanReadableTime, formatMillisToHumanReadable } from '@/app/utils/time_utils';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import React, { useEffect, useState } from 'react';
Expand Down Expand Up @@ -158,9 +158,9 @@ export default function SessionsOverview({ params }: { params: { teamId: string
{matched_free_text !== "" && <p className='p-1 mt-2 w-fit text-xs truncate border border-black rounded-md '>{"Matched " + matched_free_text}</p>}
</div>
<div className="table-cell w-48 p-4 text-center">
<p className='truncate'>{formatDateToHumanReadable(first_event_time).split(',').slice(0, 2).join(',')}</p>
<p className='truncate'>{formatDateToHumanReadableDate(first_event_time)}</p>
<div className='py-1' />
<p className='text-xs truncate'>{formatDateToHumanReadable(first_event_time).split(',').slice(2).join(',').trim()}</p>
<p className='text-xs truncate'>{formatDateToHumanReadableTime(first_event_time)}</p>
</div>
<div className="table-cell w-48 p-4 truncate text-center">{(duration as unknown as number) === 0 ? 'N/A' : formatMillisToHumanReadable(duration as unknown as number)}</div>
</Link>
Expand Down
4 changes: 2 additions & 2 deletions frontend/dashboard/app/components/copy_ai_context.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { emptyAnrExceptionsDetailsResponse, emptyCrashExceptionsDetailsResponse, ExceptionsType } from '../api/api_calls';
import { formatDateToHumanReadable } from '../utils/time_utils';
import { formatDateToHumanReadableDateTime } from '../utils/time_utils';

interface CopyAiContextProps {
appName: string,
Expand All @@ -14,7 +14,7 @@ const CopyAiContext: React.FC<CopyAiContextProps> = ({ appName, exceptionsType,

formatted = formatted + "App Name: " + appName + "\n"
formatted = formatted + "App version: " + exceptionsDetails.results[0].attribute.app_version + "\n"
formatted = formatted + "Date & time: " + formatDateToHumanReadable(exceptionsDetails.results[0].timestamp) + "\n"
formatted = formatted + "Date & time: " + formatDateToHumanReadableDateTime(exceptionsDetails.results[0].timestamp) + "\n"
formatted = formatted + "Platform: " + exceptionsDetails.results[0].attribute.platform + "\n"
formatted = formatted + "Device: " + exceptionsDetails.results[0].attribute.device_manufacturer + exceptionsDetails.results[0].attribute.device_model + "\n"
formatted = formatted + "Network type: " + exceptionsDetails.results[0].attribute.network_type + "\n"
Expand Down
4 changes: 2 additions & 2 deletions frontend/dashboard/app/components/exceptions_details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Link from "next/link";
import { ExceptionsDetailsApiStatus, ExceptionsType, emptyCrashExceptionsDetailsResponse, emptyAnrExceptionsDetailsResponse, fetchExceptionsDetailsFromServer, FiltersApiType } from '@/app/api/api_calls';
import { useRouter } from 'next/navigation';
import Paginator, { PaginationDirection } from '@/app/components/paginator';
import { formatDateToHumanReadable } from '../utils/time_utils';
import { formatDateToHumanReadableDateTime } from '../utils/time_utils';
import ExceptionspDetailsPlot from './exceptions_details_plot';
import Filters, { AppVersionsInitialSelectionType, defaultSelectedFilters } from './filters';
import Journey, { JourneyType } from './journey';
Expand Down Expand Up @@ -163,7 +163,7 @@ export const ExceptionsDetails: React.FC<ExceptionsDetailsProps> = ({ exceptions

{/* We show ... in loading state for Crash/Anr ID so that user knows some API call is happening */}
<p className="font-display text-xl"> Id: {exceptionsDetailsApiStatus == ExceptionsDetailsApiStatus.Loading ? '...' : exceptionsDetails.results[0].id}</p>
<p className="font-sans"> Date & time: {formatDateToHumanReadable(exceptionsDetails.results[0].timestamp)}</p>
<p className="font-sans"> Date & time: {formatDateToHumanReadableDateTime(exceptionsDetails.results[0].timestamp)}</p>
<p className="font-sans"> Device: {exceptionsDetails.results[0].attribute.device_manufacturer + exceptionsDetails.results[0].attribute.device_model}</p>
<p className="font-sans"> App version: {exceptionsDetails.results[0].attribute.app_version}</p>
<p className="font-sans"> Network type: {exceptionsDetails.results[0].attribute.network_type}</p>
Expand Down
4 changes: 2 additions & 2 deletions frontend/dashboard/app/components/exceptions_details_plot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react';
import { ResponsiveLine } from '@nivo/line'
import { AppVersion, ExceptionsDetailsPlotApiStatus, ExceptionsType, fetchExceptionsDetailsPlotFromServer } from '../api/api_calls';
import { useRouter } from 'next/navigation';
import { formatDateToHumanReadable } from '../utils/time_utils';
import { formatDateToHumanReadableDate } from '../utils/time_utils';

interface ExceptionsDetailsPlotProps {
appId: string,
Expand Down Expand Up @@ -147,7 +147,7 @@ const ExceptionsDetailsPlot: React.FC<ExceptionsDetailsPlotProps> = ({ appId, ex
sliceTooltip={({ slice }) => {
return (
<div className="bg-neutral-950 text-white flex flex-col p-2 text-xs">
<p className='p-2'>Date: {formatDateToHumanReadable(slice.points[0].data.xFormatted.toString())}</p>
<p className='p-2'>Date: {formatDateToHumanReadableDate(slice.points[0].data.xFormatted.toString())}</p>
{slice.points.map((point) => (
<div className="flex flex-row items-center p-2" key={point.id}>
<div className="w-2 h-2 rounded-full" style={{ backgroundColor: point.serieColor }} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react';
import { ResponsiveLine } from '@nivo/line'
import { AppVersion, ExceptionsType, ExceptionsOverviewPlotApiStatus, fetchExceptionsOverviewPlotFromServer } from '../api/api_calls';
import { useRouter } from 'next/navigation';
import { formatDateToHumanReadable } from '../utils/time_utils';
import { formatDateToHumanReadableDate } from '../utils/time_utils';

interface ExceptionsOverviewPlotProps {
appId: string,
Expand Down Expand Up @@ -155,7 +155,7 @@ const ExceptionsOverviewPlot: React.FC<ExceptionsOverviewPlotProps> = ({ appId,
sliceTooltip={({ slice }) => {
return (
<div className="bg-neutral-950 text-white flex flex-col p-2 text-xs">
<p className='p-2'>Date: {formatDateToHumanReadable(slice.points[0].data.xFormatted.toString())}</p>
<p className='p-2'>Date: {formatDateToHumanReadableDate(slice.points[0].data.xFormatted.toString())}</p>
{slice.points.map((point) => (
<div className="flex flex-row items-center p-2" key={point.id}>
<div className="w-2 h-2 rounded-full" style={{ backgroundColor: point.serieColor }} />
Expand Down
10 changes: 5 additions & 5 deletions frontend/dashboard/app/components/filters.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client"

import { useRouter } from "next/navigation";
import { formatDateToHumanReadable, formatIsoDateForDateTimeInputField, isValidTimestamp } from "../utils/time_utils";
import { formatDateToHumanReadableDateTime, formatIsoDateForDateTimeInputField, isValidTimestamp } from "../utils/time_utils";
import { useEffect, useState } from "react";
import { AppVersion, AppsApiStatus, FiltersApiStatus, FiltersApiType, SessionType, emptyApp, fetchAppsFromServer, fetchFiltersFromServer } from "../api/api_calls";
import { DateTime } from "luxon";
Expand Down Expand Up @@ -159,14 +159,14 @@ const Filters: React.FC<FiltersProps> = ({
const [dateRange, setDateRange] = useState(persistedFilters === null ? DateRange.LastWeek : persistedFilters.selectedDateRange)

const [startDate, setStartDate] = useState(persistedFilters === null ? DateTime.now().minus({ days: 7 }).toISO() : persistedFilters.selectedStartDate);
const [formattedStartDate, setFormattedStartDate] = useState(formatDateToHumanReadable(startDate));
const [formattedStartDate, setFormattedStartDate] = useState(formatDateToHumanReadableDateTime(startDate));

const [endDate, setEndDate] = useState(persistedFilters === null ? DateTime.now().toISO() : persistedFilters.selectedEndDate);
const [formattedEndDate, setFormattedEndDate] = useState(formatDateToHumanReadable(endDate));
const [formattedEndDate, setFormattedEndDate] = useState(formatDateToHumanReadableDateTime(endDate));

useEffect(() => {
setFormattedStartDate(formatDateToHumanReadable(startDate));
setFormattedEndDate(formatDateToHumanReadable(endDate));
setFormattedStartDate(formatDateToHumanReadableDateTime(startDate));
setFormattedEndDate(formatDateToHumanReadableDateTime(endDate));
}, [startDate, endDate]);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useState, useEffect, ReactNode } from 'react'
import FilterPill from './filter_pill'
import { formatDateToHumanReadable } from '../utils/time_utils'
import { formatDateToHumanReadableDateTime } from '../utils/time_utils'
import { formatToCamelCase } from '../utils/string_utils'
import Image from 'next/image';

Expand Down Expand Up @@ -177,7 +177,7 @@ export default function SessionReplayEventAccordion({
<div className="flex grow" />
<FilterPill title={threadName} />
<div className="p-2" />
<FilterPill title={`${formatDateToHumanReadable(timestamp)}`} />
<FilterPill title={`${formatDateToHumanReadableDateTime(timestamp)}`} />
</div>
</button>
<div
Expand Down
4 changes: 2 additions & 2 deletions frontend/dashboard/app/components/sessions_overview_plot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react';
import { ResponsiveLine } from '@nivo/line'
import { AppVersion, SessionType, SessionsOverviewPlotApiStatus, fetchSessionsOverviewPlotFromServer } from '../api/api_calls';
import { useRouter } from 'next/navigation';
import { formatDateToHumanReadable } from '../utils/time_utils';
import { formatDateToHumanReadableDate } from '../utils/time_utils';

interface SessionsOverviewPlotProps {
appId: string,
Expand Down Expand Up @@ -151,7 +151,7 @@ const SessionsOverviewPlot: React.FC<SessionsOverviewPlotProps> = ({ appId, star
sliceTooltip={({ slice }) => {
return (
<div className="bg-neutral-950 text-white flex flex-col p-2 text-xs">
<p className='p-2'>Date: {formatDateToHumanReadable(slice.points[0].data.xFormatted.toString()).split(',').slice(0, 2).join(',')}</p>
<p className='p-2'>Date: {formatDateToHumanReadableDate(slice.points[0].data.xFormatted.toString())}</p>
{slice.points.map((point) => (
<div className="flex flex-row items-center p-2" key={point.id}>
<div className="w-2 h-2 rounded-full" style={{ backgroundColor: point.serieColor }} />
Expand Down
26 changes: 25 additions & 1 deletion frontend/dashboard/app/utils/time_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function formatMillisToHumanReadable(millis: number) {
return output.trim().replace(/,\s*$/, ''); // Remove trailing comma if any
}

export function formatDateToHumanReadable(timestamp: string): string {
export function formatDateToHumanReadableDateTime(timestamp: string): string {
const utcDateTime = DateTime.fromISO(timestamp);

if (!utcDateTime.isValid) {
Expand All @@ -48,6 +48,30 @@ export function formatDateToHumanReadable(timestamp: string): string {
return localDateTime.toFormat('d MMM, yyyy, h:mm:ss a');
}

export function formatDateToHumanReadableDate(timestamp: string): string {
const utcDateTime = DateTime.fromISO(timestamp);

if (!utcDateTime.isValid) {
throw (utcDateTime.invalidReason)
}

const localDateTime = utcDateTime.toLocal();

return localDateTime.toFormat('d MMM, yyyy');
}

export function formatDateToHumanReadableTime(timestamp: string): string {
const utcDateTime = DateTime.fromISO(timestamp);

if (!utcDateTime.isValid) {
throw (utcDateTime.invalidReason)
}

const localDateTime = utcDateTime.toLocal();

return localDateTime.toFormat('h:mm:ss a');
}

export function formatTimestampToChartFormat(timestamp: string): string {
const utcDateTime = DateTime.fromISO(timestamp);

Expand Down

0 comments on commit 55c1b5a

Please sign in to comment.