codeant-ai-for-open-source[bot] commented on code in PR #41527:
URL: https://github.com/apache/superset/pull/41527#discussion_r3503494478
##########
superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx:
##########
@@ -16,26 +16,128 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { useEffect, useState } from 'react';
import { t } from '@apache-superset/core/translation';
+import { InputNumber, Select } from '@superset-ui/core/components';
import { Radio } from '@superset-ui/core/components/Radio';
import {
COMMON_RANGE_OPTIONS,
- COMMON_RANGE_SET,
+ COMMON_RANGE_REGEX,
DateFilterTestKey,
} from 'src/explore/components/controls/DateFilterControl/utils';
import {
- CommonRangeType,
FrameComponentProps,
} from 'src/explore/components/controls/DateFilterControl/types';
+const PRESET_VALUES = new Set(COMMON_RANGE_OPTIONS.map(o => o.value as
string));
+
+/** Sentinel value used as the radio option value for the custom "Other" row.
*/
+const CUSTOM_SENTINEL = '__custom__';
+
+const UNIT_OPTIONS = [
+ { value: 'second', label: t('Seconds') },
+ { value: 'minute', label: t('Minutes') },
+ { value: 'hour', label: t('Hours') },
+ { value: 'day', label: t('Days') },
+ { value: 'week', label: t('Weeks') },
+ { value: 'month', label: t('Months') },
+ { value: 'quarter', label: t('Quarters') },
+ { value: 'year', label: t('Years') },
+];
+
+/**
+ * Parse "Last N unit(s)" into { n, unit }, returns null for preset-style
+ * strings without an explicit number (e.g. "Last day").
+ */
+function parseLastN(value: string): { n: number; unit: string } | null {
+ const m = value.match(COMMON_RANGE_REGEX);
+ // m[1] is the optional "<number> " capture group — absent for preset-style
+ // strings like "Last week" that have no explicit number.
+ if (!m || m[1] === undefined) return null;
+ return { n: parseInt(m[1], 10), unit: m[2].toLowerCase() };
+}
+
+/** Build the canonical "Last N unit(s)" string from parts. */
+function buildLastN(n: number, unit: string): string {
+ return `Last ${n} ${unit}${n !== 1 ? 's' : ''}`;
+}
+
export function CommonFrame(props: FrameComponentProps) {
- let commonRange = 'Last week';
- if (COMMON_RANGE_SET.has(props.value as CommonRangeType)) {
- commonRange = props.value;
- } else {
- props.onChange(commonRange);
+ const isPreset = PRESET_VALUES.has(props.value);
+ const parsedCustom = parseLastN(props.value);
+ const isCustom = !isPreset && parsedCustom !== null;
+
+ // Local state for the custom inputs — persists across preset ↔ Other
switches.
+ // Default to 4 hours so the initial "Other" emission ("Last 4 hours") never
+ // accidentally matches a preset and causes the radio to snap back.
+ const [customN, setCustomN] = useState<number>(parsedCustom?.n ?? 4);
+ const [customUnit, setCustomUnit] = useState<string>(
+ parsedCustom?.unit ?? 'hour',
+ );
Review Comment:
**Suggestion:** The custom “Other” state is initialized from any parsable
`Last N unit` value, including numeric presets like `Last 5 minutes` and `Last
1 hour`. When users click “Other” while one of those presets is selected, the
emitted value is still the same preset string, so the control remains on the
preset and “Other” cannot actually be selected. Initialize custom state only
from non-preset custom values (or from a dedicated stored custom draft) so
selecting “Other” always emits a non-preset value. [incorrect condition logic]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ CommonFrame cannot switch from numeric preset to Other.
- ⚠️ Explore/dashboard time filters hinder custom sub-hour ranges.
```
</details>
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Open a chart in Explore or a dashboard and open the time range control;
the overlay is
rendered by DateFilterLabel at
/workspace/superset/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx
lines 15-27, which passes `timeRangeValue` into <CommonFrame
value={timeRangeValue}
onChange={setTimeRangeValue} /> when `frame === 'Common'`.
2. In the Common frame, select a numeric preset such as “Last 5 minutes” or
“Last 1 hour”
from the radio group; these presets are defined in COMMON_RANGE_OPTIONS at
/workspace/superset/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts
lines 7-16, and the selection updates `timeRangeValue` to the chosen string,
e.g. “Last 5
minutes”.
3. With `props.value` now equal to a numeric preset like “Last 5 minutes”,
CommonFrame at
/workspace/superset/superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx
lines 65-76 computes `isPreset = PRESET_VALUES.has(props.value)` (line 66,
using
PRESET_VALUES from line 32) and `parsedCustom = parseLastN(props.value)`
(lines 52-57,
using COMMON_RANGE_REGEX from constants.ts lines 24-25); `parseLastN`
successfully parses
the preset, so `parsedCustom` is `{ n: 5, unit: 'minute' }`, and
`customN`/`customUnit`
are initialized from this preset at lines 73-76.
4. Click the “Other” radio row (the custom option appended to `options` at
lines 136-139
with value CUSTOM_SENTINEL); Radio.GroupWrapper at lines 146-157 calls
`handleRadioChange`
(lines 88-95) with `val === CUSTOM_SENTINEL`, which in turn calls
`props.onChange(buildLastN(customN, customUnit))`. Since `customN` and
`customUnit` were
initialized from the numeric preset, `buildLastN` (lines 60-62) emits the
same preset
string (e.g. “Last 5 minutes”), leaving `props.value` equal to a preset. On
the next
render, `isPreset` remains true and `isCustom` false (line 68), so
`radioValue` is set to
`props.value` (line 86) rather than CUSTOM_SENTINEL, causing the radio
selection to stay
on the preset and making “Other” effectively unselectable when starting from
these numeric
presets.
```
</details>
[](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=7bdd9f231cf6489eb30d3fe8ac5d301d&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
[](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=7bdd9f231cf6489eb30d3fe8ac5d301d&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
*(Use Cmd/Ctrl + Click for best experience)*
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:**
superset-frontend/src/explore/components/controls/DateFilterControl/components/CommonFrame.tsx
**Line:** 73:76
**Comment:**
*Incorrect Condition Logic: The custom “Other” state is initialized
from any parsable `Last N unit` value, including numeric presets like `Last 5
minutes` and `Last 1 hour`. When users click “Other” while one of those presets
is selected, the emitted value is still the same preset string, so the control
remains on the preset and “Other” cannot actually be selected. Initialize
custom state only from non-preset custom values (or from a dedicated stored
custom draft) so selecting “Other” always emits a non-preset value.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask
user if the user wants to fix the rest of the comments as well. if said yes,
then fetch all the comments validate the correctness and implement a minimal fix
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41527&comment_hash=52c58c686511801cf454970eb7c07c0c9faefdfeb65384dc537a3b7853468b5f&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41527&comment_hash=52c58c686511801cf454970eb7c07c0c9faefdfeb65384dc537a3b7853468b5f&reaction=dislike'>👎</a>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]