Skip to content

add placeholder to keep custom palette ID's consistent#5537

Merged
DedeHai merged 1 commit intowled:mainfrom
DedeHai:custompal_placeholder
Apr 25, 2026
Merged

add placeholder to keep custom palette ID's consistent#5537
DedeHai merged 1 commit intowled:mainfrom
DedeHai:custompal_placeholder

Conversation

@DedeHai
Copy link
Copy Markdown
Collaborator

@DedeHai DedeHai commented Apr 25, 2026

fix for #5533

when deleting custom palettes, they now keep their ID, leaving previously created presets unchanged.
The "dummy" palettes inserted are gray, so if a custom palette that was used in a preset is deleted, it will end up as gray to indicate an empty palette. Also the "dummy" palettes are omitted in the custom palette list.

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved custom palette handling to properly manage missing palette files while maintaining correct palette indices and preventing placeholder entries from displaying in the palette list.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 25, 2026

Walkthrough

The PR modifies custom palette loading to insert gray placeholder entries for missing palette files, ensuring proper palette index alignment. The UI filters out these placeholders during rendering, while JSON documentation clarifies that the palette count includes them.

Changes

Cohort / File(s) Summary
Custom Palette Index Management
wled00/colors.cpp
Modified loadCustomPalettes() to insert gray placeholder palettes into customPalettes for each detected gap, maintaining correct palette indices.
Custom Palette Display
wled00/data/index.js
Added conditional logic to skip rendering palette entries that match the all-gray placeholder pattern (RGB 128 for all 16 colors).
Documentation Update
wled00/json.cpp
Clarified cpalcount field documentation to indicate the count includes gray placeholder entries alongside actual custom palettes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • netmindz
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding placeholder palettes to maintain consistent custom palette IDs when files are deleted.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
wled00/colors.cpp (1)

271-307: ⚠️ Potential issue | 🟡 Minor

ID-preservation gap when a palette file exists but fails to parse.

Placeholders are only inserted in the file-exists branch before attempting to load. If WLED_FS.exists(fileName) returns true but readObjectFromFile() fails or the JSON has an invalid format (pal.isNull() || pal.size()<=3), emptyPaletteGap has already been reset and no entry is pushed for this slot — so any later palettes loaded in the same loadCustomPalettes() call will shift down by one and lose the ID stability this PR is meant to provide.

If preserving IDs across all file-state failure modes is desired, treat parse/validation failures the same as a missing file by inserting a gray placeholder when the load doesn't succeed.

🔧 One possible fix
       DEBUGFX_PRINTF_P(PSTR("Reading palette from %s\n"), fileName);
+      bool palLoaded = false;
       if (readObjectFromFile(fileName, nullptr, &pDoc)) {
         JsonArray pal = pDoc[F("palette")];
         if (!pal.isNull() && pal.size()>3) { // not an empty palette (at least 2 entries)
           ...
           customPalettes.push_back(targetPalette.loadDynamicGradientPalette(tcp));
+          palLoaded = true;
         } else {
           DEBUGFX_PRINTLN(F("Wrong palette format."));
         }
       }
+      if (!palLoaded) customPalettes.push_back(CRGBPalette16(CRGB(128, 128, 128))); // keep ID stable
     } else {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/colors.cpp` around lines 271 - 307, The issue: placeholders are added
immediately when WLED_FS.exists(fileName) is true but emptyPaletteGap is cleared
before parsing, so parse/read failures cause missing placeholders and ID shift.
Fix by treating parse/validation failures like a missing file: if
readObjectFromFile(...) returns false or the palette JSON is invalid
(pal.isNull() || pal.size()<=3) then push the same gray-placeholder(s) into
customPalettes (using the same CRGBPalette16(CRGB(128,128,128)) logic) and do
not reset emptyPaletteGap unless a palette was successfully loaded; adjust logic
around WLED_FS.exists(fileName), readObjectFromFile, emptyPaletteGap,
customPalettes, and the targetPalette.loadDynamicGradientPalette/tcp path to
ensure placeholders are added when load fails.
wled00/data/index.js (1)

995-1007: ⚠️ Potential issue | 🟡 Minor

Brittle placeholder detection via a hard-coded sentinel color.

Two concerns with detecting placeholders by "16 entries with RGB all equal 128":

  1. Cross-file magic constant. The sentinel (128,128,128) is also produced in wled00/colors.cpp (CRGBPalette16(CRGB(128, 128, 128))). If anyone tweaks the placeholder color there, this filter silently breaks. Consider centralizing the constant (e.g. a shared comment + named constant in C++) or using a more explicit sentinel that is unlikely to collide with user palettes.
  2. False positive on user palettes. A user-authored custom palette that happens to be 16 mid-gray stops would be silently hidden from the palette list. Niche, but valid.

Optional mitigation: also require the cpalcount-vs-file-existence relationship (i.e. only filter slots whose palette<n>.json was reported missing), or pick a sentinel pattern that varies per entry to make accidental collisions effectively impossible.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/data/index.js` around lines 995 - 1007, The current placeholder
detection in the loop using palettesData[255-j] and checking for 16 entries of
RGB(128,128,128) is brittle and can hide legitimate user palettes; update the
logic in the code that builds the list (the loop referencing li.cpalcount,
palettesData, generateListItemHtml and genPalPrevCss) to use a stronger
sentinel: either (A) detect placeholders by consulting the actual palette file
existence/manifest reported by the server (e.g., only treat an entry as a
placeholder if the corresponding palette<n>.json was reported missing) or (B)
require an additional explicit marker/flag in palettesData (e.g., a boolean like
isPlaceholder) instead of relying on the RGB magic value; implement one of these
approaches and remove the hard-coded RGB(128,128,128) check so user-created
16-step mid-gray palettes are not accidentally filtered out.
🧹 Nitpick comments (1)
wled00/colors.cpp (1)

272-275: Optional: use vector::insert for the bulk placeholder push.

Minor readability/efficiency: a single insert with a count avoids per-element capacity checks.

♻️ Suggested change
-      // add gray placeholders to preserve palette IDs for subsequent slots (is omitted in UI but shown in cpal.htm)
-      for (unsigned g = 0; g < emptyPaletteGap; g++)
-        customPalettes.push_back(CRGBPalette16(CRGB(128, 128, 128)));
-      emptyPaletteGap = 0;  // reset gap counter if file exists
+      // add gray placeholders to preserve palette IDs for subsequent slots (omitted in UI, shown in cpal.htm)
+      customPalettes.insert(customPalettes.end(), emptyPaletteGap, CRGBPalette16(CRGB(128, 128, 128)));
+      emptyPaletteGap = 0;  // reset gap counter if file exists
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/colors.cpp` around lines 272 - 275, Replace the per-element loop that
calls customPalettes.push_back(...) for emptyPaletteGap with a single bulk
insert: construct one CRGBPalette16(CRGB(128,128,128)) and call
customPalettes.insert to append emptyPaletteGap copies, then reset
emptyPaletteGap; update references to the loop around customPalettes,
emptyPaletteGap, CRGBPalette16 and CRGB to locate the change. This reduces
repeated capacity checks and improves readability while preserving the exact
placeholder value and behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@wled00/colors.cpp`:
- Around line 271-307: The issue: placeholders are added immediately when
WLED_FS.exists(fileName) is true but emptyPaletteGap is cleared before parsing,
so parse/read failures cause missing placeholders and ID shift. Fix by treating
parse/validation failures like a missing file: if readObjectFromFile(...)
returns false or the palette JSON is invalid (pal.isNull() || pal.size()<=3)
then push the same gray-placeholder(s) into customPalettes (using the same
CRGBPalette16(CRGB(128,128,128)) logic) and do not reset emptyPaletteGap unless
a palette was successfully loaded; adjust logic around WLED_FS.exists(fileName),
readObjectFromFile, emptyPaletteGap, customPalettes, and the
targetPalette.loadDynamicGradientPalette/tcp path to ensure placeholders are
added when load fails.

In `@wled00/data/index.js`:
- Around line 995-1007: The current placeholder detection in the loop using
palettesData[255-j] and checking for 16 entries of RGB(128,128,128) is brittle
and can hide legitimate user palettes; update the logic in the code that builds
the list (the loop referencing li.cpalcount, palettesData, generateListItemHtml
and genPalPrevCss) to use a stronger sentinel: either (A) detect placeholders by
consulting the actual palette file existence/manifest reported by the server
(e.g., only treat an entry as a placeholder if the corresponding palette<n>.json
was reported missing) or (B) require an additional explicit marker/flag in
palettesData (e.g., a boolean like isPlaceholder) instead of relying on the RGB
magic value; implement one of these approaches and remove the hard-coded
RGB(128,128,128) check so user-created 16-step mid-gray palettes are not
accidentally filtered out.

---

Nitpick comments:
In `@wled00/colors.cpp`:
- Around line 272-275: Replace the per-element loop that calls
customPalettes.push_back(...) for emptyPaletteGap with a single bulk insert:
construct one CRGBPalette16(CRGB(128,128,128)) and call customPalettes.insert to
append emptyPaletteGap copies, then reset emptyPaletteGap; update references to
the loop around customPalettes, emptyPaletteGap, CRGBPalette16 and CRGB to
locate the change. This reduces repeated capacity checks and improves
readability while preserving the exact placeholder value and behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c39eb8bb-bd77-43da-8379-b80fa3b683aa

📥 Commits

Reviewing files that changed from the base of the PR and between 1bc71f2 and d5ae146.

📒 Files selected for processing (3)
  • wled00/colors.cpp
  • wled00/data/index.js
  • wled00/json.cpp

@DedeHai DedeHai merged commit f4f4978 into wled:main Apr 25, 2026
25 checks passed
@DedeHai DedeHai deleted the custompal_placeholder branch April 25, 2026 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant