codeant-ai-for-open-source[bot] commented on code in PR #38342:
URL: https://github.com/apache/superset/pull/38342#discussion_r2930908265
##########
superset-frontend/src/assets/staticPages/404.html:
##########
@@ -67,7 +67,7 @@
text-align: center;
text-decoration: none;
display: inline-block;
- font-size: 11px;
+ font-size: 0.6875rem; /* WCAG 1.4.4 */
Review Comment:
**Suggestion:** Setting the button text to `0.6875rem` (~11px) makes the
primary action label too small and regresses readability in an
accessibility-focused change. Increase it to a normal readable size to avoid
creating a low-vision usability issue. [possible bug]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ Primary "Back to home" action text is tiny.
- ⚠️ Low-vision users struggle recovering from 404 pages.
```
</details>
```suggestion
font-size: 1rem; /* WCAG 1.4.4 */
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Frontend build generates `404.html` from
`superset-frontend/src/assets/staticPages/404.html`
(`superset-frontend/webpack.config.js:161-164`).
2. Trigger a 404 in browser (`Accept: text/html`) while app is not in debug
mode; backend
serves this static page from `show_http_exception`
(`superset/views/error_handling.py:161-170`).
3. Inspect the primary CTA `<a class="button">Back to home</a>`
(`superset-frontend/src/assets/staticPages/404.html:100`) with `.button`
font-size defined
as `0.6875rem` at line 70.
4. The CTA label renders around 11px equivalent, making the main recovery
action hard to
read; changing to `1rem` improves legibility directly on this user path.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/assets/staticPages/404.html
**Line:** 70:70
**Comment:**
*Possible Bug: Setting the button text to `0.6875rem` (~11px) makes the
primary action label too small and regresses readability in an
accessibility-focused change. Increase it to a normal readable size to avoid
creating a low-vision usability issue.
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.
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=55a7b5bd358f5c276f9eb667bf86ce2acc71db005c20b5e23380c47f7218d09d&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=55a7b5bd358f5c276f9eb667bf86ce2acc71db005c20b5e23380c47f7218d09d&reaction=dislike'>👎</a>
##########
superset-frontend/src/assets/staticPages/500.html:
##########
@@ -66,7 +66,7 @@
text-align: center;
text-decoration: none;
display: inline-block;
- font-size: 11px;
+ font-size: 0.6875rem; /* WCAG 1.4.4 */
Review Comment:
**Suggestion:** The new button text size is set to `0.6875rem` (about 11px),
which makes the primary navigation action hard to read and undermines the
intended accessibility improvement. Increase it to a normal readable size so
users can reliably see and activate the recovery action. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ 500-page recovery CTA readability is significantly reduced.
- ⚠️ HTML error flows hinder quick return-home navigation.
```
</details>
```suggestion
font-size: 1rem; /* WCAG 1.4.4 */
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Run Superset with `DEBUG=False`, then trigger any backend unhandled
exception in an
HTML request flow; Flask routes this through `show_unexpected_exception` at
`superset/views/error_handling.py:215-223`.
2. The error handler serves the built static page `static/assets/500.html`
via
`send_file(...)` at `superset/views/error_handling.py:222-223` (same
behavior also exists
for command exceptions at `superset/views/error_handling.py:194-199`).
3. On the rendered 500 page, the only recovery CTA (`<a href="/"
class="button">Back to
home</a>`) is styled by `.button` in
`superset-frontend/src/assets/staticPages/500.html:58-72`.
4. The CTA text is explicitly forced to `font-size: 0.6875rem` at
`superset-frontend/src/assets/staticPages/500.html:69` (~11px at default
root size),
making the primary recovery action hard to read on a failure screen.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset-frontend/src/assets/staticPages/500.html
**Line:** 69:69
**Comment:**
*Logic Error: The new button text size is set to `0.6875rem` (about
11px), which makes the primary navigation action hard to read and undermines
the intended accessibility improvement. Increase it to a normal readable size
so users can reliably see and activate the recovery action.
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.
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=6801ee769ee843211598edf48b0cfa89a03059ff92b772424b13c58d8dd6e8ff&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=6801ee769ee843211598edf48b0cfa89a03059ff92b772424b13c58d8dd6e8ff&reaction=dislike'>👎</a>
##########
superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx:
##########
@@ -281,6 +318,21 @@ function Echart(
useEffect(() => () => chartRef.current?.dispose(), []);
+ // WCAG 1.4.13: Dismiss ECharts tooltip on Escape key
+ useEffect(() => {
+ const el = divRef.current;
+ if (!el) return undefined;
+
+ const handleKeyDown = (e: Event) => {
+ if ((e as globalThis.KeyboardEvent).key === 'Escape' &&
chartRef.current) {
+ chartRef.current.dispatchAction({ type: 'hideTip' });
+ }
+ };
+
+ el.addEventListener('keydown', handleKeyDown);
+ return () => el.removeEventListener('keydown', handleKeyDown);
+ }, [didMount]);
Review Comment:
**Suggestion:** The Escape handler is attached to the chart container
element, but that element is not focusable, so it usually never receives
`keydown` events. As a result, the tooltip dismissal behavior will not work for
keyboard users. Attach the listener to `document` (or make the container
focusable) so Escape is captured reliably. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ Escape tooltip dismissal fails for keyboard navigation.
- ⚠️ WCAG 1.4.13 keyboard dismissal behavior is unreliable.
- ❌ Shared Echart affects many chart visualization types.
```
</details>
```suggestion
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape' && chartRef.current) {
chartRef.current.dispatchAction({ type: 'hideTip' });
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Open any ECharts visualization in Superset (plugin registration is in
`superset-frontend/src/visualizations/presets/MainPreset.ts:151-153` for
Timeseries and
similarly other ECharts types).
2. This renders `EchartsTimeseries`
(`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/EchartsTimeseries.tsx:365`)
which mounts shared `Echart` component.
3. In `Echart`, Escape listener is bound to `divRef.current` via
`el.addEventListener('keydown', ...)` (`.../components/Echart.tsx:332`), but
the rendered
container only has `ref/height/width/role/aria-label`
(`.../Echart.tsx:363-367`) and no
focusability attribute (`tabIndex`).
4. Hover chart to show tooltip, then press Escape while normal page focus
remains outside
that non-focusable container; `dispatchAction({ type: 'hideTip' })` in key
handler
(`.../Echart.tsx:327-329`) does not run, so tooltip is not dismissed via
keyboard.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:**
superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx
**Line:** 323:334
**Comment:**
*Logic Error: The Escape handler is attached to the chart container
element, but that element is not focusable, so it usually never receives
`keydown` events. As a result, the tooltip dismissal behavior will not work for
keyboard users. Attach the listener to `document` (or make the container
focusable) so Escape is captured reliably.
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.
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=256704a3dc9291bbb1a93a05406a95bdcccb5b32dab343db36c079bc3abc70e1&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=256704a3dc9291bbb1a93a05406a95bdcccb5b32dab343db36c079bc3abc70e1&reaction=dislike'>👎</a>
##########
superset-frontend/packages/superset-core/src/ui/theme/GlobalStyles.tsx:
##########
@@ -98,6 +104,85 @@ export const GlobalStyles = () => {
[role='button'] {
cursor: pointer;
}
+
+ /* WCAG 1.4.11: Non-text contrast — form field borders need 3:1
against background.
+ Ant Design default colorBorder (#d9d9d9) is only ~1.34:1 on white.
+ Using colorTextTertiary (~#8c8c8c, ~3.54:1 on white) for all input
borders. */
+ .ant-input,
+ .ant-input-affix-wrapper,
+ .ant-select:not(.ant-select-customize-input) .ant-select-selector,
+ .ant-picker,
+ .ant-input-number,
+ .ant-input-number-group-wrapper .ant-input-number {
+ border-color: ${theme.colorTextTertiary};
+ }
+
+ /* Ensure disabled inputs retain a visible (though lighter) border */
+ .ant-input[disabled],
+ .ant-select-disabled .ant-select-selector,
+ .ant-picker-disabled,
+ .ant-input-number-disabled {
+ border-color: ${theme.colorTextQuaternary};
+ }
+
+ /* WCAG 1.4.11: Checkbox/Radio/Switch borders need 3:1 against
background.
+ Ant Design default uses colorBorder (~1.34:1 on white). Override to
+ colorTextTertiary (~3.54:1) for unchecked state borders. */
+ .ant-checkbox .ant-checkbox-inner {
+ border-color: ${theme.colorTextTertiary};
+ }
+ .ant-radio .ant-radio-inner {
+ border-color: ${theme.colorTextTertiary};
+ }
+ .ant-switch {
+ background-color: ${theme.colorTextTertiary};
+ }
+
+ /* WCAG 1.4.11: Divider/separator contrast — colorSplit (~#f0f0f0) is
~1.04:1 on white.
+ Override to colorTextTertiary (~3.54:1). */
+ .ant-divider {
+ border-color: ${theme.colorTextTertiary};
+ }
+
+ /* WCAG 1.4.11: Table borders and progress bars */
+ .ant-table-bordered .ant-table-cell {
+ border-color: ${theme.colorTextQuaternary};
+ }
+ .ant-progress-bg {
+ min-width: 2px;
+ }
Review Comment:
**Suggestion:** Setting a global `min-width: 2px` on progress fills makes 0%
progress bars render as partially filled, which misrepresents actual progress
in places like SQL Lab and export status. Keep the minimum width at 0 (or only
apply a minimum for non-zero widths) so a true zero value remains visually
empty. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ SQL Lab query progress initially appears non-zero.
- ⚠️ Export modal progress can look falsely started.
- ⚠️ User trust drops from inaccurate progress visuals.
```
</details>
```suggestion
.ant-progress-bg {
min-width: 0;
}
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Load any Superset page; `SupersetThemeProvider` always mounts
`<GlobalStyles />` at
`superset-frontend/packages/superset-core/src/ui/theme/Theme.tsx:187`, so
`.ant-progress-bg { min-width: 2px; }` is globally active from
`GlobalStyles.tsx:151-153`.
2. Open SQL Lab and run a query; query bootstrap sets `progress: 0` in
`superset-frontend/src/SqlLab/actions/sqlLab.ts:400`.
3. SQL Lab query log renders progress using `<ProgressBar ...
percent={parseInt(progress.toFixed(0), 10)} />` at
`superset-frontend/src/SqlLab/components/QueryTable/index.tsx:325` and
`:331`, so zero
percent reaches Ant Progress.
4. Because the global rule enforces `min-width: 2px`
(`GlobalStyles.tsx:152`), the fill
element `.ant-progress-bg` cannot be visually empty at 0%, so users see a
misleading
non-zero bar.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:**
superset-frontend/packages/superset-core/src/ui/theme/GlobalStyles.tsx
**Line:** 151:153
**Comment:**
*Logic Error: Setting a global `min-width: 2px` on progress fills makes
0% progress bars render as partially filled, which misrepresents actual
progress in places like SQL Lab and export status. Keep the minimum width at 0
(or only apply a minimum for non-zero widths) so a true zero value remains
visually empty.
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.
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=38ffc64346adcd4e5154afe69053319b501e12f252db68348030e7bc9a0244cb&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=38ffc64346adcd4e5154afe69053319b501e12f252db68348030e7bc9a0244cb&reaction=dislike'>👎</a>
##########
superset-frontend/packages/superset-ui-core/src/components/Popover/index.tsx:
##########
@@ -16,11 +16,56 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { useCallback, useEffect, useState } from 'react';
import { Popover as AntdPopover } from 'antd';
import { PopoverProps as AntdPopoverProps } from 'antd/es/popover';
export interface PopoverProps extends AntdPopoverProps {
forceRender?: boolean;
}
-export const Popover = (props: PopoverProps) => <AntdPopover {...props} />;
+/**
+ * WCAG 1.4.13 compliant Popover wrapper.
+ *
+ * - Dismissable: pressing Escape closes the popover.
+ * - Hoverable: Ant Design 5 popovers already keep the overlay visible
+ * while the pointer is over it.
+ */
+export const Popover = ({ open, onOpenChange, ...props }: PopoverProps) => {
+ const [visible, setVisible] = useState(false);
+
+ const isControlled = open !== undefined;
+ const isVisible = isControlled ? open : visible;
+
+ const handleOpenChange = useCallback(
+ (newOpen: boolean) => {
+ if (!isControlled) {
+ setVisible(newOpen);
+ }
+ onOpenChange?.(newOpen);
+ },
+ [isControlled, onOpenChange],
Review Comment:
**Suggestion:** The wrapper now only treats `open/onOpenChange` as the
control API, but existing callers in this codebase still use
`visible/onVisibleChange`. Because `open` is always passed to `AntdPopover`,
those legacy controlled popovers stop syncing with parent state (and
`defaultOpen` is also ignored), causing incorrect open/close behavior. Support
both APIs and initialize internal state from `defaultOpen`. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ `/tasks/list/` popover visibility callbacks stop syncing.
- ⚠️ Legacy `visible/onVisibleChange` Popover contract regresses.
- ⚠️ Uncontrolled `defaultOpen` initialization currently ignored.
```
</details>
```suggestion
export const Popover = ({
open,
visible: legacyVisible,
defaultOpen,
onOpenChange,
onVisibleChange,
...props
}: PopoverProps) => {
const [visible, setVisible] = useState(Boolean(defaultOpen));
const isControlled = open !== undefined || legacyVisible !== undefined;
const isVisible = open ?? legacyVisible ?? visible;
const handleOpenChange = useCallback(
(newOpen: boolean) => {
if (!isControlled) {
setVisible(newOpen);
}
onOpenChange?.(newOpen);
onVisibleChange?.(newOpen);
},
[isControlled, onOpenChange, onVisibleChange],
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Open route `/tasks/list/` (registered at
`superset-frontend/src/views/routes.tsx:306-307`), with Global Task
Framework enabled
(`src/pages/TaskList/index.tsx:81`).
2. In Task list "Details" column, rows render `<TaskPayloadPopover />` and
`<TaskStackTracePopover />` (`src/pages/TaskList/index.tsx:428-430`).
3. Both components call `Popover` from `@superset-ui/core/components` using
legacy props
`visible` + `onVisibleChange`
(`src/features/tasks/TaskPayloadPopover.tsx:72-77`,
`src/features/tasks/TaskStackTracePopover.tsx:133-138`).
4. Wrapper at
`packages/superset-ui-core/src/components/Popover/index.tsx:34-47` ignores
`onVisibleChange` and only fires `onOpenChange`, while forcing
`open={isVisible}` at line
66; parent `visible` state never syncs, so legacy-controlled behavior is
broken.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:**
superset-frontend/packages/superset-ui-core/src/components/Popover/index.tsx
**Line:** 34:47
**Comment:**
*Logic Error: The wrapper now only treats `open/onOpenChange` as the
control API, but existing callers in this codebase still use
`visible/onVisibleChange`. Because `open` is always passed to `AntdPopover`,
those legacy controlled popovers stop syncing with parent state (and
`defaultOpen` is also ignored), causing incorrect open/close behavior. Support
both APIs and initialize internal state from `defaultOpen`.
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.
```
</details>
<a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=1e3b05955217ff09bcd4cc18406f5a45a23be2e5f918d46f28b3273872a6d918&reaction=like'>👍</a>
| <a
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38342&comment_hash=1e3b05955217ff09bcd4cc18406f5a45a23be2e5f918d46f28b3273872a6d918&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]