You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by "manojshetty2004 (via GitHub)" <gi...@apache.org> on 2025/12/21 17:30:35 UTC
[PR] style(explore): normalize typography in widget settings panels [superset]
manojshetty2004 opened a new pull request, #36781:
URL: https://github.com/apache/superset/pull/36781
### SUMMARY
Normalizes typography in widget settings/sidebar panels to improve visual hierarchy and readability.
Inner sub-section titles previously relied on varying font weights, which created visual noise. This change uses a single, consistent font weight and spacing to establish hierarchy more clearly, without altering layout or behavior.
### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A
### TESTING INSTRUCTIONS
1. Open Explore view.
2. Open widget settings / sidebar panels.
3. Verify that inner sub-section titles use a consistent font weight.
4. Confirm improved readability and spacing without layout changes.
### ADDITIONAL INFORMATION
- [x] Has associated issue: #36670
- [ ] Required feature flags
- [x] Changes UI
- [ ] Includes DB Migration
- [ ] Introduces new feature or API
- [ ] Removes existing feature or API
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4047769558
## **Sequence Diagram**
This PR standardizes how subsection titles are styled in Explore widget settings and sidebar panels. It routes subsection headers through a single shared style so titles render with consistent medium weight and spacing, improving readability without changing behavior.
```mermaid
sequenceDiagram
participant User
participant Explore UI
participant Settings Panel
participant Shared Header Style
User->>Explore UI: Open widget settings sidebar
Explore UI->>Settings Panel: Render section and subsection headers
Settings Panel->>Shared Header Style: Apply normalized header typography
Shared Header Style-->>Settings Panel: Medium weight and consistent spacing
Settings Panel-->>User: Show cleaner and consistent hierarchy
```
---
*Generated by [CodeAnt AI](https://codeant.ai)*
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4048232189
AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
<details>
<summary>
Bito Usage Guide
</summary>
**Commands**
Type the following command in the pull request comment and save the comment.
- `/review` - Manually triggers a full AI review.
- `/pause` - Pauses automatic reviews on this pull request.
- `/resume` - Resumes automatic reviews.
- `/resolve` - Marks all Bito-posted review comments as resolved.
- `/abort` - Cancels all in-progress reviews.
Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
**Configuration**
This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
**Documentation & Help**
- <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
- <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
- <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
- <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
</details>
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4048229210
## **Sequence Diagram**
This PR adjusts the subsection header styling used in Explore widget settings panels by increasing bottom spacing while keeping typography tokens consistent. The core flow remains the same, but rendered headers now show clearer visual separation for improved readability.
```mermaid
sequenceDiagram
participant User
participant ExplorePanel
participant SubSectionHeader
participant Theme
User->>ExplorePanel: Open widget settings panel
ExplorePanel->>SubSectionHeader: Render subsection title
SubSectionHeader->>Theme: Resolve typography style tokens
Theme-->>SubSectionHeader: Return same weight and size with larger bottom spacing
SubSectionHeader-->>User: Show clearer subsection hierarchy
```
---
*Generated by [CodeAnt AI](https://codeant.ai)*
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #36781:
URL: https://github.com/apache/superset/pull/36781#discussion_r2673559941
##########
superset-frontend/packages/superset-ui-chart-controls/src/components/ControlSubSectionHeader.tsx:
##########
@@ -20,8 +20,8 @@ import { styled, css } from '@apache-superset/core/ui';
export const ControlSubSectionHeader = styled.div`
${({ theme }) => css`
- font-weight: ${theme.fontWeightStrong};
- margin-bottom: ${theme.sizeUnit}px;
+ font-weight: ${theme.typography.weights.medium};
Review Comment:
The property `theme.typography.weights.medium` does not exist in the theme definition. Based on the codebase search, the theme does not have a `typography` object with nested `weights` property.
The theme has `theme.fontWeightStrong` (number) defined in SupersetSpecificTokens, but no `typography.weights.medium`. This will cause a runtime error when this component is rendered.
Consider using `theme.fontWeightStrong` or another existing font weight property from the theme.
```suggestion
font-weight: ${theme.fontWeightStrong};
```
##########
superset-frontend/packages/superset-ui-chart-controls/src/components/ControlSubSectionHeader.tsx:
##########
@@ -20,8 +20,8 @@ import { styled, css } from '@apache-superset/core/ui';
export const ControlSubSectionHeader = styled.div`
${({ theme }) => css`
- font-weight: ${theme.fontWeightStrong};
- margin-bottom: ${theme.sizeUnit}px;
+ font-weight: ${theme.typography.weights.medium};
+ margin-bottom: ${theme.gridUnit * 2}px;
Review Comment:
The property `theme.gridUnit` does not exist in the theme definition. The correct property is `theme.sizeUnit` (which is defined in the allowedAntdTokens list).
Throughout the codebase, spacing calculations use `theme.sizeUnit` consistently. This will cause a runtime error when this component is rendered.
Change `theme.gridUnit` to `theme.sizeUnit` to fix this issue.
```suggestion
margin-bottom: ${theme.sizeUnit * 2}px;
```
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "manojshetty2004 (via GitHub)" <gi...@apache.org>.
manojshetty2004 commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4148502299
Hi , just checking in — is there any feedback or changes needed from my side? Happy to update this PR.
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4040692527
## **Sequence Diagram**
This PR updates the styled ControlSubSectionHeader used in Explore widget settings so subsection titles use a medium font weight and increased bottom spacing for clearer visual hierarchy without changing functional behavior.
```mermaid
sequenceDiagram
participant User
participant ExploreUI as Explore UI
participant Theme
User->>ExploreUI: Open widget settings panel
ExploreUI->>Theme: Request subsection header styles
Theme-->>ExploreUI: Return medium weight and increased margin
ExploreUI-->>User: Render panel with normalized subsection titles
```
---
*Generated by [CodeAnt AI](https://codeant.ai)*
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-3679135685
## Nitpicks 🔍
<table>
<tr><td>🔒 <strong>No security issues identified</strong></td></tr>
<tr><td>⚡ <strong>Recommended areas for review</strong><br><br>
- [ ] <a href='https://github.com/apache/superset/pull/36781/files#diff-671e3b985aaea8a7dcaa8ac7b0b6246e6160e6e04ae26b440080d0dbf42ae6ffR23-R23'><strong>Theme token mismatch</strong></a><br>The code now references `theme.typography.weights.medium` which may not exist in all theme shapes used across the repo (previously `theme.fontWeightStrong` was used). If the theme object doesn't include this path, the runtime value could be undefined and styling may break or regress. Verify the theme API and consider providing a safe fallback.<br>
- [ ] <a href='https://github.com/apache/superset/pull/36781/files#diff-671e3b985aaea8a7dcaa8ac7b0b6246e6160e6e04ae26b440080d0dbf42ae6ffR24-R24'><strong>Spacing token consistency</strong></a><br>The change uses `theme.gridUnit * 2` for `margin-bottom` while older code used `theme.sizeUnit`. Ensure using `gridUnit` is intentionally consistent across the codebase/themes to avoid spacing regressions in other components or themes that expect `sizeUnit`. Consider a fallback or centralize spacing tokens.<br>
</td></tr>
</table>
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-3679126049
AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "manojshetty2004 (via GitHub)" <gi...@apache.org>.
manojshetty2004 commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4040739101
Hi everyone, I've addressed the CI failures and pushed the fixes. The checks are currently running. Please let me know if any further changes are needed. Looking forward to your feedback when convenient. Thanks!
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "manojshetty2004 (via GitHub)" <gi...@apache.org>.
manojshetty2004 commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4311035767
@rusackas Rebased onto latest master and resolved conflicts. Ready for another look
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "manojshetty2004 (via GitHub)" <gi...@apache.org>.
manojshetty2004 closed pull request #36781: style(explore): normalize typography in widget settings panels
URL: https://github.com/apache/superset/pull/36781
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "codecov[bot] (via GitHub)" <gi...@apache.org>.
codecov[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4047740622
## [Codecov](https://app.codecov.io/gh/apache/superset/pull/36781?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) Report
:white_check_mark: All modified and coverable lines are covered by tests.
:white_check_mark: Project coverage is 41.31%. Comparing base ([`c0bcf28`](https://app.codecov.io/gh/apache/superset/commit/c0bcf28947577c0fb4f3599baa98c05d2046fe47?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)) to head ([`75853db`](https://app.codecov.io/gh/apache/superset/commit/75853db4e273750f0bad60ec491f2af4d46c71d0?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
:warning: Report is 824 commits behind head on master.
<details><summary>Additional details and impacted files</summary>
```diff
@@ Coverage Diff @@
## master #36781 +/- ##
===========================================
+ Coverage 0 41.31% +41.31%
===========================================
Files 0 717 +717
Lines 0 57095 +57095
Branches 0 6677 +6677
===========================================
+ Hits 0 23591 +23591
- Misses 0 33163 +33163
- Partials 0 341 +341
```
| [Flag](https://app.codecov.io/gh/apache/superset/pull/36781/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Coverage Δ | |
|---|---|---|
| [hive](https://app.codecov.io/gh/apache/superset/pull/36781/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `40.77% <ø> (?)` | |
| [presto](https://app.codecov.io/gh/apache/superset/pull/36781/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `40.79% <ø> (?)` | |
| [python](https://app.codecov.io/gh/apache/superset/pull/36781/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `40.87% <ø> (?)` | |
| [superset-extensions-cli](https://app.codecov.io/gh/apache/superset/pull/36781/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `89.82% <ø> (?)` | |
Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#carryforward-flags-in-the-pull-request-comment) to find out more.
</details>
[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/apache/superset/pull/36781?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
<details><summary> :rocket: New features to boost your workflow: </summary>
- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-3679127574
CodeAnt AI is reviewing your PR.
---
### Thanks for using CodeAnt! 🎉
We're free for open-source projects. if you're enjoying it, help us grow by sharing.
[Share on X](https://twitter.com/intent/tweet?text=Just%20tried%20%40CodeAntAI%20for%20automated%20code%20review%20and%20I%27m%20impressed%21%20Free%20for%20open%20source%20with%20a%20free%20trial%20for%20private%20repos.%20Worth%20checking%20out%3A&url=https%3A//codeant.ai) ·
[Reddit](https://www.reddit.com/submit?title=Check%20out%20CodeAnt%20for%20automated%20code%20review&text=Just%20tried%20CodeAnt%20for%20automated%20code%20review%20and%20I%27m%20impressed%21%20Free%20for%20open%20source%20with%20a%20free%20trial%20for%20private%20repos.%20Worth%20checking%20out%3A%20https%3A//codeant.ai) ·
[LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcodeant.ai&mini=true&title=Check%20out%20CodeAnt%20for%20automated%20code%20review&summary=Just%20tried%20CodeAnt%20for%20automated%20code%20review%20and%20I%27m%20impressed%21%20Free%20for%20open%20source%20with%20a%20free%20trial%20for%20private%20repos)
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "sadpandajoe (via GitHub)" <gi...@apache.org>.
sadpandajoe commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-3715748248
@manojshetty2004 can you add before and after screenshots to your PR?
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "manojshetty2004 (via GitHub)" <gi...@apache.org>.
manojshetty2004 commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-3723095061
@sadpandajoe
I’ve added before/after screenshots based on the code diff. I ran into local environment limitations while trying to run Superset in Codespaces (Docker isn’t available there), and will be happy to add UI screenshots if needed. Let me know if the diff screenshots are sufficient.
Before
<img width="433" height="48" alt="Screenshot 2026-01-08 152116" src="https://github.com/user-attachments/assets/7c4d9127-3f48-486d-a45c-6459cc0dcc85" />
After
<img width="407" height="47" alt="Screenshot 2026-01-08 152146" src="https://github.com/user-attachments/assets/bc5ecf67-1e91-4323-9833-52657e26a86a" />
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "rusackas (via GitHub)" <gi...@apache.org>.
rusackas commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4325506611
Thanks for rebasing! Heads up though — looking at the PR after the rebase, the diff is now empty (0 additions / 0 deletions / 0 changed files across 10 commits). It looks like the conflict resolution dropped the original `ControlSubSectionHeader.tsx` change rather than keeping it. Could you either re-apply the typography/spacing change on top of master, or close this PR if the change is no longer needed? Happy to take another look once there's something to review.
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-3679139033
CodeAnt AI finished reviewing your PR.
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "manojshetty2004 (via GitHub)" <gi...@apache.org>.
manojshetty2004 commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4048727305
Hi! It looks like the Playwright experimental tests failed, but the failures appear unrelated to the changes in this PR (which only modifies DatasourceEditor). All other checks passed. Could this be a flaky CI issue? Happy to rerun if needed. Thanks!
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "github-advanced-security[bot] (via GitHub)" <gi...@apache.org>.
github-advanced-security[bot] commented on code in PR #36781:
URL: https://github.com/apache/superset/pull/36781#discussion_r2925553763
##########
superset-frontend/src/components/Datasource/components/DatasourceEditor/DatasourceEditor.tsx:
##########
@@ -0,0 +1,2620 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import rison from 'rison';
+import { PureComponent, useCallback, type ReactNode } from 'react';
+import { connect, ConnectedProps } from 'react-redux';
+import type { JsonObject } from '@superset-ui/core';
+import { type SupersetTheme } from '@apache-superset/core/theme';
+import type { AnyAction } from 'redux';
+import type { ThunkDispatch } from 'redux-thunk';
+import { Radio } from '@superset-ui/core/components/Radio';
+import {
+ isFeatureEnabled,
+ FeatureFlag,
+ SupersetClient,
+ getClientErrorObject,
+ getExtensionsRegistry,
+} from '@superset-ui/core';
+import { GenericDataType } from '@apache-superset/core/common';
+import { Alert } from '@apache-superset/core/components';
+import {
+ css,
+ styled,
+ themeObject,
+ withTheme,
+} from '@apache-superset/core/theme';
+import { t } from '@apache-superset/core/translation';
+import Tabs from '@superset-ui/core/components/Tabs';
+import WarningIconWithTooltip from '@superset-ui/core/components/WarningIconWithTooltip';
+import TableSelector from 'src/components/TableSelector';
+import CheckboxControl from 'src/explore/components/controls/CheckboxControl';
+import TextControl from 'src/explore/components/controls/TextControl';
+import TextAreaControl from 'src/explore/components/controls/TextAreaControl';
+import SpatialControl from 'src/explore/components/controls/SpatialControl';
+import withToasts from 'src/components/MessageToasts/withToasts';
+import CurrencyControl from 'src/explore/components/controls/CurrencyControl';
+import {
+ AsyncSelect,
+ Badge,
+ Button,
+ Card,
+ CertifiedBadge,
+ Col,
+ Divider,
+ EditableTitle,
+ Flex,
+ FormLabel,
+ Icons,
+ InfoTooltip,
+ Input,
+ Loading,
+ Row,
+ Select,
+ Typography,
+ Label,
+} from '@superset-ui/core/components';
+import { FilterableTable } from 'src/components';
+import {
+ executeQuery,
+ formatQuery,
+ resetDatabaseState,
+} from 'src/database/actions';
+import Mousetrap from 'mousetrap';
+import { clearDatasetCache } from 'src/utils/cachedSupersetGet';
+import { makeUrl } from 'src/utils/pathUtils';
+import {
+ OwnerSelectLabel,
+ OWNER_TEXT_LABEL_PROP,
+ OWNER_EMAIL_PROP,
+ OWNER_OPTION_FILTER_PROPS,
+} from 'src/features/owners/OwnerSelectLabel';
+import { DatabaseSelector } from '../../../DatabaseSelector';
+import CollectionTable from '../CollectionTable';
+import Fieldset from '../Fieldset';
+import Field from '../Field';
+import { fetchSyncedColumns, updateColumns } from '../../utils';
+import DatasetUsageTab from './components/DatasetUsageTab';
+import {
+ DEFAULT_FOLDERS_COUNT,
+ isDefaultFolder,
+} from '../../FoldersEditor/constants';
+import { validateFolders } from '../../FoldersEditor/folderValidation';
+import {
+ countAllFolders,
+ filterFoldersByValidUuids,
+} from '../../FoldersEditor/treeUtils';
+import FoldersEditor from '../../FoldersEditor';
+import { DatasourceFolder } from 'src/explore/components/DatasourcePanel/types';
+
+const extensionsRegistry = getExtensionsRegistry();
+
+// Type definitions
+
+interface Owner {
+ id?: number;
+ value?: number;
+ label?: ReactNode;
+ first_name?: string;
+ last_name?: string;
+ email?: string;
+ [key: string]: unknown;
+}
+
+interface Currency {
+ symbol?: string;
+ symbolPosition?: string;
+}
+
+interface Metric {
+ id?: number;
+ uuid?: string;
+ metric_name: string;
+ expression?: string;
+ verbose_name?: string;
+ description?: string;
+ d3format?: string;
+ currency?: Currency;
+ certified_by?: string;
+ certification_details?: string;
+ warning_markdown?: string;
+ extra?: string;
+}
+
+interface Column {
+ id?: number;
+ uuid?: string;
+ column_name: string;
+ verbose_name?: string;
+ description?: string;
+ expression?: string;
+ filterable?: boolean;
+ groupby?: boolean;
+ is_dttm?: boolean;
+ type?: string;
+ type_generic?: number;
+ advanced_data_type?: string;
+ python_date_format?: string;
+ json?: string;
+ certified_by?: string;
+ certification_details?: string;
+ is_certified?: boolean;
+}
+
+interface Database {
+ id: number;
+ database_name?: string;
+ name?: string;
+ backend?: string;
+}
+
+interface SpatialConfig {
+ name: string;
+ type: string;
+ config: Record<string, unknown> | null;
+}
+
+interface DatasourceObject {
+ id?: number;
+ datasource_name?: string;
+ database?: Database;
+ catalog?: string;
+ schema?: string;
+ table_name?: string;
+ sql?: string;
+ columns: Column[];
+ metrics?: Metric[];
+ owners: Owner[];
+ main_dttm_col?: string;
+ currency_code_column?: string;
+ filter_select_enabled?: boolean;
+ fetch_values_predicate?: string;
+ description?: string;
+ default_endpoint?: string;
+ extra?: string;
+ datasource_type?: string;
+ type?: string;
+ offset?: number;
+ cache_timeout?: number;
+ normalize_columns?: boolean;
+ always_filter_main_dttm?: boolean;
+ template_params?: string;
+ spatials?: SpatialConfig[];
+ all_cols?: string[];
+ folders?: DatasourceFolder[];
+}
+
+interface DatasourceEditorOwnProps {
+ datasource: DatasourceObject;
+ onChange?: (datasource: DatasourceObject, errors: string[]) => void;
+ addSuccessToast: (msg: string) => void;
+ addDangerToast: (msg: string) => void;
+ setIsEditing?: (isEditing: boolean) => void;
+ currencies?: string[];
+ theme?: SupersetTheme;
+}
+
+interface QueryResultColumn {
+ name: string;
+ type: string;
+ is_dttm?: boolean;
+ type_generic?: number;
+ is_hidden?: boolean;
+ column_name: string;
+}
+
+interface QueryResult {
+ status?: string;
+ query_id?: string;
+ data?: Record<string, unknown>[];
+ columns?: QueryResultColumn[];
+ selected_columns?: QueryResultColumn[];
+ expanded_columns?: QueryResultColumn[];
+ query?: {
+ id?: string;
+ };
+}
+
+interface DatabaseState {
+ clientId?: string;
+ queryRunning?: boolean;
+ isLoading?: boolean;
+ error?: string;
+ queryResult?: QueryResult;
+}
+
+interface RootState {
+ database?: DatabaseState;
+}
+
+interface ChartUsageData {
+ id: number;
+ slice_name: string;
+ url: string;
+ certified_by?: string;
+ certification_details?: string;
+ description?: string;
+ owners?: Owner[];
+ changed_on_delta_humanized?: string;
+ changed_on?: string;
+ changed_by?: {
+ first_name?: string;
+ last_name?: string;
+ id?: number;
+ };
+ dashboards?: Array<{
+ id: number;
+ dashboard_title: string;
+ url: string;
+ }>;
+}
+
+interface DatasourceEditorState {
+ datasource: DatasourceObject;
+ errors: string[];
+ isSqla: boolean;
+ isEditMode: boolean;
+ databaseColumns: Column[];
+ calculatedColumns: Column[];
+ folders: DatasourceFolder[];
+ folderCount: number;
+ metadataLoading: boolean;
+ activeTabKey: string;
+ datasourceType: string;
+ usageCharts: ChartUsageData[];
+ usageChartsCount: number;
+ metricSearchTerm: string;
+ columnSearchTerm: string;
+ calculatedColumnSearchTerm: string;
+}
+
+interface AbortControllers {
+ formatQuery: AbortController | null;
+ formatSql: AbortController | null;
+ syncMetadata: AbortController | null;
+ fetchUsageData: AbortController | null;
+}
+
+// Component props interfaces
+interface CollectionTabTitleProps {
+ title: string;
+ collection?: unknown[] | { length: number };
+ count?: number;
+}
+
+interface ColumnCollectionTableProps {
+ columns: Column[];
+ datasource: DatasourceObject;
+ onColumnsChange: (columns: Column[]) => void;
+ onDatasourceChange: (datasource: DatasourceObject) => void;
+ editableColumnName?: boolean;
+ showExpression?: boolean;
+ allowAddItem?: boolean;
+ allowEditDataType?: boolean;
+ className?: string;
+ itemGenerator?: () => Partial<Column>;
+ columnLabelTooltips?: Record<string, string>;
+ filterTerm?: string;
+ filterFields?: string[];
+}
+
+interface StackedFieldProps {
+ label: string;
+ formElement: ReactNode;
+}
+
+interface FormContainerProps {
+ children: ReactNode;
+}
+
+interface OwnersSelectorProps {
+ datasource: DatasourceObject;
+ onChange: (owners: Owner[]) => void;
+}
+
+const DatasourceContainer = styled.div`
+ flex: 1;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
+
+ .change-warning {
+ margin: 16px 10px 0;
+ color: ${({ theme }) => theme.colorWarning};
+ }
+
+ .change-warning .bold {
+ font-weight: ${({ theme }) => theme.fontWeightStrong};
+ }
+
+ .form-group.has-feedback > .help-block {
+ margin-top: 8px;
+ }
+
+ .form-group.form-group-md {
+ margin-bottom: 8px;
+ }
+`;
+
+const FlexRowContainer = styled.div`
+ align-items: center;
+ display: flex;
+
+ svg {
+ margin-right: ${({ theme }) => theme.sizeUnit}px;
+ }
+`;
+
+const StyledTableTabs = styled(Tabs)`
+ flex: 1;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
+
+ .ant-tabs-content-holder {
+ flex: 1;
+ min-height: 0;
+ overflow: auto;
+ }
+
+ .ant-tabs-content {
+ height: 100%;
+ }
+
+ .ant-tabs-tabpane-active {
+ height: 100%;
+ }
+`;
+
+const StyledBadge = styled(Badge)`
+ .ant-badge-count {
+ line-height: ${({ theme }) => theme.sizeUnit * 4}px;
+ height: ${({ theme }) => theme.sizeUnit * 4}px;
+ margin-left: ${({ theme }) => theme.sizeUnit}px;
+ }
+`;
+
+const EditLockContainer = styled.div`
+ font-size: ${({ theme }) => theme.fontSizeSM}px;
+ display: flex;
+ align-items: center;
+ a {
+ padding: 0 10px;
+ }
+`;
+
+const ColumnButtonWrapper = styled.div`
+ text-align: right;
+ ${({ theme }) => `margin-bottom: ${theme.sizeUnit * 2}px`}
+`;
+
+const StyledLabelWrapper = styled.div`
+ display: flex;
+ align-items: center;
+ span {
+ margin-right: ${({ theme }) => theme.sizeUnit}px;
+ }
+`;
+
+const StyledTableTabWrapper = styled.div`
+ .table > tbody > tr > td {
+ vertical-align: middle;
+ }
+
+ .ant-tag {
+ margin-top: ${({ theme }) => theme.sizeUnit}px;
+ }
+`;
+
+const DefaultColumnSettingsContainer = styled.div`
+ ${({ theme }) => css`
+ margin-bottom: ${theme.sizeUnit * 4}px;
+ `}
+`;
+
+const DefaultColumnSettingsTitle = styled.h4`
+ ${({ theme }) => css`
+ margin: 0 0 ${theme.sizeUnit * 2}px 0;
+ font-size: ${theme.fontSizeLG}px;
+ font-weight: ${theme.fontWeightStrong};
+ color: ${theme.colorText};
+ `}
+`;
+
+const FieldLabelWithTooltip = styled.div`
+ ${({ theme }) => css`
+ display: flex;
+ align-items: center;
+ gap: ${theme.sizeUnit}px;
+ font-size: ${theme.fontSizeSM}px;
+ color: ${theme.colorTextLabel};
+ `}
+`;
+
+const StyledButtonWrapper = styled.span`
+ ${({ theme }) => `
+ margin-top: ${theme.sizeUnit * 3}px;
+ margin-left: ${theme.sizeUnit * 3}px;
+ button>span>:first-of-type {
+ margin-right: 0;
+ }
+ `}
+`;
+
+const checkboxGenerator = (
+ d: boolean,
+ onChange: (value: boolean) => void,
+): ReactNode => <CheckboxControl value={d} onChange={onChange} />;
+const DATA_TYPES = [
+ { value: 'STRING', label: t('STRING') },
+ { value: 'NUMERIC', label: t('NUMERIC') },
+ { value: 'DATETIME', label: t('DATETIME') },
+ { value: 'BOOLEAN', label: t('BOOLEAN') },
+];
+
+const TABS_KEYS = {
+ SOURCE: 'SOURCE',
+ METRICS: 'METRICS',
+ COLUMNS: 'COLUMNS',
+ CALCULATED_COLUMNS: 'CALCULATED_COLUMNS',
+ USAGE: 'USAGE',
+ FOLDERS: 'FOLDERS',
+ SETTINGS: 'SETTINGS',
+ SPATIAL: 'SPATIAL',
+};
+
+const DATASOURCE_TYPES_ARR = [
+ { key: 'physical', label: t('Physical (table or view)') },
+ { key: 'virtual', label: t('Virtual (SQL)') },
+];
+const DATASOURCE_TYPES: Record<string, { key: string; label: string }> = {};
+DATASOURCE_TYPES_ARR.forEach(o => {
+ DATASOURCE_TYPES[o.key] = o;
+});
+
+function CollectionTabTitle({
+ title,
+ collection,
+ count,
+}: CollectionTabTitleProps): JSX.Element {
+ return (
+ <div
+ css={{ display: 'flex', alignItems: 'center' }}
+ data-test={`collection-tab-${title}`}
+ >
+ {title}{' '}
+ <StyledBadge
+ count={count ?? (collection ? collection.length : 0)}
+ showZero
+ />
+ </div>
+ );
+}
+
+function FormContainer({ children }: FormContainerProps): JSX.Element {
+ return (
+ <Card padded style={{ backgroundColor: themeObject.theme.colorBgLayout }}>
+ {children}
+ </Card>
+ );
+}
+
+function ColumnCollectionTable({
+ columns,
+ datasource,
+ onColumnsChange,
+ onDatasourceChange,
+ editableColumnName = false,
+ showExpression = false,
+ allowAddItem = false,
+ allowEditDataType = false,
+ itemGenerator = () => ({
+ column_name: t('<new column>'),
+ filterable: true,
+ groupby: true,
+ }),
+ columnLabelTooltips,
+ filterTerm,
+ filterFields,
+}: ColumnCollectionTableProps): JSX.Element {
+ return (
+ <CollectionTable
+ tableColumns={
+ isFeatureEnabled(FeatureFlag.EnableAdvancedDataTypes)
+ ? [
+ 'column_name',
+ 'advanced_data_type',
+ 'type',
+ 'is_dttm',
+ 'filterable',
+ 'groupby',
+ ]
+ : ['column_name', 'type', 'is_dttm', 'filterable', 'groupby']
+ }
+ sortColumns={
+ isFeatureEnabled(FeatureFlag.EnableAdvancedDataTypes)
+ ? [
+ 'column_name',
+ 'advanced_data_type',
+ 'type',
+ 'is_dttm',
+ 'filterable',
+ 'groupby',
+ ]
+ : ['column_name', 'type', 'is_dttm', 'filterable', 'groupby']
+ }
+ allowDeletes
+ allowAddItem={allowAddItem}
+ itemGenerator={itemGenerator}
+ collection={columns}
+ columnLabelTooltips={columnLabelTooltips}
+ filterTerm={filterTerm}
+ filterFields={filterFields}
+ stickyHeader
+ expandFieldset={
+ <FormContainer>
+ <Fieldset compact>
+ {showExpression && (
+ <Field
+ fieldKey="expression"
+ label={t('SQL expression')}
+ control={
+ <TextAreaControl
+ language="sql"
+ offerEditInModal={false}
+ resize="vertical"
+ />
+ }
+ />
+ )}
+ <Field
+ fieldKey="verbose_name"
+ label={t('Label')}
+ control={
+ <TextControl
+ controlId="verbose_name"
+ placeholder={t('Label')}
+ />
+ }
+ />
+ <Field
+ fieldKey="description"
+ label={t('Description')}
+ control={
+ <TextControl
+ controlId="description"
+ placeholder={t('Description')}
+ />
+ }
+ />
+ {allowEditDataType && (
+ <Field
+ fieldKey="type"
+ label={t('Data type')}
+ control={
+ <Select
+ ariaLabel={t('Data type')}
+ header={<FormLabel>{t('Data type')}</FormLabel>}
+ options={DATA_TYPES}
+ name="type"
+ allowNewOptions
+ allowClear
+ />
+ }
+ />
+ )}
+ {isFeatureEnabled(FeatureFlag.EnableAdvancedDataTypes) ? (
+ <Field
+ fieldKey="advanced_data_type"
+ label={t('Advanced data type')}
+ control={
+ <TextControl
+ controlId="advanced_data_type"
+ placeholder={t('Advanced Data type')}
+ />
+ }
+ />
+ ) : (
+ <></>
+ )}
+ <Field
+ fieldKey="python_date_format"
+ label={t('Datetime format')}
+ description={
+ /* Note the fragmented translations may not work. */
+ <div>
+ {t('The pattern of timestamp format. For strings use ')}
+ <Typography.Link href="https://docs.python.org/2/library/datetime.html#strftime-strptime-behavior">
+ {t('Python datetime string pattern')}
+ </Typography.Link>
+ {t(' expression which needs to adhere to the ')}
+ <Typography.Link href="https://en.wikipedia.org/wiki/ISO_8601">
+ {t('ISO 8601')}
+ </Typography.Link>
+ {t(` standard to ensure that the lexicographical ordering
+ coincides with the chronological ordering. If the
+ timestamp format does not adhere to the ISO 8601 standard
+ you will need to define an expression and type for
+ transforming the string into a date or timestamp. Note
+ currently time zones are not supported. If time is stored
+ in epoch format, put \`epoch_s\` or \`epoch_ms\`. If no pattern
+ is specified we fall back to using the optional defaults on a per
+ database/column name level via the extra parameter.`)}
+ </div>
+ }
+ control={
+ <TextControl
+ controlId="python_date_format"
+ placeholder="%Y-%m-%d"
+ />
+ }
+ />
+ <Field
+ fieldKey="certified_by"
+ label={t('Certified By')}
+ description={t('Person or group that has certified this metric')}
+ control={
+ <TextControl
+ controlId="certified"
+ placeholder={t('Certified by')}
+ />
+ }
+ />
+ <Field
+ fieldKey="certification_details"
+ label={t('Certification details')}
+ description={t('Details of the certification')}
+ control={
+ <TextControl
+ controlId="certificationDetails"
+ placeholder={t('Certification details')}
+ />
+ }
+ />
+ </Fieldset>
+ </FormContainer>
+ }
+ columnLabels={
+ isFeatureEnabled(FeatureFlag.EnableAdvancedDataTypes)
+ ? {
+ column_name: t('Column'),
+ advanced_data_type: t('Advanced data type'),
+ type: t('Data type'),
+ groupby: t('Is dimension'),
+ is_dttm: t('Is temporal'),
+ filterable: t('Is filterable'),
+ }
+ : {
+ column_name: t('Column'),
+ type: t('Data type'),
+ groupby: t('Is dimension'),
+ is_dttm: t('Is temporal'),
+ filterable: t('Is filterable'),
+ }
+ }
+ onChange={onColumnsChange}
+ itemRenderers={
+ isFeatureEnabled(FeatureFlag.EnableAdvancedDataTypes)
+ ? {
+ column_name: (v, onItemChange, _, record) =>
+ editableColumnName ? (
+ <StyledLabelWrapper>
+ {record.is_certified && (
+ <CertifiedBadge
+ certifiedBy={record.certified_by}
+ details={record.certification_details}
+ />
+ )}
+ <EditableTitle
+ canEdit
+ title={v as string}
+ onSaveTitle={onItemChange}
+ />
+ </StyledLabelWrapper>
+ ) : (
+ <StyledLabelWrapper>
+ {record.is_certified && (
+ <CertifiedBadge
+ certifiedBy={record.certified_by}
+ details={record.certification_details}
+ />
+ )}
+ {v}
+ </StyledLabelWrapper>
+ ),
+ type: d => (d ? <Label>{d}</Label> : null),
+ advanced_data_type: d => <Label>{d as string}</Label>,
+ is_dttm: checkboxGenerator,
+ filterable: checkboxGenerator,
+ groupby: checkboxGenerator,
+ }
+ : {
+ column_name: (v, onItemChange, _, record) =>
+ editableColumnName ? (
+ <StyledLabelWrapper>
+ {record.is_certified && (
+ <CertifiedBadge
+ certifiedBy={record.certified_by}
+ details={record.certification_details}
+ />
+ )}
+ <TextControl value={v as string} onChange={onItemChange} />
+ </StyledLabelWrapper>
+ ) : (
+ <StyledLabelWrapper>
+ {record.is_certified && (
+ <CertifiedBadge
+ certifiedBy={record.certified_by}
+ details={record.certification_details}
+ />
+ )}
+ {v}
+ </StyledLabelWrapper>
+ ),
+ type: d => (d ? <Label>{d}</Label> : null),
+ is_dttm: checkboxGenerator,
+ filterable: checkboxGenerator,
+ groupby: checkboxGenerator,
+ }
+ }
+ />
+ );
+}
+
+function StackedField({ label, formElement }: StackedFieldProps): JSX.Element {
+ return (
+ <div>
+ <div>
+ <strong>{label}</strong>
+ </div>
+ <div>{formElement}</div>
+ </div>
+ );
+}
+
+function OwnersSelector({
+ datasource,
+ onChange,
+}: OwnersSelectorProps): JSX.Element {
+ const loadOptions = useCallback(
+ (
+ search = '',
+ page: number,
+ pageSize: number,
+ ): Promise<{ data: Owner[]; totalCount: number }> => {
+ const query = rison.encode({ filter: search, page, page_size: pageSize });
+ return SupersetClient.get({
+ endpoint: `/api/v1/dataset/related/owners?q=${query}`,
+ }).then(response => ({
+ data: (response.json.result as Array<JsonObject>)
+ .filter(item => item.extra.active)
+ .map(item => ({
+ value: item.value as number,
+ label: OwnerSelectLabel({
+ name: item.text as string,
+ email: item.extra?.email as string | undefined,
+ }),
+ [OWNER_TEXT_LABEL_PROP]: item.text as string,
+ [OWNER_EMAIL_PROP]: (item.extra?.email as string) ?? '',
+ })),
+ totalCount: response.json.count,
+ }));
+ },
+ [],
+ );
+
+ return (
+ <AsyncSelect
+ ariaLabel={t('Select owners')}
+ mode="multiple"
+ name="owners"
+ value={datasource.owners as { value: number; label: string }[]}
+ options={loadOptions}
+ onChange={value => onChange(value as Owner[])}
+ header={<FormLabel>{t('Owners')}</FormLabel>}
+ allowClear
+ optionFilterProps={OWNER_OPTION_FILTER_PROPS}
+ />
+ );
+}
+const ResultTable =
+ extensionsRegistry.get('sqleditor.extension.resultTable') ?? FilterableTable;
+
+// Redux connector types
+interface QueryPayload {
+ client_id?: string;
+ database_id: number;
+ runAsync: boolean;
+ catalog?: string;
+ schema?: string;
+ sql: string;
+ tmp_table_name: string;
+ select_as_cta: boolean;
+ ctas_method: string;
+ queryLimit: number;
+ expand_data: boolean;
+}
+
+interface FormatQueryResponse {
+ json: {
+ result: string;
+ };
+}
+
+const mapDispatchToProps = (
+ dispatch: ThunkDispatch<RootState, unknown, AnyAction>,
+) => ({
+ runQuery: (payload: QueryPayload) =>
+ dispatch(executeQuery(payload as Parameters<typeof executeQuery>[0])),
+ resetQuery: () => dispatch(resetDatabaseState()),
+ formatQuery: (
+ sql: string,
+ options: { signal: AbortSignal },
+ ): Promise<FormatQueryResponse> =>
+ dispatch(
+ formatQuery(sql, options),
+ ) as unknown as Promise<FormatQueryResponse>,
+});
+
+const mapStateToProps = (state: RootState) => ({
+ database: state?.database,
+});
+
+const connector = connect(mapStateToProps, mapDispatchToProps);
+type PropsFromRedux = ConnectedProps<typeof connector>;
+
+type DatasourceEditorProps = DatasourceEditorOwnProps &
+ PropsFromRedux & {
+ theme?: SupersetTheme;
+ };
+
+class DatasourceEditor extends PureComponent<
+ DatasourceEditorProps,
+ DatasourceEditorState
+> {
+ private isComponentMounted: boolean;
+
+ private abortControllers: AbortControllers;
+
+ static defaultProps = {
+ onChange: () => {},
+ setIsEditing: () => {},
+ };
+
+ constructor(props: DatasourceEditorProps) {
+ super(props);
+ this.state = {
+ datasource: {
+ ...props.datasource,
+ owners: props.datasource.owners.map(owner => {
+ const ownerName =
+ owner.label || `${owner.first_name} ${owner.last_name}`;
+ return {
+ value: owner.value || owner.id,
+ label: OwnerSelectLabel({
+ name: typeof ownerName === 'string' ? ownerName : '',
+ email: owner.email,
+ }),
+ [OWNER_TEXT_LABEL_PROP]:
+ typeof ownerName === 'string' ? ownerName : '',
+ [OWNER_EMAIL_PROP]: owner.email ?? '',
+ };
+ }),
+ metrics: props.datasource.metrics?.map(metric => {
+ const {
+ certified_by: certifiedByMetric,
+ certification_details: certificationDetails,
+ } = metric;
+ const {
+ certification: {
+ details = undefined,
+ certified_by: certifiedBy = undefined,
+ } = {},
+ warning_markdown: warningMarkdown,
+ } = JSON.parse(metric.extra || '{}') || {};
+ return {
+ ...metric,
+ certification_details: certificationDetails || details,
+ warning_markdown: warningMarkdown || '',
+ certified_by: certifiedBy || certifiedByMetric,
+ };
+ }),
+ },
+ errors: [],
+ isSqla:
+ props.datasource.datasource_type === 'table' ||
+ props.datasource.type === 'table',
+ isEditMode: false,
+ databaseColumns: props.datasource.columns.filter(col => !col.expression),
+ calculatedColumns: props.datasource.columns.filter(
+ col => !!col.expression,
+ ),
+ folders: props.datasource.folders || [],
+ folderCount: (() => {
+ const savedFolders = props.datasource.folders || [];
+ const savedCount = countAllFolders(savedFolders);
+ const hasDefaultsSaved = savedFolders.some(f =>
+ isDefaultFolder(f.uuid),
+ );
+ return savedCount + (hasDefaultsSaved ? 0 : DEFAULT_FOLDERS_COUNT);
+ })(),
+ metadataLoading: false,
+ activeTabKey: TABS_KEYS.SOURCE,
+ datasourceType: props.datasource.sql
+ ? DATASOURCE_TYPES.virtual.key
+ : DATASOURCE_TYPES.physical.key,
+ usageCharts: [],
+ usageChartsCount: 0,
+ metricSearchTerm: '',
+ columnSearchTerm: '',
+ calculatedColumnSearchTerm: '',
+ };
+
+ this.isComponentMounted = false;
+ this.abortControllers = {
+ formatQuery: null,
+ formatSql: null,
+ syncMetadata: null,
+ fetchUsageData: null,
+ };
+
+ this.onChange = this.onChange.bind(this);
+ this.onChangeEditMode = this.onChangeEditMode.bind(this);
+ this.onDatasourcePropChange = this.onDatasourcePropChange.bind(this);
+ this.onDatasourceChange = this.onDatasourceChange.bind(this);
+ this.tableChangeAndSyncMetadata =
+ this.tableChangeAndSyncMetadata.bind(this);
+ this.syncMetadata = this.syncMetadata.bind(this);
+ this.setColumns = this.setColumns.bind(this);
+ this.validateAndChange = this.validateAndChange.bind(this);
+ this.handleTabSelect = this.handleTabSelect.bind(this);
+ this.formatSql = this.formatSql.bind(this);
+ this.fetchUsageData = this.fetchUsageData.bind(this);
+ this.handleFoldersChange = this.handleFoldersChange.bind(this);
+ }
+
+ onChange() {
+ // Emptying SQL if "Physical" radio button is selected
+ // Currently the logic to know whether the source is
+ // physical or virtual is based on whether SQL is empty or not.
+ const { datasourceType, datasource } = this.state;
+ const sql =
+ datasourceType === DATASOURCE_TYPES.physical.key ? '' : datasource.sql;
+
+ const columns = [
+ ...this.state.databaseColumns,
+ ...this.state.calculatedColumns,
+ ];
+
+ // Remove deleted column/metric references from folders
+ const validUuids = new Set<string>();
+ for (const col of columns) {
+ if (col.uuid) validUuids.add(col.uuid);
+ }
+ for (const metric of datasource.metrics ?? []) {
+ if (metric.uuid) validUuids.add(metric.uuid);
+ }
+ const folders = filterFoldersByValidUuids(this.state.folders, validUuids);
+
+ const newDatasource = {
+ ...this.state.datasource,
+ sql,
+ columns,
+ folders,
+ };
+
+ this.props.onChange?.(newDatasource, this.state.errors);
+ }
+
+ onChangeEditMode() {
+ this.props.setIsEditing?.(!this.state.isEditMode);
+ this.setState(prevState => ({ isEditMode: !prevState.isEditMode }));
+ }
+
+ onDatasourceChange(
+ datasource: DatasourceObject,
+ callback: () => void = this.validateAndChange,
+ ) {
+ this.setState({ datasource }, callback);
+ }
+
+ onDatasourcePropChange(attr: string, value: unknown) {
+ if (value === undefined) return; // if value is undefined do not update state
+ const datasource = { ...this.state.datasource, [attr]: value };
+ this.setState(
+ prevState => ({
+ datasource: { ...prevState.datasource, [attr]: value },
+ }),
+ () =>
+ attr === 'table_name'
+ ? this.onDatasourceChange(datasource, this.tableChangeAndSyncMetadata)
+ : this.onDatasourceChange(datasource, this.validateAndChange),
+ );
+ }
+
+ onDatasourceTypeChange(datasourceType: string) {
+ // Call onChange after setting datasourceType to ensure
+ // SQL is cleared when switching to a physical dataset
+ this.setState({ datasourceType }, this.onChange);
+ }
+
+ handleFoldersChange(folders: DatasourceFolder[]) {
+ const folderCount = countAllFolders(folders);
+ this.setState({ folders, folderCount }, () => {
+ this.onDatasourceChange({
+ ...this.state.datasource,
+ folders,
+ });
+ });
+ }
+
+ setColumns(
+ obj: { databaseColumns?: Column[] } | { calculatedColumns?: Column[] },
+ ) {
+ // update calculatedColumns or databaseColumns
+ this.setState(
+ obj as Pick<
+ DatasourceEditorState,
+ 'databaseColumns' | 'calculatedColumns'
+ >,
+ this.validateAndChange,
+ );
+ }
+
+ validateAndChange() {
+ this.validate(this.onChange);
+ }
+
+ async onQueryRun() {
+ const databaseId = this.state.datasource.database?.id;
+ const { sql } = this.state.datasource;
+ if (!databaseId || !sql) {
+ return;
+ }
+ this.props.runQuery({
+ client_id: this.props.database?.clientId,
+ database_id: databaseId,
+ runAsync: false,
+ catalog: this.state.datasource.catalog,
+ schema: this.state.datasource.schema,
+ sql,
+ tmp_table_name: '',
+ select_as_cta: false,
+ ctas_method: 'TABLE',
+ queryLimit: 25,
+ expand_data: true,
+ });
+ }
+
+ /**
+ * Formats SQL query using the formatQuery action.
+ * Aborts any pending format requests before starting a new one.
+ */
+ async onQueryFormat() {
+ const { datasource } = this.state;
+ if (!datasource.sql || !this.state.isEditMode) {
+ return;
+ }
+
+ // Abort previous formatQuery if still pending
+ if (this.abortControllers.formatQuery) {
+ this.abortControllers.formatQuery.abort();
+ }
+
+ this.abortControllers.formatQuery = new AbortController();
+ const { signal } = this.abortControllers.formatQuery;
+
+ try {
+ const response = await this.props.formatQuery(datasource.sql, { signal });
+
+ this.onDatasourcePropChange('sql', response.json.result);
+ this.props.addSuccessToast(t('SQL was formatted'));
+ } catch (error) {
+ if (error.name === 'AbortError') return;
+
+ const { error: clientError, statusText } =
+ await getClientErrorObject(error);
+
+ this.props.addDangerToast(
+ clientError ||
+ statusText ||
+ t('An error occurred while formatting SQL'),
+ );
+ } finally {
+ this.abortControllers.formatQuery = null;
+ }
+ }
+
+ getSQLLabUrl() {
+ const queryParams = new URLSearchParams({
+ dbid: String(this.state.datasource.database?.id ?? ''),
+ sql: this.state.datasource.sql ?? '',
+ name: this.state.datasource.datasource_name ?? '',
+ schema: this.state.datasource.schema ?? '',
+ autorun: 'true',
+ isDataset: 'true',
+ });
+ return makeUrl(`/sqllab/?${queryParams.toString()}`);
+ }
+
+ openOnSqlLab() {
+ window.open(this.getSQLLabUrl(), '_blank', 'noopener,noreferrer');
+ }
+
+ tableChangeAndSyncMetadata() {
+ this.validate(() => {
+ this.syncMetadata();
+ this.onChange();
+ });
+ }
+
+ /**
+ * Formats SQL query using the SQL format API endpoint.
+ * Aborts any pending format requests before starting a new one.
+ */
+ async formatSql() {
+ const { datasource } = this.state;
+ if (!datasource.sql) {
+ return;
+ }
+
+ // Abort previous formatSql if still pending
+ if (this.abortControllers.formatSql) {
+ this.abortControllers.formatSql.abort();
+ }
+
+ this.abortControllers.formatSql = new AbortController();
+ const { signal } = this.abortControllers.formatSql;
+
+ try {
+ const response = await SupersetClient.post({
+ endpoint: '/api/v1/sql/format',
+ body: JSON.stringify({ sql: datasource.sql }),
+ headers: { 'Content-Type': 'application/json' },
+ signal,
+ });
+
+ this.onDatasourcePropChange('sql', response.json.result);
+ this.props.addSuccessToast(t('SQL was formatted'));
+ } catch (error) {
+ if (error.name === 'AbortError') return;
+
+ const { error: clientError, statusText } =
+ await getClientErrorObject(error);
+
+ this.props.addDangerToast(
+ clientError ||
+ statusText ||
+ t('An error occurred while formatting SQL'),
+ );
+ } finally {
+ this.abortControllers.formatSql = null;
+ }
+ }
+
+ /**
+ * Syncs dataset columns with the database schema.
+ * Fetches column metadata from the underlying table/view and updates the dataset.
+ * Aborts any pending sync requests before starting a new one.
+ */
+ async syncMetadata() {
+ const { datasource } = this.state;
+
+ // Abort previous syncMetadata if still pending
+ if (this.abortControllers.syncMetadata) {
+ this.abortControllers.syncMetadata.abort();
+ }
+
+ this.abortControllers.syncMetadata = new AbortController();
+ const { signal } = this.abortControllers.syncMetadata;
+
+ this.setState({ metadataLoading: true });
+
+ try {
+ const newCols = await fetchSyncedColumns(datasource, signal);
+
+ const columnChanges = updateColumns(
+ datasource.columns,
+ newCols,
+ this.props.addSuccessToast,
+ );
+ this.setColumns({
+ databaseColumns: columnChanges.finalColumns.filter(
+ col => !col.expression, // remove calculated columns
+ ) as Column[],
+ });
+
+ if (datasource.id !== undefined) {
+ clearDatasetCache(datasource.id);
+ }
+
+ this.props.addSuccessToast(t('Metadata has been synced'));
+ this.setState({ metadataLoading: false });
+ } catch (error) {
+ if (error.name === 'AbortError') {
+ // Only update state if still mounted (abort may happen during unmount)
+ if (this.isComponentMounted) {
+ this.setState({ metadataLoading: false });
+ }
+ return;
+ }
+
+ const { error: clientError, statusText } =
+ await getClientErrorObject(error);
+
+ this.props.addDangerToast(
+ clientError || statusText || t('An error has occurred'),
+ );
+ this.setState({ metadataLoading: false });
+ } finally {
+ this.abortControllers.syncMetadata = null;
+ }
+ }
+
+ /**
+ * Fetches chart usage data for this dataset (which charts use this dataset).
+ * Aborts any pending fetch requests before starting a new one.
+ *
+ * @param {number} page - Page number (1-indexed)
+ * @param {number} pageSize - Number of results per page
+ * @param {string} sortColumn - Column to sort by
+ * @param {string} sortDirection - Sort direction ('asc' or 'desc')
+ * @returns {Promise<{charts: Array, count: number, ids: Array}>} Chart usage data
+ */
+ async fetchUsageData(
+ page = 1,
+ pageSize = 25,
+ sortColumn = 'changed_on_delta_humanized',
+ sortDirection = 'desc',
+ ) {
+ const { datasource } = this.state;
+
+ // Abort previous fetchUsageData if still pending
+ if (this.abortControllers.fetchUsageData) {
+ this.abortControllers.fetchUsageData.abort();
+ }
+
+ this.abortControllers.fetchUsageData = new AbortController();
+ const { signal } = this.abortControllers.fetchUsageData;
+
+ try {
+ const queryParams = rison.encode({
+ columns: [
+ 'slice_name',
+ 'url',
+ 'certified_by',
+ 'certification_details',
+ 'description',
+ 'owners.first_name',
+ 'owners.last_name',
+ 'owners.id',
+ 'changed_on_delta_humanized',
+ 'changed_on',
+ 'changed_by.first_name',
+ 'changed_by.last_name',
+ 'changed_by.id',
+ 'dashboards.id',
+ 'dashboards.dashboard_title',
+ 'dashboards.url',
+ ],
+ filters: [
+ {
+ col: 'datasource_id',
+ opr: 'eq',
+ value: datasource.id,
+ },
+ ],
+ order_column: sortColumn,
+ order_direction: sortDirection,
+ page: page - 1,
+ page_size: pageSize,
+ });
+
+ const { json = {} } = await SupersetClient.get({
+ endpoint: `/api/v1/chart/?q=${queryParams}`,
+ signal,
+ });
+
+ const charts = json?.result || [];
+ const ids = json?.ids || [];
+
+ // Map chart IDs to chart objects
+ const chartsWithIds = charts.map(
+ (chart: Omit<ChartUsageData, 'id'>, index: number) => ({
+ ...chart,
+ id: ids[index],
+ }),
+ );
+
+ // Only update state if not aborted and component still mounted
+ if (!signal.aborted && this.isComponentMounted) {
+ this.setState({
+ usageCharts: chartsWithIds,
+ usageChartsCount: json?.count || 0,
+ });
+ }
+
+ return {
+ charts: chartsWithIds,
+ count: json?.count || 0,
+ ids,
+ };
+ } catch (error) {
+ // Rethrow AbortError so callers can handle gracefully
+ if (error.name === 'AbortError') throw error;
+
+ const { error: clientError, statusText } =
+ await getClientErrorObject(error);
+
+ this.props.addDangerToast(
+ clientError ||
+ statusText ||
+ t('An error occurred while fetching usage data'),
+ );
+ this.setState({
+ usageCharts: [],
+ usageChartsCount: 0,
+ });
+
+ return {
+ charts: [],
+ count: 0,
+ ids: [],
+ };
+ } finally {
+ this.abortControllers.fetchUsageData = null;
+ }
+ }
+
+ findDuplicates<T>(arr: T[], accessor: (obj: T) => string): string[] {
+ const seen: Record<string, null> = {};
+ const dups: string[] = [];
+ arr.forEach((obj: T) => {
+ const item = accessor(obj);
+ if (item in seen) {
+ dups.push(item);
+ } else {
+ seen[item] = null;
+ }
+ });
+ return dups;
+ }
+
+ validate(callback: () => void) {
+ let errors: string[] = [];
+ let dups: string[];
+ const { datasource } = this.state;
+
+ // Looking for duplicate column_name
+ dups = this.findDuplicates(datasource.columns, obj => obj.column_name);
+ errors = errors.concat(
+ dups.map(name => t('Column name [%s] is duplicated', name)),
+ );
+
+ // Looking for duplicate metric_name
+ dups = this.findDuplicates(
+ datasource.metrics ?? [],
+ obj => obj.metric_name,
+ );
+ errors = errors.concat(
+ dups.map(name => t('Metric name [%s] is duplicated', name)),
+ );
+
+ // Making sure calculatedColumns have an expression defined
+ const noFilterCalcCols = this.state.calculatedColumns.filter(
+ col => !col.expression && !col.json,
+ );
+ errors = errors.concat(
+ noFilterCalcCols.map(col =>
+ t('Calculated column [%s] requires an expression', col.column_name),
+ ),
+ );
+
+ // validate currency code (skip 'AUTO' - it's a placeholder for auto-detection)
+ try {
+ this.state.datasource.metrics?.forEach(
+ metric =>
+ metric.currency?.symbol &&
+ metric.currency.symbol !== 'AUTO' &&
+ new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: metric.currency.symbol,
+ }),
+ );
+ } catch {
+ errors = errors.concat([t('Invalid currency code in saved metrics')]);
+ }
+
+ // Validate folders
+ if (this.state.folders?.length > 0) {
+ const folderValidation = validateFolders(this.state.folders);
+ errors = errors.concat(folderValidation.errors);
+ }
+
+ this.setState({ errors }, callback);
+ }
+
+ handleTabSelect(activeTabKey: string) {
+ this.setState({ activeTabKey });
+ }
+
+ sortMetrics(metrics: Metric[]) {
+ return metrics.sort(
+ ({ id: a }: { id?: number }, { id: b }: { id?: number }) =>
+ (b ?? 0) - (a ?? 0),
+ );
+ }
+
+ renderDefaultColumnSettings() {
+ const { datasource, databaseColumns, calculatedColumns } = this.state;
+ const { theme } = this.props;
+ const allColumns = [...databaseColumns, ...calculatedColumns];
+
+ // Get datetime-compatible columns for the default datetime dropdown
+ const datetimeColumns = allColumns
+ .filter(col => col.is_dttm)
+ .map(col => ({
+ value: col.column_name,
+ label: col.verbose_name || col.column_name,
+ }));
+
+ // String columns + untyped calculated columns for the currency code dropdown
+ const stringColumns = allColumns
+ .filter(
+ col =>
+ col.type_generic === GenericDataType.String ||
+ (col.expression && col.type_generic == null),
+ )
+ .map(col => ({
+ value: col.column_name,
+ label: col.verbose_name || col.column_name,
+ }));
+
+ return (
+ <DefaultColumnSettingsContainer data-test="default-column-settings">
+ <DefaultColumnSettingsTitle>
+ {t('Default Column Settings')}
+ </DefaultColumnSettingsTitle>
+ <Flex vertical gap={(theme?.sizeUnit ?? 4) * 3}>
+ <Flex vertical gap={theme?.sizeUnit ?? 4}>
+ <FieldLabelWithTooltip>
+ <span>{t('Default datetime column')}</span>
+ <InfoTooltip
+ tooltip={t(
+ 'Sets the default temporal column for this dataset. Automatically selected as the time column when building charts that require a time dimension and used in dashboard level time filters.',
+ )}
+ />
+ </FieldLabelWithTooltip>
+ <Select
+ ariaLabel={t('Default datetime column')}
+ options={datetimeColumns}
+ value={datasource.main_dttm_col}
+ onChange={value =>
+ this.onDatasourceChange({
+ ...datasource,
+ main_dttm_col: value as string | undefined,
+ })
+ }
+ placeholder={t('Select datetime column')}
+ allowClear
+ data-test="default-datetime-column-select"
+ />
+ </Flex>
+ <Flex vertical gap={theme?.sizeUnit ?? 4}>
+ <FieldLabelWithTooltip>
+ <span>{t('Currency code column')}</span>
+ <InfoTooltip
+ tooltip={t(
+ "Select the column containing currency codes such as USD, EUR, GBP, etc. Used when building charts when 'Auto-detect' currency formatting is enabled. If this column is not set or if a chart metric contains multiple currencies, charts will fall back to neutral numeric formatting.",
+ )}
+ />
+ </FieldLabelWithTooltip>
+ <Select
+ ariaLabel={t('Currency code column')}
+ options={stringColumns}
+ value={datasource.currency_code_column}
+ onChange={value =>
+ this.onDatasourceChange({
+ ...datasource,
+ currency_code_column: value as string | undefined,
+ })
+ }
+ placeholder={t('Select currency code column')}
+ allowClear
+ data-test="currency-code-column-select"
+ />
+ </Flex>
+ </Flex>
+ </DefaultColumnSettingsContainer>
+ );
+ }
+
+ renderSettingsFieldset() {
+ const { datasource } = this.state;
+ return (
+ <Fieldset
+ title={t('Basic')}
+ item={datasource}
+ onChange={this.onDatasourceChange}
+ >
+ <Field
+ fieldKey="description"
+ label={t('Description')}
+ control={
+ <TextAreaControl
+ language="markdown"
+ offerEditInModal={false}
+ resize="vertical"
+ />
+ }
+ />
+ <Field
+ fieldKey="default_endpoint"
+ label={t('Default URL')}
+ description={
+ <>
+ {t(
+ 'Default URL to redirect to when accessing from the dataset list page. Accepts relative URLs such as',
+ )}{' '}
+ <Typography.Text code>
+ /superset/dashboard/{'{id}'}/
+ </Typography.Text>
+ </>
+ }
+ control={<TextControl controlId="default_endpoint" />}
+ />
+ <Field
+ inline
+ fieldKey="filter_select_enabled"
+ label={t('Autocomplete filters')}
+ description={t('Whether to populate autocomplete filters options')}
+ control={<CheckboxControl />}
+ />
+ {this.state.isSqla && (
+ <Field
+ fieldKey="fetch_values_predicate"
+ label={t('Autocomplete query predicate')}
+ description={t(
+ 'When using "Autocomplete filters", this can be used to improve performance ' +
+ 'of the query fetching the values. Use this option to apply a ' +
+ 'predicate (WHERE clause) to the query selecting the distinct ' +
+ 'values from the table. Typically the intent would be to limit the scan ' +
+ 'by applying a relative time filter on a partitioned or indexed time-related field.',
+ )}
+ control={
+ <TextAreaControl
+ language="sql"
+ controlId="fetch_values_predicate"
+ minLines={5}
+ resize="vertical"
+ />
+ }
+ />
+ )}
+ {this.state.isSqla && (
+ <Field
+ fieldKey="extra"
+ label={t('Extra')}
+ description={t(
+ 'Extra data to specify table metadata. Currently supports ' +
+ 'metadata of the format: `{ "certification": { "certified_by": ' +
+ '"Data Platform Team", "details": "This table is the source of truth." ' +
+ '}, "warning_markdown": "This is a warning." }`.',
+ )}
+ control={
+ <TextAreaControl
+ controlId="extra"
+ language="json"
+ offerEditInModal={false}
+ resize="vertical"
+ />
+ }
+ />
+ )}
+ <OwnersSelector
+ datasource={datasource}
+ onChange={newOwners => {
+ this.onDatasourceChange({ ...datasource, owners: newOwners });
+ }}
+ />
+ </Fieldset>
+ );
+ }
+
+ renderAdvancedFieldset() {
+ const { datasource } = this.state;
+ return (
+ <Fieldset
+ title={t('Advanced')}
+ item={datasource}
+ onChange={this.onDatasourceChange}
+ >
+ <Field
+ fieldKey="cache_timeout"
+ label={t('Cache timeout')}
+ description={t(
+ 'The duration of time in seconds before the cache is invalidated. Set to -1 to bypass the cache.',
+ )}
+ control={<TextControl controlId="cache_timeout" />}
+ />
+ <Field
+ fieldKey="offset"
+ label={t('Hours offset')}
+ control={<TextControl controlId="offset" />}
+ description={t(
+ 'The number of hours, negative or positive, to shift the time column. This can be used to move UTC time to local time.',
+ )}
+ />
+ {this.state.isSqla && (
+ <Field
+ fieldKey="template_params"
+ label={t('Template parameters')}
+ description={t(
+ 'A set of parameters that become available in the query using Jinja templating syntax',
+ )}
+ control={<TextControl controlId="template_params" />}
+ />
+ )}
+ <Field
+ inline
+ fieldKey="normalize_columns"
+ label={t('Normalize column names')}
+ description={t(
+ 'Allow column names to be changed to case insensitive format, if supported (e.g. Oracle, Snowflake).',
+ )}
+ control={<CheckboxControl />}
+ />
+ <Field
+ inline
+ fieldKey="always_filter_main_dttm"
+ label={t('Always filter main datetime column')}
+ description={t(
+ `When the secondary temporal columns are filtered, apply the same filter to the main datetime column.`,
+ )}
+ control={<CheckboxControl />}
+ />
+ </Fieldset>
+ );
+ }
+
+ renderSpatialTab() {
+ const { datasource } = this.state;
+ const { spatials, all_cols: allCols } = datasource;
+
+ return {
+ key: TABS_KEYS.SPATIAL,
+ label: <CollectionTabTitle collection={spatials} title={t('Spatial')} />,
+ children: (
+ <CollectionTable
+ tableColumns={['name', 'config']}
+ sortColumns={['name']}
+ onChange={this.onDatasourcePropChange.bind(this, 'spatials')}
+ itemGenerator={() => ({
+ name: t('<new spatial>'),
+ type: t('<no type>'),
+ config: null,
+ })}
+ collection={spatials ?? []}
+ allowDeletes
+ itemRenderers={{
+ name: (d, onChange) => (
+ <EditableTitle
+ canEdit
+ title={d as string}
+ onSaveTitle={onChange}
+ />
+ ),
+ config: (v, onChange) => (
+ <SpatialControl
+ value={
+ v as {
+ type: 'latlong' | 'delimited' | 'geohash';
+ }
+ }
+ onChange={onChange}
+ choices={allCols?.map(col => [col, col] as [string, string])}
+ />
+ ),
+ }}
+ />
+ ),
+ };
+ }
+
+ renderSqlEditorOverlay = () => (
+ <div
+ css={theme => css`
+ position: absolute;
+ background: ${theme.colorBgLayout};
+ align-items: center;
+ display: flex;
+ height: 100%;
+ width: 100%;
+ justify-content: center;
+ `}
+ >
+ <div>
+ <Loading position="inline-centered" />
+ <span
+ css={theme => css`
+ display: block;
+ margin: ${theme.sizeUnit * 4}px auto;
+ width: fit-content;
+ color: ${theme.colorText};
+ `}
+ >
+ {t('We are working on your query')}
+ </span>
+ </div>
+ </div>
+ );
+
+ renderOpenInSqlLabLink(isError = false) {
+ return (
+ <a
+ href={this.getSQLLabUrl()}
Review Comment:
## DOM text reinterpreted as HTML
[DOM text](1) is reinterpreted as HTML without escaping meta-characters.
[Show more details](https://github.com/apache/superset/security/code-scanning/2230)
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "manojshetty2004 (via GitHub)" <gi...@apache.org>.
manojshetty2004 commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4327312308
@rusackas Thanks for pointing that out! It looks like the original change was dropped during conflict resolution and the current diff is empty. Given the scope is minimal, I’ll go ahead and close this PR. Appreciate the review and guidance.
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "rusackas (via GitHub)" <gi...@apache.org>.
rusackas commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4307738163
@manojshetty2004 thanks for the ping! The branch has drifted and now has merge conflicts with master — could you rebase onto the latest master and resolve them? Once that's done and CI is green I'll take another look. Also, the current diff is just a one-line `margin-bottom` bump; the typography-weight changes mentioned in the title/description appear to have been reverted along the way, so it'd be worth either updating the PR title/description to reflect the narrower scope or re-introducing the weight change if that was the original intent.
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [PR] style(explore): normalize typography in widget settings panels [superset]
Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #36781:
URL: https://github.com/apache/superset/pull/36781#issuecomment-4048702899
AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
<details>
<summary>
Bito Usage Guide
</summary>
**Commands**
Type the following command in the pull request comment and save the comment.
- `/review` - Manually triggers a full AI review.
- `/pause` - Pauses automatic reviews on this pull request.
- `/resume` - Resumes automatic reviews.
- `/resolve` - Marks all Bito-posted review comments as resolved.
- `/abort` - Cancels all in-progress reviews.
Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
**Configuration**
This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
**Documentation & Help**
- <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
- <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
- <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
- <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
</details>
--
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: notifications-unsubscribe@superset.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org