diff --git a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx new file mode 100644 index 00000000000..7d1e50a9850 --- /dev/null +++ b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx @@ -0,0 +1,74 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { byRole, byText } from 'testing-library-selector'; +import { Props, GeneralSettingsUnconnected as GeneralSettings } from './GeneralSettings'; +import { DashboardModel } from '../../state'; + +jest.mock('@grafana/runtime', () => ({ + ...((jest.requireActual('@grafana/runtime') as unknown) as object), + getBackendSrv: () => ({ + search: jest.fn(() => [ + { title: 'A', id: 'A' }, + { title: 'B', id: 'B' }, + ]), + }), +})); + +jest.mock('app/core/services/context_srv', () => ({ + contextSrv: { + user: { orgId: 1 }, + }, +})); + +const setupTestContext = (options: Partial) => { + const defaults: Props = { + dashboard: ({ + title: 'test dashboard title', + description: 'test dashboard description', + timepicker: { + refresh_intervals: ['5s', '10s', '30s', '1m', '5m', '15m', '30m', '1h', '2h', '1d', '2d'], + time_options: ['5m', '15m', '1h', '6h', '12h', '24h', '2d', '7d', '30d'], + }, + meta: { + folderTitle: 'test', + }, + timezone: 'utc', + } as unknown) as DashboardModel, + updateTimeZone: jest.fn(), + }; + + const props = { ...defaults, ...options }; + const { rerender } = render(); + + return { rerender, props }; +}; + +const clickSelectOption = async (selectElement: HTMLElement, optionText: string): Promise => { + userEvent.click(byRole('textbox').get(selectElement)); + userEvent.click(byText(optionText).get(selectElement)); +}; + +describe('General Settings', () => { + describe('when component is mounted with timezone', () => { + it('should render correctly', () => { + setupTestContext({}); + screen.getByDisplayValue('test dashboard title'); + screen.getByDisplayValue('test dashboard description'); + expect(screen.getByLabelText('Time zone picker select container')).toHaveTextContent( + 'Coordinated Universal Time' + ); + }); + }); + + describe('when timezone is changed', () => { + it('should call update function', async () => { + const { props } = setupTestContext({}); + userEvent.click(screen.getByLabelText('Time zone picker select container')); + await clickSelectOption(screen.getByLabelText('Time zone picker select container'), 'Browser Time'); + expect(props.updateTimeZone).toHaveBeenCalledWith('browser'); + expect(props.dashboard.timezone).toBe('browser'); + }); + }); +}); diff --git a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx index cc92988f7e6..db13642ad6e 100644 --- a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx +++ b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import { connect, ConnectedProps } from 'react-redux'; import { TimeZone } from '@grafana/data'; import { TagsInput, Input, Field, CollapsableSection, RadioButtonGroup } from '@grafana/ui'; import { selectors } from '@grafana/e2e-selectors'; @@ -7,17 +8,21 @@ import { DashboardModel } from '../../state/DashboardModel'; import { DeleteDashboardButton } from '../DeleteDashboard/DeleteDashboardButton'; import { TimePickerSettings } from './TimePickerSettings'; -interface Props { +import { updateTimeZoneDashboard } from 'app/features/dashboard/state/actions'; + +interface OwnProps { dashboard: DashboardModel; } +export type Props = OwnProps & ConnectedProps; + const GRAPH_TOOLTIP_OPTIONS = [ { value: 0, label: 'Default' }, { value: 1, label: 'Shared crosshair' }, { value: 2, label: 'Shared Tooltip' }, ]; -export const GeneralSettings: React.FC = ({ dashboard }) => { +export function GeneralSettingsUnconnected({ dashboard, updateTimeZone }: Props): JSX.Element { const [renderCounter, setRenderCounter] = useState(0); const onFolderChange = (folder: { id: number; title: string }) => { @@ -51,6 +56,7 @@ export const GeneralSettings: React.FC = ({ dashboard }) => { const onTimeZoneChange = (timeZone: TimeZone) => { dashboard.timezone = timeZone; setRenderCounter(renderCounter + 1); + updateTimeZone(timeZone); }; const onTagsChange = (tags: string[]) => { @@ -126,4 +132,12 @@ export const GeneralSettings: React.FC = ({ dashboard }) => { ); +} + +const mapDispatchToProps = { + updateTimeZone: updateTimeZoneDashboard, }; + +const connector = connect(null, mapDispatchToProps); + +export const GeneralSettings = connector(GeneralSettingsUnconnected); diff --git a/public/app/features/dashboard/state/actions.ts b/public/app/features/dashboard/state/actions.ts index 05111cb5d08..4c532f8aa84 100644 --- a/public/app/features/dashboard/state/actions.ts +++ b/public/app/features/dashboard/state/actions.ts @@ -11,12 +11,14 @@ import { } from './reducers'; import { notifyApp } from 'app/core/actions'; import { loadPanelPlugin } from 'app/features/plugins/state/actions'; +import { updateTimeZoneForSession } from 'app/features/profile/state/reducers'; // Types import { DashboardAcl, DashboardAclUpdateDTO, NewDashboardAclItem, PermissionLevel, ThunkResult } from 'app/types'; import { PanelModel } from './PanelModel'; import { cancelVariables } from '../../variables/state/actions'; import { getPanelPluginNotFound } from '../dashgrid/PanelPluginError'; import { getTimeSrv } from '../services/TimeSrv'; +import { TimeZone } from '@grafana/data'; export function getDashboardPermissions(id: number): ThunkResult { return async (dispatch) => { @@ -181,3 +183,8 @@ export const cleanUpDashboardAndVariables = (): ThunkResult => (dispatch, dispatch(cleanUpDashboard()); dispatch(cancelVariables()); }; + +export const updateTimeZoneDashboard = (timeZone: TimeZone): ThunkResult => (dispatch) => { + dispatch(updateTimeZoneForSession(timeZone)); + getTimeSrv().refreshDashboard(); +};