Dashboards: WeekStart is now of type WeekStart | undefined instead of string (#101123)

* change weektype from string to WeekStart | undefined

* Change to WeekStart in more places, fix lint

* change in more places

* More weekstart changes

* fix snapshot, update betterer

* keep weekstart as '' in test dashboards to make sure it doesn't break old dashboards
This commit is contained in:
Oscar Kilhed
2025-02-24 11:35:55 +01:00
committed by GitHub
parent 5d57236a0c
commit 01b57f412f
15 changed files with 42 additions and 36 deletions

View File

@ -635,9 +635,6 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"], [0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"] [0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"]
], ],
"packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx:5381": [ "packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"] [0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
], ],
@ -3661,10 +3658,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Do not use any type assertions.", "1"],
[0, 0, 0, "Do not use any type assertions.", "2"], [0, 0, 0, "Do not use any type assertions.", "2"],
[0, 0, 0, "Do not use any type assertions.", "3"], [0, 0, 0, "Do not use any type assertions.", "3"],
[0, 0, 0, "Do not use any type assertions.", "4"], [0, 0, 0, "Unexpected any. Specify a different type.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"], [0, 0, 0, "Unexpected any. Specify a different type.", "5"],
[0, 0, 0, "Unexpected any. Specify a different type.", "6"], [0, 0, 0, "Unexpected any. Specify a different type.", "6"]
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
], ],
"public/app/features/dashboard/api/v1.ts:5381": [ "public/app/features/dashboard/api/v1.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"] [0, 0, 0, "Do not use any type assertions.", "0"]

View File

@ -48,8 +48,8 @@ export function makeNewDashboardRequestBody(dashboardName: string, folderUid?: s
timezone: '', timezone: '',
title: dashboardName, title: dashboardName,
version: 0, version: 0,
weekStart: '',
uid: '', uid: '',
weekStart: '',
}, },
message: '', message: '',
overwrite: false, overwrite: false,

View File

@ -7,8 +7,8 @@ import { Combobox } from '../Combobox/Combobox';
import { ComboboxOption } from '../Combobox/types'; import { ComboboxOption } from '../Combobox/types';
export interface Props { export interface Props {
onChange: (weekStart: WeekStart) => void; onChange: (weekStart?: WeekStart) => void;
value: string; value?: WeekStart;
width?: number; width?: number;
autoFocus?: boolean; autoFocus?: boolean;
onBlur?: () => void; onBlur?: () => void;
@ -24,9 +24,9 @@ const weekStarts: ComboboxOption[] = [
{ value: 'monday', label: 'Monday' }, { value: 'monday', label: 'Monday' },
]; ];
const isWeekStart = (value: string): value is WeekStart => { export function isWeekStart(value: string): value is WeekStart {
return ['saturday', 'sunday', 'monday'].includes(value); return ['saturday', 'sunday', 'monday'].includes(value);
}; }
declare global { declare global {
interface Window { interface Window {
@ -57,13 +57,13 @@ export const WeekStartPicker = (props: Props) => {
const onChangeWeekStart = useCallback( const onChangeWeekStart = useCallback(
(selectable: ComboboxOption | null) => { (selectable: ComboboxOption | null) => {
if (selectable && selectable.value !== undefined) { if (selectable && selectable.value !== undefined) {
onChange(selectable.value as WeekStart); onChange(isWeekStart(selectable.value) ? selectable.value : undefined);
} }
}, },
[onChange] [onChange]
); );
const selected = useMemo(() => weekStarts.find((item) => item.value === value)?.value ?? null, [value]); const selected = useMemo(() => weekStarts.find((item) => item.value === value)?.value ?? '', [value]);
return ( return (
<Combobox <Combobox

View File

@ -40,7 +40,7 @@ export { TimePickerTooltip } from './DateTimePickers/TimeRangePicker';
export { TimeRangeLabel } from './DateTimePickers/TimeRangePicker/TimeRangeLabel'; export { TimeRangeLabel } from './DateTimePickers/TimeRangePicker/TimeRangeLabel';
export { TimeOfDayPicker } from './DateTimePickers/TimeOfDayPicker'; export { TimeOfDayPicker } from './DateTimePickers/TimeOfDayPicker';
export { TimeZonePicker } from './DateTimePickers/TimeZonePicker'; export { TimeZonePicker } from './DateTimePickers/TimeZonePicker';
export { WeekStartPicker, getWeekStart, type WeekStart } from './DateTimePickers/WeekStartPicker'; export { WeekStartPicker, getWeekStart, type WeekStart, isWeekStart } from './DateTimePickers/WeekStartPicker';
export { DatePicker, type DatePickerProps } from './DateTimePickers/DatePicker/DatePicker'; export { DatePicker, type DatePickerProps } from './DateTimePickers/DatePicker/DatePicker';
export { export {
DatePickerWithInput, DatePickerWithInput,

View File

@ -18,13 +18,14 @@ import {
Combobox, Combobox,
ComboboxOption, ComboboxOption,
TextLink, TextLink,
WeekStart,
isWeekStart,
} from '@grafana/ui'; } from '@grafana/ui';
import { DashboardPicker } from 'app/core/components/Select/DashboardPicker'; import { DashboardPicker } from 'app/core/components/Select/DashboardPicker';
import { t, Trans } from 'app/core/internationalization'; import { t, Trans } from 'app/core/internationalization';
import { LANGUAGES, PSEUDO_LOCALE } from 'app/core/internationalization/constants'; import { LANGUAGES, PSEUDO_LOCALE } from 'app/core/internationalization/constants';
import { PreferencesService } from 'app/core/services/PreferencesService'; import { PreferencesService } from 'app/core/services/PreferencesService';
import { changeTheme } from 'app/core/services/theme'; import { changeTheme } from 'app/core/services/theme';
export interface Props { export interface Props {
resourceUri: string; resourceUri: string;
disabled?: boolean; disabled?: boolean;
@ -152,8 +153,8 @@ export class SharedPreferences extends PureComponent<Props, State> {
this.setState({ timezone: timezone }); this.setState({ timezone: timezone });
}; };
onWeekStartChanged = (weekStart: string) => { onWeekStartChanged = (weekStart?: WeekStart) => {
this.setState({ weekStart: weekStart }); this.setState({ weekStart: weekStart ?? '' });
}; };
onHomeDashboardChanged = (dashboardUID: string) => { onHomeDashboardChanged = (dashboardUID: string) => {
@ -249,7 +250,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
data-testid={selectors.components.WeekStartPicker.containerV2} data-testid={selectors.components.WeekStartPicker.containerV2}
> >
<WeekStartPicker <WeekStartPicker
value={weekStart || ''} value={weekStart && isWeekStart(weekStart) ? weekStart : undefined}
onChange={this.onWeekStartChanged} onChange={this.onWeekStartChanged}
inputId="shared-preferences-week-start-picker" inputId="shared-preferences-week-start-picker"
/> />

View File

@ -334,7 +334,6 @@ exports[`transformSceneToSaveModel Given a scene with rows Should transform back
"title": "Repeating rows", "title": "Repeating rows",
"uid": "Repeating-rows-uid", "uid": "Repeating-rows-uid",
"version": 1, "version": 1,
"weekStart": "",
} }
`; `;

View File

@ -22,6 +22,7 @@ import {
SceneInteractionProfileEvent, SceneInteractionProfileEvent,
SceneObjectState, SceneObjectState,
} from '@grafana/scenes'; } from '@grafana/scenes';
import { isWeekStart } from '@grafana/ui';
import { contextSrv } from 'app/core/core'; import { contextSrv } from 'app/core/core';
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel'; import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { PanelModel } from 'app/features/dashboard/state/PanelModel'; import { PanelModel } from 'app/features/dashboard/state/PanelModel';
@ -274,7 +275,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel,
to: oldModel.time.to, to: oldModel.time.to,
fiscalYearStartMonth: oldModel.fiscalYearStartMonth, fiscalYearStartMonth: oldModel.fiscalYearStartMonth,
timeZone: oldModel.timezone, timeZone: oldModel.timezone,
weekStart: oldModel.weekStart, weekStart: isWeekStart(oldModel.weekStart) ? oldModel.weekStart : undefined,
UNSAFE_nowDelay: oldModel.timepicker?.nowDelay, UNSAFE_nowDelay: oldModel.timepicker?.nowDelay,
}), }),
$variables: variables, $variables: variables,

View File

@ -123,7 +123,7 @@ export class GeneralSettingsEditView
}); });
}; };
public onWeekStartChange = (value: WeekStart) => { public onWeekStartChange = (value?: WeekStart) => {
this.getTimeRange().setState({ weekStart: value }); this.getTimeRange().setState({ weekStart: value });
}; };
@ -258,7 +258,7 @@ export class GeneralSettingsEditView
nowDelay={nowDelay || ''} nowDelay={nowDelay || ''}
liveNow={liveNow} liveNow={liveNow}
timezone={timeZone || ''} timezone={timeZone || ''}
weekStart={weekStart || ''} weekStart={weekStart}
/> />
{/* @todo: Update "Graph tooltip" description to remove prompt about reloading when resolving #46581 */} {/* @todo: Update "Graph tooltip" description to remove prompt about reloading when resolving #46581 */}

View File

@ -41,7 +41,7 @@ import {
GridLayoutItemKind, GridLayoutItemKind,
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0'; } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
import { DashboardLink, DataTransformerConfig } from '@grafana/schema/src/raw/dashboard/x/dashboard_types.gen'; import { DashboardLink, DataTransformerConfig } from '@grafana/schema/src/raw/dashboard/x/dashboard_types.gen';
import { WeekStart } from '@grafana/ui'; import { isWeekStart, WeekStart } from '@grafana/ui';
import { import {
AnnoKeyCreatedBy, AnnoKeyCreatedBy,
AnnoKeyDashboardGnetId, AnnoKeyDashboardGnetId,
@ -161,8 +161,7 @@ export function ensureV2Response(
fiscalYearStartMonth: dashboard.fiscalYearStartMonth || timeSettingsDefaults.fiscalYearStartMonth, fiscalYearStartMonth: dashboard.fiscalYearStartMonth || timeSettingsDefaults.fiscalYearStartMonth,
hideTimepicker: dashboard.timepicker?.hidden || timeSettingsDefaults.hideTimepicker, hideTimepicker: dashboard.timepicker?.hidden || timeSettingsDefaults.hideTimepicker,
quickRanges: dashboard.timepicker?.quick_ranges, quickRanges: dashboard.timepicker?.quick_ranges,
// casting WeekStart here to avoid editing old schema weekStart: getWeekStart(dashboard.weekStart, timeSettingsDefaults.weekStart),
weekStart: (dashboard.weekStart as WeekStart) || timeSettingsDefaults.weekStart,
nowDelay: dashboard.timepicker?.nowDelay || timeSettingsDefaults.nowDelay, nowDelay: dashboard.timepicker?.nowDelay || timeSettingsDefaults.nowDelay,
}, },
links: dashboard.links || [], links: dashboard.links || [],
@ -332,6 +331,13 @@ function isRowPanel(panel: Panel | RowPanel): panel is RowPanel {
return panel.type === 'row'; return panel.type === 'row';
} }
function getWeekStart(weekStart?: string, defaultWeekStart?: WeekStart): WeekStart | undefined {
if (!weekStart || !isWeekStart(weekStart)) {
return defaultWeekStart;
}
return weekStart;
}
function buildRowKind(p: RowPanel, elements: GridLayoutItemKind[]): GridLayoutRowKind { function buildRowKind(p: RowPanel, elements: GridLayoutItemKind[]): GridLayoutRowKind {
return { return {
kind: 'GridLayoutRow', kind: 'GridLayoutRow',

View File

@ -3,7 +3,7 @@ import { Unsubscribable } from 'rxjs';
import { dateMath, TimeRange, TimeZone } from '@grafana/data'; import { dateMath, TimeRange, TimeZone } from '@grafana/data';
import { TimeRangeUpdatedEvent } from '@grafana/runtime'; import { TimeRangeUpdatedEvent } from '@grafana/runtime';
import { defaultIntervals, RefreshPicker } from '@grafana/ui'; import { defaultIntervals, isWeekStart, RefreshPicker } from '@grafana/ui';
import { TimePickerWithHistory } from 'app/core/components/TimePicker/TimePickerWithHistory'; import { TimePickerWithHistory } from 'app/core/components/TimePicker/TimePickerWithHistory';
import { appEvents } from 'app/core/core'; import { appEvents } from 'app/core/core';
import { t } from 'app/core/internationalization'; import { t } from 'app/core/internationalization';
@ -121,7 +121,7 @@ export class DashNavTimeControls extends Component<Props> {
onChangeFiscalYearStartMonth={this.onChangeFiscalYearStartMonth} onChangeFiscalYearStartMonth={this.onChangeFiscalYearStartMonth}
isOnCanvas={isOnCanvas} isOnCanvas={isOnCanvas}
onToolbarTimePickerClick={this.props.onToolbarTimePickerClick} onToolbarTimePickerClick={this.props.onToolbarTimePickerClick}
weekStart={weekStart} weekStart={isWeekStart(weekStart) ? weekStart : undefined}
quickRanges={quick_ranges} quickRanges={quick_ranges}
/> />
<RefreshPicker <RefreshPicker

View File

@ -13,6 +13,7 @@ import {
TextArea, TextArea,
Box, Box,
Stack, Stack,
WeekStart,
} from '@grafana/ui'; } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page'; import { Page } from 'app/core/components/Page/Page';
import { FolderPicker } from 'app/core/components/Select/FolderPicker'; import { FolderPicker } from 'app/core/components/Select/FolderPicker';
@ -97,7 +98,7 @@ export function GeneralSettingsUnconnected({
updateTimeZone(timeZone); updateTimeZone(timeZone);
}; };
const onWeekStartChange = (weekStart: string) => { const onWeekStartChange = (weekStart?: WeekStart) => {
dashboard.weekStart = weekStart; dashboard.weekStart = weekStart;
setRenderCounter(renderCounter + 1); setRenderCounter(renderCounter + 1);
updateWeekStart(weekStart); updateWeekStart(weekStart);

View File

@ -10,7 +10,7 @@ import { t } from 'app/core/internationalization';
import { AutoRefreshIntervals } from './AutoRefreshIntervals'; import { AutoRefreshIntervals } from './AutoRefreshIntervals';
interface Props { interface Props {
onWeekStartChange: (weekStart: WeekStart) => void; onWeekStartChange: (weekStart?: WeekStart) => void;
onTimeZoneChange: (timeZone: TimeZone) => void; onTimeZoneChange: (timeZone: TimeZone) => void;
onRefreshIntervalChange: (interval: string[]) => void; onRefreshIntervalChange: (interval: string[]) => void;
onNowDelayChange: (nowDelay: string) => void; onNowDelayChange: (nowDelay: string) => void;
@ -20,7 +20,7 @@ interface Props {
timePickerHidden?: boolean; timePickerHidden?: boolean;
nowDelay?: string; nowDelay?: string;
timezone: TimeZone; timezone: TimeZone;
weekStart: string; weekStart?: WeekStart;
liveNow?: boolean; liveNow?: boolean;
} }
@ -62,7 +62,7 @@ export class TimePickerSettings extends PureComponent<Props, State> {
this.props.onTimeZoneChange(timeZone); this.props.onTimeZoneChange(timeZone);
}; };
onWeekStartChange = (weekStart: WeekStart) => { onWeekStartChange = (weekStart?: WeekStart) => {
this.props.onWeekStartChange(weekStart); this.props.onWeekStartChange(weekStart);
}; };

View File

@ -1,5 +1,6 @@
import { TimeZone } from '@grafana/data'; import { TimeZone } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
import { WeekStart } from '@grafana/ui';
import { notifyApp } from 'app/core/actions'; import { notifyApp } from 'app/core/actions';
import { createSuccessNotification } from 'app/core/copy/appNotification'; import { createSuccessNotification } from 'app/core/copy/appNotification';
import { getDashboardAPI } from 'app/features/dashboard/api/dashboard_api'; import { getDashboardAPI } from 'app/features/dashboard/api/dashboard_api';
@ -56,7 +57,7 @@ export const updateTimeZoneDashboard =
}; };
export const updateWeekStartDashboard = export const updateWeekStartDashboard =
(weekStart: string): ThunkResult<void> => (weekStart?: WeekStart): ThunkResult<void> =>
(dispatch) => { (dispatch) => {
dispatch(updateWeekStartForSession(weekStart)); dispatch(updateWeekStartForSession(weekStart));
getTimeSrv().refreshTimeModel(); getTimeSrv().refreshTimeModel();

View File

@ -273,7 +273,7 @@ export function initDashboard(args: InitDashboardArgs): ThunkResult<void> {
} }
// set week start // set week start
if (dashboard.weekStart !== '') { if (dashboard.weekStart !== '' && dashboard.weekStart !== undefined) {
setWeekStart(dashboard.weekStart); setWeekStart(dashboard.weekStart);
} else { } else {
setWeekStart(config.bootData.user.weekStart); setWeekStart(config.bootData.user.weekStart);

View File

@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { isEmpty, isString, set } from 'lodash'; import { isEmpty, isString, set } from 'lodash';
import { dateTimeFormatTimeAgo, setWeekStart, TimeZone } from '@grafana/data'; import { dateTimeFormatTimeAgo, setWeekStart, TimeZone } from '@grafana/data';
import { getWeekStart, WeekStart } from '@grafana/ui';
import config from 'app/core/config'; import config from 'app/core/config';
import { contextSrv } from 'app/core/core'; import { contextSrv } from 'app/core/core';
import { Team, ThunkResult, UserDTO, UserOrg, UserSession } from 'app/types'; import { Team, ThunkResult, UserDTO, UserOrg, UserSession } from 'app/types';
@ -116,10 +117,10 @@ export const updateTimeZoneForSession = (timeZone: TimeZone): ThunkResult<void>
}; };
}; };
export const updateWeekStartForSession = (weekStart: string): ThunkResult<void> => { export const updateWeekStartForSession = (weekStart?: WeekStart): ThunkResult<void> => {
return async (dispatch) => { return async (dispatch) => {
if (!isString(weekStart) || isEmpty(weekStart)) { if (!weekStart) {
weekStart = config?.bootData?.user?.weekStart; weekStart = getWeekStart();
} }
set(contextSrv, 'user.weekStart', weekStart); set(contextSrv, 'user.weekStart', weekStart);