Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import useSearchStore from "../../SearchState/index";
import {
DATE_RANGE_POSITION,
DATE_RANGE_PROP_KEY,
TIME_RANGE_DISPLAY_TEXT_MAP,
TIME_RANGE_OPTION,
} from "./utils";


interface TimeDateInputProps {
value: string;
[DATE_RANGE_PROP_KEY]: DATE_RANGE_POSITION;
}

/**
* Input component for DatePicker that displays custom text for preset time ranges.
*
* @param props
* @return
*/
const TimeDateInput = (props: TimeDateInputProps) => {
const {value, [DATE_RANGE_PROP_KEY]: dateRange} = props;
const timeRangeOption = useSearchStore((state) => state.timeRangeOption);

const displayText = timeRangeOption === TIME_RANGE_OPTION.CUSTOM ?
value :
TIME_RANGE_DISPLAY_TEXT_MAP[timeRangeOption][dateRange];

return (
<input
{...props}
readOnly={true}
value={displayText}/>
);
};


export default TimeDateInput;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
display: inline-flex;
}

.timeRangeInputContainer :global(.ant-select) {
min-width: 150px;
}

Comment on lines +5 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this style isn't actually used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its used. It forces the size of the select for timestamp presets

/* Makes border flush with range picker */
.customSelected :global(.ant-select-selector) {
border-top-right-radius: 0 !important;
Expand All @@ -11,6 +15,5 @@
.rangePicker {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
min-width: 200px;
max-width: 220px;
min-width: 350px;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Verify 350px min-width on smaller layouts

Bumping the range picker min-width to 350px will improve readability but may squeeze very narrow layouts. Please sanity-check responsive breakpoints to ensure this does not cause horizontal overflow or wrapping issues in tighter containers.

🤖 Prompt for AI Agents
In
components/webui/client/src/pages/SearchPage/SearchControls/TimeRangeInput/index.module.css
around line 18, the hard-coded min-width: 350px may cause horizontal overflow on
narrow screens; change this to a responsive rule (for example apply min-width:
350px only at and above a specific breakpoint via a media query, or replace with
min-width: min(350px, 100%) / set width: 100% with a max-width: 350px) and
verify the range picker fits inside its parent by checking container padding and
breakpoints to prevent wrapping or overflow on small viewports.

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import {useCallback} from "react";

import {CLP_QUERY_ENGINES} from "@webui/common/config";
import {
ConfigProvider,
DatePicker,
Select,
theme,
} from "antd";
import dayjs from "dayjs";

Expand All @@ -14,6 +16,7 @@ import {PRESTO_SQL_INTERFACE} from "../../SearchState/Presto/typings";
import {SEARCH_UI_STATE} from "../../SearchState/typings";
import styles from "./index.module.css";
import TimeRangeFooter from "./Presto/TimeRangeFooter";
import TimeDateInput from "./TimeDateInput";
import {
isValidDateRange,
TIME_RANGE_OPTION,
Expand All @@ -37,6 +40,8 @@ const TimeRangeInput = () => {
searchUiState,
} = useSearchStore();

const {token} = theme.useToken();

const sqlInterface = usePrestoSearchState((state) => state.sqlInterface);
const isPrestoGuided = SETTINGS_QUERY_ENGINE === CLP_QUERY_ENGINES.PRESTO &&
sqlInterface === PRESTO_SQL_INTERFACE.GUIDED;
Expand Down Expand Up @@ -84,20 +89,32 @@ const TimeRangeInput = () => {
disabled={searchUiState === SEARCH_UI_STATE.QUERY_ID_PENDING ||
searchUiState === SEARCH_UI_STATE.QUERYING}
onChange={handleSelectChange}/>
{timeRangeOption === TIME_RANGE_OPTION.CUSTOM && (
{/* Customize disabled styling to make date strings easier to read */}
<ConfigProvider
theme={{
token: {
colorBgContainerDisabled: token.colorBgLayout,
colorTextDisabled: token.colorTextSecondary,
},
}}
>
<DatePicker.RangePicker
allowClear={true}
className={styles["rangePicker"] || ""}
renderExtraFooter={renderFooter}
showTime={true}
size={"middle"}
value={timeRange}
disabled={searchUiState === SEARCH_UI_STATE.QUERY_ID_PENDING ||
components={{
input: TimeDateInput,
}}
disabled={timeRangeOption !== TIME_RANGE_OPTION.CUSTOM ||
searchUiState === SEARCH_UI_STATE.QUERY_ID_PENDING ||
searchUiState === SEARCH_UI_STATE.QUERYING}
onCalendarChange={(dates) => {
handleRangePickerChange(dates);
}}/>
)}
</ConfigProvider>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,83 @@ const isValidDateRange = (
return null !== dates && null !== dates[0] && null !== dates[1];
};

/**
* AntD date range position.
*/
enum DATE_RANGE_POSITION {
START = "start",
END = "end",
}

/**
* AntD RangePicker prop key for date range position.
*/
const DATE_RANGE_PROP_KEY = "date-range";

/**
* Map of time range options to their display text
*/
const TIME_RANGE_DISPLAY_TEXT_MAP: Record<
TIME_RANGE_OPTION,
Record<DATE_RANGE_POSITION, string>
> = {
[TIME_RANGE_OPTION.LAST_15_MINUTES]: {
[DATE_RANGE_POSITION.START]: "15 minutes ago",
[DATE_RANGE_POSITION.END]: "Now",
},
[TIME_RANGE_OPTION.LAST_HOUR]: {
[DATE_RANGE_POSITION.START]: "1 hour ago",
[DATE_RANGE_POSITION.END]: "Now",
},
[TIME_RANGE_OPTION.TODAY]: {
[DATE_RANGE_POSITION.START]: "Start of today",
[DATE_RANGE_POSITION.END]: "End of today",
},
[TIME_RANGE_OPTION.YESTERDAY]: {
[DATE_RANGE_POSITION.START]: "Start of yesterday",
[DATE_RANGE_POSITION.END]: "End of yesterday",
},
[TIME_RANGE_OPTION.LAST_7_DAYS]: {
[DATE_RANGE_POSITION.START]: "7 days ago",
[DATE_RANGE_POSITION.END]: "Now",
},
[TIME_RANGE_OPTION.LAST_30_DAYS]: {
[DATE_RANGE_POSITION.START]: "30 days ago",
[DATE_RANGE_POSITION.END]: "Now",
},
[TIME_RANGE_OPTION.LAST_12_MONTHS]: {
[DATE_RANGE_POSITION.START]: "12 months ago",
[DATE_RANGE_POSITION.END]: "Now",
},
[TIME_RANGE_OPTION.MONTH_TO_DATE]: {
[DATE_RANGE_POSITION.START]: "Start of month",
[DATE_RANGE_POSITION.END]: "Now",
},
[TIME_RANGE_OPTION.YEAR_TO_DATE]: {
[DATE_RANGE_POSITION.START]: "Start of year",
[DATE_RANGE_POSITION.END]: "Now",
},
[TIME_RANGE_OPTION.ALL_TIME]: {
[DATE_RANGE_POSITION.START]: "First timestamp",
[DATE_RANGE_POSITION.END]: "Last timestamp",
},

// Custom option is just a placeholder for typing purposes, its values should not
// be used.
[TIME_RANGE_OPTION.CUSTOM]: {
[DATE_RANGE_POSITION.START]: "Start date",
[DATE_RANGE_POSITION.END]: "End date",
},
};
Comment on lines +125 to +192
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Display text mapping is consistent and well-typed

The DATE_RANGE_POSITION enum, DATE_RANGE_PROP_KEY, and TIME_RANGE_DISPLAY_TEXT_MAP are cleanly modelled: every TIME_RANGE_OPTION is covered, and the nested Record keeps START/END text in sync with the logical ranges (e.g., “7 days ago”/“Now”). This should make the UI text easy to maintain. Consider adding a small unit test tying TIME_RANGE_DISPLAY_TEXT_MAP to TIME_RANGE_OPTION_DAYJS_MAP so future edits do not drift in meaning.

Also applies to: 195-205

🤖 Prompt for AI Agents
components/webui/client/src/pages/SearchPage/SearchControls/TimeRangeInput/utils.tsx
around lines 125-192 (and similarly 195-205): add a small unit test that asserts
the TIME_RANGE_DISPLAY_TEXT_MAP covers exactly the same set of TIME_RANGE_OPTION
keys as TIME_RANGE_OPTION_DAYJS_MAP and that for any non-custom option the
START/END semantics are consistent (e.g., END maps to "Now" or "End ..." when
the corresponding DAYJS map end is a "now" or end-of-period sentinel); implement
the test by importing both maps/enums, comparing Object.keys(...) equality, and
spot-checking a couple representative options for expected START/END text
patterns, failing the test if any drift is detected.



export {
DATE_RANGE_POSITION,
DATE_RANGE_PROP_KEY,
DEFAULT_TIME_RANGE,
DEFAULT_TIME_RANGE_OPTION,
isValidDateRange,
TIME_RANGE_DISPLAY_TEXT_MAP,
TIME_RANGE_OPTION,
TIME_RANGE_OPTION_DAYJS_MAP,
TIME_RANGE_OPTION_NAMES,
Expand Down
Loading