Timepicker add local broweser time info when on hover

pull/105642/head
YUNWEN ZHENG 2 months ago
parent c03957d805
commit 4391ee83ab
No known key found for this signature in database
  1. 55
      packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.test.tsx
  2. 18
      packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx
  3. 9
      packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneDescription.tsx

@ -5,7 +5,7 @@ import { dateTime, makeTimeRange, TimeRange } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { TimeRangeProvider } from './TimeRangeContext'; import { TimeRangeProvider } from './TimeRangeContext';
import { TimeRangePicker } from './TimeRangePicker'; import { TimePickerTooltip, TimeRangePicker } from './TimeRangePicker';
const selectors = e2eSelectors.components.TimePicker; const selectors = e2eSelectors.components.TimePicker;
@ -113,3 +113,56 @@ it('does not submit wrapping forms', async () => {
expect(onSubmit).not.toHaveBeenCalled(); expect(onSubmit).not.toHaveBeenCalled();
}); });
describe('TimePickerTooltip', () => {
beforeAll(() => {
const mockIntl = {
resolvedOptions: () => ({
timeZone: 'America/New_York',
}),
};
jest.spyOn(Intl, 'DateTimeFormat').mockImplementation(() => mockIntl as Intl.DateTimeFormat);
});
afterAll(() => {
jest.restoreAllMocks();
});
const timeRange: TimeRange = {
from: dateTime('2024-01-01T00:00:00Z'),
to: dateTime('2024-01-02T00:00:00Z'),
raw: {
from: dateTime('2024-01-01T00:00:00Z'),
to: dateTime('2024-01-02T00:00:00Z'),
},
};
it('renders time range with UTC timezone', () => {
render(<TimePickerTooltip timeRange={timeRange} timeZone="utc" />);
expect(screen.getByText(/2024-01-01 00:00:00/)).toBeInTheDocument();
expect(screen.getByText('to')).toBeInTheDocument();
expect(screen.getByText(/2024-01-02 00:00:00/)).toBeInTheDocument();
expect(screen.getByTestId('time-picker-tooltip-timezone')).toHaveTextContent('UTC, GMT');
});
it('renders time range without timezone if timezone is not passed in', () => {
render(<TimePickerTooltip timeRange={timeRange} />);
expect(screen.queryByTestId('time-picker-tooltip-timezone')).not.toBeInTheDocument();
});
it('renders time range with browser timezone', () => {
render(<TimePickerTooltip timeRange={timeRange} timeZone="browser" />);
expect(screen.getByText('Local browser time')).toBeInTheDocument();
expect(screen.getByTestId('time-picker-tooltip-timezone')).toHaveTextContent('United States, EDT'); // this was mocked at the beginning, in beforeAll block
});
it('renders time range with specific timezone', () => {
render(<TimePickerTooltip timeRange={timeRange} timeZone="Africa/Accra" />);
expect(screen.getByText('Ghana, GMT')).toBeInTheDocument();
});
});

@ -13,6 +13,7 @@ import {
TimeRange, TimeRange,
TimeZone, TimeZone,
dateMath, dateMath,
getTimeZoneInfo,
} from '@grafana/data'; } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
@ -25,6 +26,7 @@ import { ToolbarButton } from '../ToolbarButton';
import { Tooltip } from '../Tooltip/Tooltip'; import { Tooltip } from '../Tooltip/Tooltip';
import { TimePickerContent } from './TimeRangePicker/TimePickerContent'; import { TimePickerContent } from './TimeRangePicker/TimePickerContent';
import { TimeZoneDescription } from './TimeZonePicker/TimeZoneDescription';
import { WeekStart } from './WeekStartPicker'; import { WeekStart } from './WeekStartPicker';
import { quickOptions } from './options'; import { quickOptions } from './options';
import { useTimeSync } from './utils/useTimeSync'; import { useTimeSync } from './utils/useTimeSync';
@ -243,16 +245,23 @@ const ZoomOutTooltip = () => (
export const TimePickerTooltip = ({ timeRange, timeZone }: { timeRange: TimeRange; timeZone?: TimeZone }) => { export const TimePickerTooltip = ({ timeRange, timeZone }: { timeRange: TimeRange; timeZone?: TimeZone }) => {
const styles = useStyles2(getLabelStyles); const styles = useStyles2(getLabelStyles);
const now = Date.now();
// Get timezone info only if timeZone is provided
const timeZoneInfo = timeZone ? getTimeZoneInfo(timeZone, now) : undefined;
return ( return (
<> <>
{dateTimeFormat(timeRange.from, { timeZone })}
<div className="text-center"> <div className="text-center">
<Trans i18nKey="time-picker.range-picker.to">to</Trans> {dateTimeFormat(timeRange.from, { timeZone })}
<div className="text-center">
<Trans i18nKey="time-picker.range-picker.to">to</Trans>
</div>
{dateTimeFormat(timeRange.to, { timeZone })}
</div> </div>
{dateTimeFormat(timeRange.to, { timeZone })} <div className={styles.container}>
<div className="text-center">
<span className={styles.utc}>{timeZoneFormatUserFriendly(timeZone)}</span> <span className={styles.utc}>{timeZoneFormatUserFriendly(timeZone)}</span>
<TimeZoneDescription testId="time-picker-tooltip-timezone" info={timeZoneInfo} />
</div> </div>
</> </>
); );
@ -321,6 +330,7 @@ const getLabelStyles = (theme: GrafanaTheme2) => {
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
columnGap: '4px',
}), }),
utc: css({ utc: css({
color: theme.v1.palette.orange, color: theme.v1.palette.orange,

@ -7,9 +7,10 @@ import { useStyles2 } from '../../../themes';
interface Props { interface Props {
info?: TimeZoneInfo; info?: TimeZoneInfo;
testId?: string;
} }
export const TimeZoneDescription = ({ info }: Props) => { export const TimeZoneDescription = ({ info, testId }: Props) => {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const description = useDescription(info); const description = useDescription(info);
@ -17,7 +18,11 @@ export const TimeZoneDescription = ({ info }: Props) => {
return null; return null;
} }
return <div className={styles.description}>{description}</div>; return (
<div data-testid={testId} className={styles.description}>
{description}
</div>
);
}; };
const useDescription = (info?: TimeZoneInfo): string => { const useDescription = (info?: TimeZoneInfo): string => {

Loading…
Cancel
Save