export function CustomFrame()

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>
  );
}