Skip to content

Conversation

@Facyla
Copy link

@Facyla Facyla commented Nov 13, 2025

User description

SUMMARY

Add a JSON-based customisation block that allows to override linearColorScheme colors and thresholds.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

A new setting is available is "Chart Options" panel
image

TESTING INSTRUCTIONS

  • Cut sample rules in "Custom Color Scale": the overrided configuration is removed, resulting in the original linear Color Scheme to apply.
  • Edit sample values to update colors and thresholds, or add/remove thresholds: the new configuration should apply.

ADDITIONAL INFORMATION

  • Has associated issue: mentioned in Implement custom formatting similar to Table Chart into Country Map plugin #34427
  • Required feature flags:
  • Changes UI: new setting added, modal for editing
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

CodeAnt-AI Description

Add custom color rules and percent-based color scales to the Country Map chart

What Changed

  • Users can define a JSON "Custom Color Scale (by %)" to map percentage thresholds to exact colors; the chart applies the specified step colors without blending between steps
  • Users can set per-value or min/max range color overrides via "custom color rules" and pick colors with a new color picker that provides HEX codes for the custom scale
  • Invalid JSON in custom controls is caught and logged (chart falls back gracefully); non-numeric metric values are ignored and regions with missing numeric data render as empty
  • Color selection priority: conditional rules (exact value / ranges) → percent-based custom scale → registered linear palette → gradient fallback between configured min and max colors
  • Visual tweak: map text labels receive a subtle white text shadow for improved readability

Impact

✅ Custom color steps for Country Map
✅ Easier color selection for custom scales
✅ Clearer handling of invalid JSON and non-numeric metrics

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@bito-code-review
Copy link
Contributor

bito-code-review bot commented Nov 13, 2025

Code Review Agent Run #3fbf4f

Actionable Suggestions - 0
Review Details
  • Files reviewed - 4 · Commit Range: 58885b0..58885b0
    • superset-frontend/plugins/legacy-plugin-chart-country-map/src/CountryMap.js
    • superset-frontend/plugins/legacy-plugin-chart-country-map/src/ReactCountryMap.jsx
    • superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts
    • superset-frontend/plugins/legacy-plugin-chart-country-map/src/transformProps.js
  • Files skipped - 0
  • Tools
    • Eslint (Linter) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

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 documentation for additional commands.

Configuration

This repository uses Default Agent You can customize the agent settings here or contact your Bito workspace admin at [email protected].

Documentation & Help

AI Code Review powered by Bito Logo

Copy link

@korbit-ai korbit-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've completed my review and didn't find any issues.

Files scanned
File Path Reviewed
superset-frontend/plugins/legacy-plugin-chart-country-map/src/transformProps.js
superset-frontend/plugins/legacy-plugin-chart-country-map/src/ReactCountryMap.jsx
superset-frontend/plugins/legacy-plugin-chart-country-map/src/controlPanel.ts
superset-frontend/plugins/legacy-plugin-chart-country-map/src/CountryMap.js

Explore our documentation to understand the languages and file types we support and the files we ignore.

Check out our docs on how you can make Korbit work best for you and your team.

Loving Korbit!? Share us on LinkedIn Reddit and X

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds JSON-based customization capabilities to the CountryMap plugin, allowing users to override the default linear color scheme with custom colors and percentage-based thresholds. The feature is configurable through a new "Custom Color Scale" setting in the Chart Options panel.

Key Changes

  • Added a new customColorScale TextAreaControl that accepts JSON configuration for color thresholds defined by percentages
  • Implemented color priority logic: conditional rules > custom percentage scale > linear palette > gradient fallback
  • Added helper functions for color normalization, safe number parsing, and RGBA to hex conversion

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 17 comments.

File Description
transformProps.js Parses JSON configuration from form data for custom color rules and scales
controlPanel.ts Adds new TextAreaControl for custom color scale configuration with JSON syntax
ReactCountryMap.jsx Minor formatting adjustments (whitespace)
CountryMap.js Core implementation of custom color scaling logic with multiple fallback strategies

@Facyla
Copy link
Author

Facyla commented Nov 25, 2025

Latest commit fixes an unwanted interpolation issue that would create scales between custom-defined steps (while we want ranges with the same color instead).

@Facyla
Copy link
Author

Facyla commented Nov 25, 2025

Hi,
Latest commit fixes an unwanted behaviour, which would interpolate colors between the custom defined steps.
Also removed a feature that added default colors to zones without data - which should remain white and blank.
And a small french typo.
Thank you

@rusackas
Copy link
Member

rusackas commented Dec 4, 2025

Looks like pre-commit might clear up some of the CI issues.

@Facyla
Copy link
Author

Facyla commented Dec 5, 2025

Thank you @rusackas i installed and setup pre-commit for the project, and should update the PR in the beginning of the week

@Facyla
Copy link
Author

Facyla commented Dec 10, 2025

Hello @rusackas,
I see that there are ongoing updates (67cf287) on the country map plugin with the rc4 release, and wonder what would be the best way to integrate this in the upcoming 6.0.0 release:
I am wondering whether I should keep updating this PR, or rather create on a new one on rc4 base code?
(latest seems easier than reconcialiating changes, especially after latest UI additions)

@codeant-ai-for-open-source
Copy link
Contributor

CodeAnt AI is reviewing your PR.

@codeant-ai-for-open-source codeant-ai-for-open-source bot added the size:L This PR changes 100-499 lines, ignoring generated files label Dec 10, 2025
export interface VirtualTableProps<RecordType>
extends AntTableProps<RecordType> {
export interface VirtualTableProps<
RecordType,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Inconsistent generic constraint: the VirtualTable component uses RecordType extends object in its generic, but the new VirtualTableProps declaration does not constrain RecordType; make the interface generic consistent by adding extends object to avoid allowing incompatible types and to keep type constraints aligned. [type error]

Severity Level: Minor ⚠️

Suggested change
RecordType,
RecordType extends object,
Why it matters? ⭐

Good, actionable suggestion. The component signature uses RecordType extends object
while the props interface currently allows any type. Adding extends object keeps
the API consistent and prevents accidental use with primitive record types that
would be incompatible with how the component expects row objects.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/packages/superset-ui-core/src/components/Table/VirtualTable.tsx
**Line:** 35:35
**Comment:**
	*Type Error: Inconsistent generic constraint: the `VirtualTable` component uses `RecordType extends object` in its generic, but the new `VirtualTableProps` declaration does not constrain `RecordType`; make the interface generic consistent by adding `extends object` to avoid allowing incompatible types and to keep type constraints aligned.

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.

export interface ColumnInterface<D extends object>
extends UseGlobalFiltersColumnOptions<D>,
UseSortByColumnOptions<D> {
extends UseGlobalFiltersColumnOptions<D>, UseSortByColumnOptions<D> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The ColumnInterface was extended with UseGlobalFiltersColumnOptions<D>, which is not imported in this file and will cause a TypeScript unresolved type error; remove the unreferenced type (or import the correct column-level global filter type) — minimal fix shown removes the unimported symbol and keeps the already-imported UseSortByColumnOptions. [type error]

Severity Level: Minor ⚠️

Suggested change
extends UseGlobalFiltersColumnOptions<D>, UseSortByColumnOptions<D> {
extends UseSortByColumnOptions<D> {
Why it matters? ⭐

This is a valid, actionable fix: UseGlobalFiltersColumnOptions isn't imported and likely wasn't intended here. Dropping it and keeping UseSortByColumnOptions fixes the unresolved type while preserving sort-related typings.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/plugins/plugin-chart-table/src/DataTable/types/react-table.d.ts
**Line:** 99:99
**Comment:**
	*Type Error: The `ColumnInterface` was extended with `UseGlobalFiltersColumnOptions<D>`, which is not imported in this file and will cause a TypeScript unresolved type error; remove the unreferenced type (or import the correct column-level global filter type) — minimal fix shown removes the unimported symbol and keeps the already-imported `UseSortByColumnOptions`.

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.

if (Array.isArray(scale)) return scale;
if (typeof scale === 'string') {
try {
return JSON.parse(scale);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: normalizeScale currently returns an empty array if the JSON-parsed value is an object (not an array). If the caller passes a single scale object serialized as JSON, it will be ignored. Update normalizeScale to accept a JSON string that parses to either an array or a single object by wrapping a parsed object into an array. [logic error]

Severity Level: Minor ⚠️

Suggested change
return JSON.parse(scale);
const parsed = JSON.parse(scale);
// If a single object was provided, wrap it into an array for consistent downstream handling
if (Array.isArray(parsed)) return parsed;
if (parsed && typeof parsed === 'object') return [parsed];
return [];
Why it matters? ⭐

Correct. Currently a JSON string that parses to a single object will be returned as an object and later discarded because callers expect an array (normalizedScaleWithColors uses Array.isArray). Wrapping a parsed object into an array makes downstream code behave as intended and fixes a real bug.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/plugins/legacy-plugin-chart-country-map/src/CountryMap.js
**Line:** 99:99
**Comment:**
	*Logic Error: `normalizeScale` currently returns an empty array if the JSON-parsed value is an object (not an array). If the caller passes a single scale object serialized as JSON, it will be ignored. Update `normalizeScale` to accept a JSON string that parses to either an array or a single object by wrapping a parsed object into an array.

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.

stroke: ${theme.colorSplit};
}
g.text-layer text, g.text-layer text.big-text, g.text-layer text.result-text {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The selector list g.text-layer text, g.text-layer text.big-text, g.text-layer text.result-text is redundant because g.text-layer text already matches text elements with classes; keep a single selector to avoid duplication and reduce maintenance risk. [logic error]

Severity Level: Minor ⚠️

Suggested change
g.text-layer text, g.text-layer text.big-text, g.text-layer text.result-text {
g.text-layer text {
Why it matters? ⭐

The selector g.text-layer text already matches all descendant elements, including
those with big-text and result-text classes. Consolidating to a single selector reduces
duplication and maintenance burden without changing behavior.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/plugins/legacy-plugin-chart-country-map/src/ReactCountryMap.jsx
**Line:** 78:78
**Comment:**
	*Logic Error: The selector list `g.text-layer text, g.text-layer text.big-text, g.text-layer text.result-text` is redundant because `g.text-layer text` already matches text elements with classes; keep a single selector to avoid duplication and reduce maintenance risk.

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.

Comment on lines 35 to 40
parsedColorRules = customColorRules ? JSON.parse(customColorRules) : [];
} catch (error) {
console.warn(
'Invalid JSON in customColorRules. Please check your configuration syntax:',
error && error.message ? error.message : error,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Passing non-string values (objects/arrays) to JSON.parse will throw a runtime error or a SyntaxError; ensure you only call JSON.parse on strings and otherwise accept already-parsed objects/arrays or fallback to an empty array. Also explicitly reset parsedColorRules in the catch so its value is predictable after a failed parse. [type error]

Severity Level: Minor ⚠️

Suggested change
parsedColorRules = customColorRules ? JSON.parse(customColorRules) : [];
} catch (error) {
console.warn(
'Invalid JSON in customColorRules. Please check your configuration syntax:',
error && error.message ? error.message : error,
);
if (!customColorRules) {
parsedColorRules = [];
} else if (typeof customColorRules === 'string') {
parsedColorRules = JSON.parse(customColorRules);
} else {
// already an object/array — accept as-is
parsedColorRules = customColorRules;
}
} catch (error) {
console.warn(
'Invalid JSON in customColorRules. Please check your configuration syntax:',
error && error.message ? error.message : error,
);
parsedColorRules = [];
Why it matters? ⭐

The current code unconditionally calls JSON.parse when a value exists — if the caller already passes an object/array, JSON.parse will throw. Guarding on typeof and accepting already-parsed objects avoids unnecessary runtime errors and makes the behavior predictable. Resetting to [] in the catch also makes the post-error state explicit (though parsedColorRules is initialized to [] already).

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/plugins/legacy-plugin-chart-country-map/src/transformProps.js
**Line:** 35:40
**Comment:**
	*Type Error: Passing non-string values (objects/arrays) to JSON.parse will throw a runtime error or a SyntaxError; ensure you only call JSON.parse on strings and otherwise accept already-parsed objects/arrays or fallback to an empty array. Also explicitly reset `parsedColorRules` in the catch so its value is predictable after a failed parse.

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.

Comment on lines 56 to 64
setShowTooltip(
Boolean(
!isTransitioning &&
(!isActive ||
(chartNameRef.current &&
chartNameRef.current.scrollWidth >
chartNameRef.current.clientWidth)),
(!isActive ||
(chartNameRef.current &&
chartNameRef.current.scrollWidth >
chartNameRef.current.clientWidth)),
),
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The boolean calculation is repeated and uses Boolean(...) with a complex inline expression; factor out the measured element once, use optional chaining/explicit check, and set a clear boolean to avoid subtle coercion and repeated property access. [logic error]

Severity Level: Minor ⚠️

Suggested change
setShowTooltip(
Boolean(
!isTransitioning &&
(!isActive ||
(chartNameRef.current &&
chartNameRef.current.scrollWidth >
chartNameRef.current.clientWidth)),
(!isActive ||
(chartNameRef.current &&
chartNameRef.current.scrollWidth >
chartNameRef.current.clientWidth)),
),
);
{
const el = chartNameRef.current;
const isOverflowing = el ? el.scrollWidth > el.clientWidth : false;
setShowTooltip(!isTransitioning && (!isActive || isOverflowing));
}
Why it matters? ⭐

Factoring out chartNameRef.current into a local variable and using an explicit boolean improves readability and avoids repeated property access; it doesn't change semantics and is a safe, beneficial refactor.

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/src/explore/components/controls/VizTypeControl/VizTile.tsx
**Line:** 56:64
**Comment:**
	*Logic Error: The boolean calculation is repeated and uses `Boolean(...)` with a complex inline expression; factor out the measured element once, use optional chaining/explicit check, and set a clear boolean to avoid subtle coercion and repeated property access.

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.

@codeant-ai-for-open-source
Copy link
Contributor

CodeAnt AI finished reviewing your PR.

@codeant-ai-for-open-source
Copy link
Contributor

💡 Enhance Your PR Reviews

We noticed that 3 feature(s) are not configured for this repository. Enabling these features can help improve your code quality and workflow:

🚦 Quality Gates

Status: Quality Gates are not enabled at the organization level
Learn more about Quality Gates

🎫 Jira Ticket Compliance

Status: Jira credentials file not found. Please configure Jira integration in your settings
Learn more about Jira Integration

⚙️ Custom Rules

Status: No custom rules configured. Add rules via organization settings or .codeant/review.json in your repository
Learn more about Custom Rules


Want to enable these features? Contact your organization admin or check our documentation for setup instructions.

@Facyla Facyla marked this pull request as draft December 10, 2025 14:15
@Facyla
Copy link
Author

Facyla commented Dec 10, 2025

Hi,
I've converted this PR to draft to handle master changes merge and produce a more readable PR.

@Facyla Facyla force-pushed the feat/custom-color-scales-for-countrymap-plugin branch from 28a6282 to 73fb398 Compare December 16, 2025 14:08
@github-actions github-actions bot added i18n Namespace | Anything related to localization risk:db-migration PRs that require a DB migration i18n:russian Translation related to Russian language labels Dec 16, 2025
@github-actions github-actions bot added api Related to the REST API doc Namespace | Anything related to documentation embedded dependencies:npm github_actions Pull requests that update GitHub Actions code labels Dec 16, 2025
@Facyla Facyla closed this Dec 16, 2025
@Facyla Facyla force-pushed the feat/custom-color-scales-for-countrymap-plugin branch from 73fb398 to 6f8052b Compare December 16, 2025 14:12
@Facyla
Copy link
Author

Facyla commented Dec 18, 2025

Hi,
The changes have been reintegrated for a cleaner integration based on rc4 master, and proposed in a new PR: #36732

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Related to the REST API dependencies:npm doc Namespace | Anything related to documentation embedded github_actions Pull requests that update GitHub Actions code i18n:russian Translation related to Russian language i18n Namespace | Anything related to localization packages plugins risk:db-migration PRs that require a DB migration size:L This PR changes 100-499 lines, ignoring generated files size/XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants