in superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx [45:275]
export function CustomFrame(props: FrameComponentProps) {
const { customRange, matchedFlag } = customTimeRangeDecode(props.value);
const datePickerLocale = useLocale();
if (!matchedFlag) {
props.onChange(customTimeRangeEncode(customRange));
}
const {
sinceDatetime,
sinceMode,
sinceGrain,
sinceGrainValue,
untilDatetime,
untilMode,
untilGrain,
untilGrainValue,
anchorValue,
anchorMode,
} = { ...customRange };
function onChange(control: CustomRangeKey, value: string) {
props.onChange(
customTimeRangeEncode({
...customRange,
[control]: value,
}),
);
}
function onGrainValue(
control: 'sinceGrainValue' | 'untilGrainValue',
value: string | number,
) {
// only positive values in grainValue controls
if (typeof value === 'number' && Number.isInteger(value) && value > 0) {
props.onChange(
customTimeRangeEncode({
...customRange,
[control]: value,
}),
);
}
}
function onAnchorMode(option: any) {
const radioValue = option.target.value;
if (radioValue === 'now') {
props.onChange(
customTimeRangeEncode({
...customRange,
anchorValue: 'now',
anchorMode: radioValue,
}),
);
} else {
props.onChange(
customTimeRangeEncode({
...customRange,
anchorValue: MIDNIGHT,
anchorMode: radioValue,
}),
);
}
}
if (datePickerLocale === null) {
return <Loading position="inline-centered" />;
}
return (
<AntdThemeProvider locale={datePickerLocale}>
<div data-test="custom-frame">
<div className="section-title">{t('Configure custom time range')}</div>
<Row gutter={24}>
<Col span={12}>
<div className="control-label">
{t('START (INCLUSIVE)')}{' '}
<InfoTooltipWithTrigger
tooltip={t('Start date included in time range')}
placement="right"
/>
</div>
<Select
ariaLabel={t('START (INCLUSIVE)')}
options={SINCE_MODE_OPTIONS}
value={sinceMode}
onChange={(value: string) => onChange('sinceMode', value)}
/>
{sinceMode === 'specific' && (
<Row>
<DatePicker
showTime
defaultValue={dttmToDayjs(sinceDatetime)}
onChange={(datetime: Dayjs) =>
onChange('sinceDatetime', datetime.format(DAYJS_FORMAT))
}
allowClear={false}
getPopupContainer={(triggerNode: HTMLElement) =>
props.isOverflowingFilterBar
? (triggerNode.parentNode as HTMLElement)
: document.body
}
/>
</Row>
)}
{sinceMode === 'relative' && (
<Row gutter={8}>
<Col span={11}>
{/* Make sure sinceGrainValue looks like a positive integer */}
<InputNumber
placeholder={t('Relative quantity')}
value={Math.abs(sinceGrainValue)}
min={1}
defaultValue={1}
onChange={value =>
onGrainValue('sinceGrainValue', value || 1)
}
onStep={value =>
onGrainValue('sinceGrainValue', value || 1)
}
/>
</Col>
<Col span={13}>
<Select
ariaLabel={t('Relative period')}
options={SINCE_GRAIN_OPTIONS}
value={sinceGrain}
onChange={(value: string) => onChange('sinceGrain', value)}
/>
</Col>
</Row>
)}
</Col>
<Col span={12}>
<div className="control-label">
{t('END (EXCLUSIVE)')}{' '}
<InfoTooltipWithTrigger
tooltip={t('End date excluded from time range')}
placement="right"
/>
</div>
<Select
ariaLabel={t('END (EXCLUSIVE)')}
options={UNTIL_MODE_OPTIONS}
value={untilMode}
onChange={(value: string) => onChange('untilMode', value)}
/>
{untilMode === 'specific' && (
<Row>
<DatePicker
showTime
defaultValue={dttmToDayjs(untilDatetime)}
onChange={(datetime: Dayjs) =>
onChange('untilDatetime', datetime.format(DAYJS_FORMAT))
}
allowClear={false}
getPopupContainer={(triggerNode: HTMLElement) =>
props.isOverflowingFilterBar
? (triggerNode.parentNode as HTMLElement)
: document.body
}
/>
</Row>
)}
{untilMode === 'relative' && (
<Row gutter={8}>
<Col span={11}>
<InputNumber
placeholder={t('Relative quantity')}
value={untilGrainValue}
min={1}
defaultValue={1}
onChange={value =>
onGrainValue('untilGrainValue', value || 1)
}
onStep={value =>
onGrainValue('untilGrainValue', value || 1)
}
/>
</Col>
<Col span={13}>
<Select
ariaLabel={t('Relative period')}
options={UNTIL_GRAIN_OPTIONS}
value={untilGrain}
onChange={(value: string) => onChange('untilGrain', value)}
/>
</Col>
</Row>
)}
</Col>
</Row>
{sinceMode === 'relative' && untilMode === 'relative' && (
<div className="control-anchor-to">
<div className="control-label">{t('Anchor to')}</div>
<Row align="middle">
<Col>
<Radio.GroupWrapper
options={[
{ value: 'now', label: t('Now') },
{ value: 'specific', label: t('Date/Time') },
]}
onChange={onAnchorMode}
defaultValue="now"
value={anchorMode}
/>
</Col>
{anchorMode !== 'now' && (
<Col>
<DatePicker
showTime
defaultValue={dttmToDayjs(anchorValue)}
onChange={(datetime: Dayjs) =>
onChange('anchorValue', datetime.format(DAYJS_FORMAT))
}
allowClear={false}
className="control-anchor-to-datetime"
getPopupContainer={(triggerNode: HTMLElement) =>
props.isOverflowingFilterBar
? (triggerNode.parentNode as HTMLElement)
: document.body
}
/>
</Col>
)}
</Row>
</div>
)}
</div>
</AntdThemeProvider>
);
}