@grafana/ui
Version:
Grafana Components Library
263 lines (258 loc) • 9.31 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var jsxRuntime = require('react/jsx-runtime');
var css = require('@emotion/css');
var React = require('react');
var reactHookForm = require('react-hook-form');
var data = require('@grafana/data');
var e2eSelectors = require('@grafana/e2e-selectors');
var i18n = require('@grafana/i18n');
var ThemeContext = require('../../../themes/ThemeContext.cjs');
var Button = require('../../Button/Button.cjs');
var Field = require('../../Forms/Field.cjs');
var Icon = require('../../Icon/Icon.cjs');
var Input = require('../../Input/Input.cjs');
var Tooltip = require('../../Tooltip/Tooltip.cjs');
var utils = require('../utils.cjs');
var TimePickerCalendar = require('./TimePickerCalendar.cjs');
"use strict";
const ERROR_MESSAGES = {
default: () => i18n.t(
"time-picker.range-content.default-error",
"Enter a date ({{dateExample}}) or relative time ({{relativeTimeExample1}}, {{relativeTimeExample2}})",
{
dateExample: "YYYY-MM-DD HH:mm:ss",
relativeTimeExample1: "now",
relativeTimeExample2: "now-1h"
}
),
range: () => i18n.t("time-picker.range-content.range-error", '"From" date must be before "To" date')
};
const TimeRangeContent = (props) => {
var _a, _b;
const {
value,
isFullscreen = false,
timeZone,
onApply: onApplyFromProps,
isReversed,
fiscalYearStartMonth,
onError,
weekStart
} = props;
const style = ThemeContext.useStyles2(getStyles);
const [isOpen, setOpen] = React.useState(false);
const {
handleSubmit,
register,
formState: { errors },
setValue,
watch
} = reactHookForm.useForm({
defaultValues: {
from: valueAsString(value.raw.from, timeZone),
to: valueAsString(value.raw.to, timeZone)
}
});
const fromFieldId = React.useId();
const toFieldId = React.useId();
React.useEffect(() => {
setValue("from", valueAsString(value.raw.from, timeZone));
setValue("to", valueAsString(value.raw.to, timeZone));
}, [value.raw.from, value.raw.to, setValue, timeZone]);
const onOpen = () => setOpen(true);
const onApply = React.useCallback(() => {
handleSubmit((data$1) => {
const raw = { from: data$1.from, to: data$1.to };
const timeRange = data.rangeUtil.convertRawToRange(raw, timeZone, fiscalYearStartMonth);
onApplyFromProps(timeRange);
})();
}, [handleSubmit, timeZone, fiscalYearStartMonth, onApplyFromProps]);
const onChange = React.useCallback(
(from, to) => {
setValue("from", valueAsString(from, timeZone));
setValue("to", valueAsString(to, timeZone));
},
[setValue, timeZone]
);
const submitOnEnter = (event) => {
if (event.key === "Enter") {
onApply();
}
};
const onCopy = () => {
const rawSource = value.raw;
const clipboardPayload = data.rangeUtil.formatRawTimeRange(rawSource);
navigator.clipboard.writeText(JSON.stringify(clipboardPayload));
};
const onPaste = async () => {
const raw = await navigator.clipboard.readText();
let range;
try {
range = JSON.parse(raw);
} catch (error) {
if (onError) {
onError(raw);
}
return;
}
setValue("from", valueAsString(range.from, timeZone));
setValue("to", valueAsString(range.to, timeZone));
};
const fiscalYear = data.rangeUtil.convertRawToRange({ from: "now/fy", to: "now/fy" }, timeZone, fiscalYearStartMonth);
const fyTooltip = /* @__PURE__ */ jsxRuntime.jsx("div", { className: style.tooltip, children: data.rangeUtil.isFiscal(value) ? /* @__PURE__ */ jsxRuntime.jsx(
Tooltip.Tooltip,
{
content: i18n.t("time-picker.range-content.fiscal-year", "Fiscal year: {{from}} - {{to}}", {
from: fiscalYear.from.format("MMM-DD"),
to: fiscalYear.to.format("MMM-DD")
}),
children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: "info-circle" })
}
) : null });
const icon = /* @__PURE__ */ jsxRuntime.jsx(
Button.Button,
{
"aria-label": i18n.t("time-picker.range-content.open-input-calendar", "Open calendar"),
"data-testid": e2eSelectors.selectors.components.TimePicker.calendar.openButton,
icon: "calendar-alt",
variant: "secondary",
type: "button",
onClick: onOpen
}
);
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: style.fieldContainer, children: [
/* @__PURE__ */ jsxRuntime.jsx(
Field.Field,
{
label: i18n.t("time-picker.range-content.from-input", "From"),
invalid: !!errors.from,
error: (_a = errors.from) == null ? void 0 : _a.message,
children: /* @__PURE__ */ jsxRuntime.jsx(
Input.Input,
{
...register("from", {
required: ERROR_MESSAGES.default(),
validate: (value2, formValues) => {
if (!utils.isValid(value2, false, timeZone)) {
return ERROR_MESSAGES.default();
}
if (!!formValues.to && utils.isValid(formValues.to, true, timeZone) && isRangeInvalid(value2, formValues.to, timeZone)) {
return ERROR_MESSAGES.range();
}
return true;
}
}),
id: fromFieldId,
onClick: (event) => event.stopPropagation(),
onKeyDown: submitOnEnter,
addonAfter: icon,
"data-testid": e2eSelectors.selectors.components.TimePicker.fromField
}
)
}
),
fyTooltip
] }),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: style.fieldContainer, children: [
/* @__PURE__ */ jsxRuntime.jsx(Field.Field, { label: i18n.t("time-picker.range-content.to-input", "To"), invalid: !!errors.to, error: (_b = errors.to) == null ? void 0 : _b.message, children: /* @__PURE__ */ jsxRuntime.jsx(
Input.Input,
{
...register("to", {
required: ERROR_MESSAGES.default(),
validate: (value2, formValues) => {
if (!utils.isValid(value2, true, timeZone)) {
return ERROR_MESSAGES.default();
}
if (!!formValues.from && utils.isValid(formValues.from, false, timeZone) && isRangeInvalid(formValues.from, value2, timeZone)) {
return ERROR_MESSAGES.range();
}
return true;
}
}),
id: toFieldId,
onClick: (event) => event.stopPropagation(),
onKeyDown: submitOnEnter,
addonAfter: icon,
"data-testid": e2eSelectors.selectors.components.TimePicker.toField
}
) }),
fyTooltip
] }),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: style.buttonsContainer, children: [
/* @__PURE__ */ jsxRuntime.jsx(
Button.Button,
{
"data-testid": e2eSelectors.selectors.components.TimePicker.copyTimeRange,
icon: "copy",
variant: "secondary",
tooltip: i18n.t("time-picker.copy-paste.tooltip-copy", "Copy time range to clipboard"),
type: "button",
onClick: onCopy
}
),
/* @__PURE__ */ jsxRuntime.jsx(
Button.Button,
{
"data-testid": e2eSelectors.selectors.components.TimePicker.pasteTimeRange,
icon: "clipboard-alt",
variant: "secondary",
tooltip: i18n.t("time-picker.copy-paste.tooltip-paste", "Paste time range"),
type: "button",
onClick: onPaste
}
),
/* @__PURE__ */ jsxRuntime.jsx(Button.Button, { "data-testid": e2eSelectors.selectors.components.TimePicker.applyTimeRange, type: "button", onClick: onApply, children: /* @__PURE__ */ jsxRuntime.jsx(i18n.Trans, { i18nKey: "time-picker.range-content.apply-button", children: "Apply time range" }) })
] }),
/* @__PURE__ */ jsxRuntime.jsx(
TimePickerCalendar,
{
isFullscreen,
isOpen,
from: data.dateTimeParse(watch("from"), { timeZone }),
to: data.dateTimeParse(watch("to"), { timeZone }),
onApply,
onClose: () => setOpen(false),
onChange,
timeZone,
isReversed,
weekStart
}
)
] });
};
function isRangeInvalid(from, to, timezone) {
const raw = { from, to };
const timeRange = data.rangeUtil.convertRawToRange(raw, timezone);
const valid = timeRange.from.isSame(timeRange.to) || timeRange.from.isBefore(timeRange.to);
return !valid;
}
function valueAsString(value, timeZone) {
if (data.isDateTime(value)) {
return data.dateTimeFormat(value, { timeZone });
}
if (value.endsWith("Z")) {
const dt = data.dateTimeParse(value);
return data.dateTimeFormat(dt, { timeZone });
}
return value;
}
function getStyles(theme) {
return {
fieldContainer: css.css({
display: "flex"
}),
buttonsContainer: css.css({
display: "flex",
gap: theme.spacing(0.5),
marginTop: theme.spacing(1)
}),
tooltip: css.css({
paddingLeft: theme.spacing(1),
paddingTop: theme.spacing(3)
})
};
}
exports.TimeRangeContent = TimeRangeContent;
//# sourceMappingURL=TimeRangeContent.cjs.map