mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* replace rc-time-picker with rc-picker * remove unnecessary stack * remove TimePickerInput * make props stricter * fix type assertions * remove outdated comment * fix types * fix clear icon * fix styling * fix z-index and 6 tests * fix remaining unit tests * betterer results * styling tweaks * don't show/hide scrollbars on hover
192 lines
5.4 KiB
TypeScript
192 lines
5.4 KiB
TypeScript
import { css } from '@emotion/css';
|
|
import moment, { Moment } from 'moment/moment';
|
|
import { useState } from 'react';
|
|
|
|
import { dateTimeAsMoment, getTimeZoneInfo, GrafanaTheme2, isDateTime, SelectableValue } from '@grafana/data';
|
|
import { Button, Field, FieldSet, Select, Stack, TimeOfDayPicker, TimeZonePicker, useStyles2 } from '@grafana/ui';
|
|
import { TimeZoneOffset } from '@grafana/ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOffset';
|
|
import { TimeZoneTitle } from '@grafana/ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneTitle';
|
|
import { TimeRegionConfig } from 'app/core/utils/timeRegions';
|
|
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
|
|
|
interface Props {
|
|
value: TimeRegionConfig;
|
|
onChange: (value?: TimeRegionConfig) => void;
|
|
}
|
|
|
|
const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'].map((v, idx) => {
|
|
return {
|
|
label: v,
|
|
value: idx + 1,
|
|
};
|
|
});
|
|
export const TimeRegionEditor = ({ value, onChange }: Props) => {
|
|
const styles = useStyles2(getStyles);
|
|
const timestamp = Date.now();
|
|
const timezoneInfo = getTimeZoneInfo(value.timezone ?? 'utc', timestamp);
|
|
const isDashboardTimezone = getDashboardSrv().getCurrent()?.getTimezone() === value.timezone;
|
|
|
|
const [isEditing, setEditing] = useState(false);
|
|
|
|
const onToggleChangeTimezone = () => {
|
|
setEditing(!isEditing);
|
|
};
|
|
|
|
const getTime = (time: string | undefined): Moment | undefined => {
|
|
if (!time) {
|
|
return undefined;
|
|
}
|
|
|
|
const date = moment();
|
|
|
|
if (time) {
|
|
const match = time.split(':');
|
|
date.set('hour', parseInt(match[0], 10));
|
|
date.set('minute', parseInt(match[1], 10));
|
|
}
|
|
|
|
return date;
|
|
};
|
|
|
|
const getToPlaceholder = () => {
|
|
let placeholder = 'Everyday';
|
|
if (value.fromDayOfWeek && !value.toDayOfWeek) {
|
|
placeholder = days[value.fromDayOfWeek - 1].label;
|
|
}
|
|
|
|
return placeholder;
|
|
};
|
|
|
|
const renderTimezonePicker = () => {
|
|
const timezone = (
|
|
<>
|
|
<TimeZoneTitle title={timezoneInfo?.name} />
|
|
<TimeZoneOffset timeZone={value.timezone} timestamp={timestamp} />
|
|
</>
|
|
);
|
|
|
|
if (isDashboardTimezone) {
|
|
return <>Dashboard timezone ({timezone})</>;
|
|
}
|
|
|
|
return timezone;
|
|
};
|
|
|
|
const onTimeChange = (v: Moment | undefined, field: string) => {
|
|
const time = v ? v.format('HH:mm') : undefined;
|
|
if (field === 'from') {
|
|
onChange({ ...value, from: time });
|
|
} else {
|
|
onChange({ ...value, to: time });
|
|
}
|
|
};
|
|
|
|
const onTimezoneChange = (v: string | undefined) => {
|
|
onChange({ ...value, timezone: v });
|
|
};
|
|
|
|
const onFromDayOfWeekChange = (v: SelectableValue<number>) => {
|
|
const fromDayOfWeek = v ? v.value : undefined;
|
|
const toDayOfWeek = v ? value.toDayOfWeek : undefined; // clear if everyday
|
|
onChange({ ...value, fromDayOfWeek, toDayOfWeek });
|
|
};
|
|
|
|
const onToDayOfWeekChange = (v: SelectableValue<number>) => {
|
|
onChange({ ...value, toDayOfWeek: v ? v.value : undefined });
|
|
};
|
|
|
|
const renderTimezone = () => {
|
|
if (isEditing) {
|
|
return (
|
|
<TimeZonePicker
|
|
value={value.timezone}
|
|
includeInternal={true}
|
|
onChange={(v) => onTimezoneChange(v)}
|
|
onBlur={() => setEditing(false)}
|
|
openMenuOnFocus={false}
|
|
width={100}
|
|
autoFocus
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className={styles.timezoneContainer}>
|
|
<div className={styles.timezone}>{renderTimezonePicker()}</div>
|
|
<Button variant="secondary" onClick={onToggleChangeTimezone} size="sm">
|
|
Change timezone
|
|
</Button>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const from = getTime(value.from);
|
|
const to = getTime(value.to);
|
|
|
|
return (
|
|
<FieldSet className={styles.wrapper}>
|
|
<Field label="From">
|
|
<Stack gap={0.5}>
|
|
<Select
|
|
options={days}
|
|
isClearable
|
|
placeholder="Everyday"
|
|
value={value.fromDayOfWeek ?? null}
|
|
onChange={(v) => onFromDayOfWeekChange(v)}
|
|
width={20}
|
|
/>
|
|
<TimeOfDayPicker
|
|
value={isDateTime(from) ? from : undefined}
|
|
onChange={(v) => onTimeChange(v ? dateTimeAsMoment(v) : v, 'from')}
|
|
allowEmpty={true}
|
|
placeholder="HH:mm"
|
|
size="sm"
|
|
/>
|
|
</Stack>
|
|
</Field>
|
|
<Field label="To">
|
|
<Stack gap={0.5}>
|
|
{(value.fromDayOfWeek || value.toDayOfWeek) && (
|
|
<Select
|
|
options={days}
|
|
isClearable
|
|
placeholder={getToPlaceholder()}
|
|
value={value.toDayOfWeek ?? null}
|
|
onChange={(v) => onToDayOfWeekChange(v)}
|
|
width={20}
|
|
/>
|
|
)}
|
|
<TimeOfDayPicker
|
|
value={isDateTime(to) ? to : undefined}
|
|
onChange={(v) => onTimeChange(v ? dateTimeAsMoment(v) : v, 'to')}
|
|
allowEmpty={true}
|
|
placeholder="HH:mm"
|
|
size="sm"
|
|
/>
|
|
</Stack>
|
|
</Field>
|
|
<Field label="Timezone">{renderTimezone()}</Field>
|
|
</FieldSet>
|
|
);
|
|
};
|
|
|
|
const getStyles = (theme: GrafanaTheme2) => {
|
|
return {
|
|
wrapper: css({
|
|
maxWidth: theme.spacing(60),
|
|
marginBottom: theme.spacing(2),
|
|
}),
|
|
timezoneContainer: css({
|
|
padding: '5px',
|
|
display: 'flex',
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
fontSize: '12px',
|
|
}),
|
|
timezone: css({
|
|
marginRight: '5px',
|
|
}),
|
|
};
|
|
};
|