Skip to content

Commit 5bbe225

Browse files
hangtime79claude
andcommitted
docs(v0.10.1): Add release notes, post-mortem, and gotchas
- Release notes for v0.10.1 custom palettes feature - Post-mortem with API discovery learnings - Updated CHANGELOG - Added gotchas: webapp PRESET resolution, preset.config property - CLI docs template with PRESET resolution examples 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ba0b403 commit 5bbe225

5 files changed

Lines changed: 331 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.10.1] - 2025-12-29
11+
12+
### Added
13+
- Custom color palettes via admin-defined presets (#79)
14+
- New "Custom (Preset)" option in Color Palette dropdown
15+
- Admins create palettes in plugin settings with 6-12 hex colors
16+
- WCAG-compliant auto text contrast (dark text on light bars, white on dark)
17+
- Dynamic CSS injection for custom bar-custom-N classes
18+
19+
### Fixed
20+
- PRESET parameter resolution in webapps (requires manual API resolution)
21+
1022
## [0.10.0] - 2025-12-29
1123

1224
### Added

CLAUDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ DSS Dataset → backend.py → TaskTransformer → dependency_validator → JSON
6060
- **Frappe Gantt popup positioning** — Library treats popup coords as anchors and re-centres vertically after render. Don't fight it by modifying `opts.x/y` before calling `show_popup()`. Instead: call `originalShowPopup(opts)` first, then correct position in `requestAnimationFrame()` by directly setting `popup.style.left/top`. Disable transition temporarily to prevent visual jump.
6161
- **Webapp icons require inline SVG** — FontAwesome classes (`fas fa-*`) don't work in Dataiku webapp context. Use inline SVG with `fill="currentColor"` for theme compatibility. FontAwesome is only available for `plugin.json` icon field.
6262
- **Frappe Gantt single popup** — Library has single `$popup_wrapper`. For multiple simultaneous tooltips, clone popup content into independent DOM elements in a separate container.
63+
- **Webapp PRESET params are raw references** — Unlike recipes/connectors where Dataiku auto-resolves PRESET params to dicts, webapps receive `{"mode": "PRESET", "name": "PRESET_3"}` and must manually resolve via API: `client.get_plugin(id).get_settings().get_parameter_set(id).get_preset(name).config`
64+
- **DSSPluginPreset.config is a property** — Use `preset.config`, NOT `preset.get_config()`. The config attribute is a property that returns a dict, not a method.
6365

6466
---
6567

plan/cli-docs-template-update.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,109 @@ upperTexts.forEach(text => {
149149
- To be integrated into: `cli-docs/reference/frappe-gantt.md` → "Header Manipulation" section
150150

151151
---
152+
153+
### Context
154+
Using PRESET parameter type in a Dataiku webapp to reference admin-defined parameter sets (like custom color palettes).
155+
156+
### The Problem
157+
In recipes and connectors, Dataiku automatically resolves PRESET parameters to their dict values. However, in webapps, you receive a **raw reference** like `{"mode": "PRESET", "name": "PRESET_3"}` instead of the resolved values. Attempting to access the preset's properties directly fails.
158+
159+
```python
160+
# What you expect (works in recipes)
161+
preset_config = config.get('customPalettePreset')
162+
colors = preset_config.get('colors') # Works!
163+
164+
# What you actually get in webapps
165+
preset_config = config.get('customPalettePreset')
166+
# preset_config = {"mode": "PRESET", "name": "PRESET_3"}
167+
colors = preset_config.get('colors') # Returns None! No 'colors' key
168+
```
169+
170+
### The Solution
171+
Manually resolve the PRESET reference using the Dataiku API. Check the `mode` key: if `"INLINE"`, values are embedded; if `"PRESET"`, you must fetch via API.
172+
173+
### Implementation
174+
175+
```python
176+
def resolve_preset(preset_ref, parameter_set_id):
177+
"""Resolve a webapp PRESET parameter to its actual values."""
178+
if not preset_ref:
179+
return None
180+
181+
mode = preset_ref.get('mode')
182+
183+
if mode == 'INLINE':
184+
# Values embedded directly
185+
return {k: v for k, v in preset_ref.items() if k != 'mode'}
186+
187+
elif mode == 'PRESET':
188+
# Must resolve via API
189+
preset_name = preset_ref.get('name')
190+
if not preset_name:
191+
return None
192+
193+
import dataiku
194+
client = dataiku.api_client()
195+
plugin = client.get_plugin("your-plugin-id")
196+
settings = plugin.get_settings()
197+
parameter_set = settings.get_parameter_set(parameter_set_id)
198+
preset = parameter_set.get_preset(preset_name)
199+
200+
if preset:
201+
# IMPORTANT: config is a PROPERTY, not a method!
202+
return preset.config # NOT preset.get_config()
203+
return None
204+
205+
else:
206+
# Direct values (no mode key)
207+
return preset_ref
208+
```
209+
210+
### Verification
211+
1. Create a parameter set with a preset in Dataiku plugin settings
212+
2. In your webapp, select the preset via the PRESET param type
213+
3. Add logging to see the raw config: `{"mode": "PRESET", "name": "..."}`
214+
4. Verify resolve_preset() returns the actual preset values
215+
216+
### Related
217+
- To be integrated into: `cli-docs/reference/parameters.md` → "PRESET Type" section
218+
- Related gotcha: DSSPluginPreset.config is a property, not a method
219+
220+
---
221+
222+
### Context
223+
Accessing preset configuration values after resolving a PRESET parameter via the Dataiku API.
224+
225+
### The Problem
226+
After calling `parameter_set.get_preset(name)`, you get a `DSSPluginPreset` object. Attempting to call `preset.get_config()` fails with `AttributeError: 'DSSPluginPreset' object has no attribute 'get_config'`.
227+
228+
```python
229+
preset = parameter_set.get_preset("PRESET_3")
230+
values = preset.get_config() # AttributeError!
231+
```
232+
233+
### The Solution
234+
`config` is a **property**, not a method. Access it directly without parentheses.
235+
236+
### Implementation
237+
238+
```python
239+
# BAD - get_config() doesn't exist
240+
preset = parameter_set.get_preset("PRESET_3")
241+
values = preset.get_config() # AttributeError
242+
243+
# GOOD - config is a property
244+
preset = parameter_set.get_preset("PRESET_3")
245+
values = preset.config # Returns dict of preset values
246+
```
247+
248+
### Verification
249+
1. In Python console: `type(preset.config)` should return `<class 'dict'>`
250+
2. `preset.config.keys()` should show your preset's parameter names
251+
3. No AttributeError when accessing `.config`
252+
253+
### Related
254+
- To be integrated into: `cli-docs/reference/parameters.md` → "Accessing Preset Values" section
255+
- Dataiku API docs sparse on this detail
256+
257+
---
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Post-Mortem: v0.10.1
2+
3+
**Branch:** `feature/v0.10.1-custom-palettes`
4+
**Type:** Feature
5+
**Duration:** 1 day (Started: 2025-12-29, Completed: 2025-12-29)
6+
**Outcome:** ✅ Success
7+
8+
---
9+
10+
## Summary
11+
12+
Implemented admin-defined custom color palettes using Dataiku's parameter set (PRESET) mechanism. The feature required significant debugging to understand how PRESET parameters work differently in webapps vs recipes/connectors.
13+
14+
---
15+
16+
## Scope
17+
18+
### Planned
19+
- [x] Parameter set for custom palettes
20+
- [x] Custom option in color palette dropdown
21+
- [x] PRESET selector with visibility condition
22+
- [x] Backend preset resolution
23+
- [x] Hex color validation
24+
- [x] Dynamic CSS injection with text contrast
25+
26+
### Delivered
27+
All planned items delivered.
28+
29+
### Deferred Items
30+
None
31+
32+
---
33+
34+
## Commit Analysis
35+
36+
| Metric | Value | Assessment |
37+
|--------|-------|------------|
38+
| Total commits | 5 | |
39+
| Feature commits | 1 | |
40+
| Fix/debug commits | 4 | |
41+
| Reverts | 0 | |
42+
| Churn ratio | 80% | 🔴 High (API discovery) |
43+
44+
**Churn explanation:** High churn ratio due to iterative API discovery. The Dataiku PRESET mechanism works differently in webapps (raw references) vs recipes (auto-resolved). Required 4 iterations to find correct API pattern:
45+
46+
1. Initial implementation assumed auto-resolution (wrong)
47+
2. Added debug logging to discover raw reference format
48+
3. First API attempt with wrong method names
49+
4. Final fix: `preset.config` is a property, not `preset.get_config()`
50+
51+
---
52+
53+
## What Went Well
54+
55+
- Clean architecture: CSS injection with luminance-based text contrast
56+
- Parameter set structure follows Dataiku patterns
57+
- Hex validation handles 3-digit and 6-digit formats
58+
- Graceful fallback to classic palette on errors
59+
60+
---
61+
62+
## What Didn't Go Well
63+
64+
- Assumed PRESET params auto-resolve in webapps (they don't)
65+
- Searched for wrong API methods initially
66+
- `config` is a property vs `get_config()` method distinction not obvious
67+
68+
---
69+
70+
## Blockers Encountered
71+
72+
| Blocker | Impact | Resolution | Time Lost |
73+
|---------|--------|------------|-----------|
74+
| PRESET not resolving | Colors defaulted to classic | Added resolve_preset() | 1 hour |
75+
| Wrong API method | AttributeError | Found correct API path | 30 min |
76+
| Property vs method | AttributeError | Changed to `preset.config` | 30 min |
77+
78+
---
79+
80+
## Technical Discoveries
81+
82+
### Platform Behavior
83+
1. **Webapps receive raw PRESET references** - Unlike recipes where Dataiku auto-resolves PRESET params to dicts, webapps receive `{"mode": "PRESET", "name": "PRESET_3"}` and must manually resolve via API
84+
85+
2. **DSSPluginPreset.config is a property** - Use `preset.config`, not `preset.get_config()`. The API documentation is sparse on this detail.
86+
87+
3. **Preset resolution API path**:
88+
```python
89+
client = dataiku.api_client()
90+
plugin = client.get_plugin("plugin-id")
91+
settings = plugin.get_settings()
92+
parameter_set = settings.get_parameter_set("param-set-id")
93+
preset = parameter_set.get_preset("PRESET_NAME")
94+
values = preset.config # Property, not method!
95+
```
96+
97+
### Library Behavior
98+
- WCAG luminance formula works well for auto text contrast
99+
- CSS injection timing not critical - can inject before render
100+
101+
---
102+
103+
## CLI Docs Candidates
104+
105+
Items added to CLAUDE.md gotchas:
106+
107+
1. **Webapp PRESET params are raw references** - Must resolve via API, not auto-resolved like in recipes
108+
2. **DSSPluginPreset.config is a property** - Not a method, don't use get_config()
109+
110+
---
111+
112+
## Recommendations
113+
114+
### For Next Release
115+
- Consider adding color preview in parameter set UI (not possible with current TEXTAREA)
116+
117+
### Process Improvements
118+
- Check Dataiku API examples before assuming behavior matches recipes
119+
120+
### Technical Debt
121+
- Unit test collection errors need investigation (ScenarioConfiguration)
122+
123+
---
124+
125+
## Lessons Learned
126+
127+
1. Dataiku has different behavior for PRESET params across component types (webapp vs recipe)
128+
2. Always check if Python attributes are properties vs methods
129+
3. Debug logging early is valuable for understanding framework behavior
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Release Notes: v0.10.1
2+
3+
**Release Date:** 2025-12-29
4+
**Type:** Feature
5+
**Branch:** `feature/v0.10.1-custom-palettes`
6+
7+
---
8+
9+
## Summary
10+
11+
Adds admin-defined custom color palettes via Dataiku's parameter set (PRESET) mechanism. Administrators can create global color palette presets in plugin settings, and users can select these custom palettes from the Color Palette dropdown when configuring Gantt chart webapps.
12+
13+
---
14+
15+
## Changes
16+
17+
### Added
18+
- Custom color palette support via parameter sets (#79)
19+
- New "Custom (Preset)" option in Color Palette dropdown
20+
- PRESET selector appears when custom is selected
21+
- Admins create palettes in plugin settings with 6-12 hex colors
22+
- Dynamic CSS injection with WCAG-compliant text contrast
23+
- Automatic light/dark text based on background luminance
24+
25+
### Fixed
26+
- PRESET parameter resolution in webapps
27+
- Webapps receive raw references, must resolve via API (unlike recipes)
28+
- Implemented resolve_preset() function for API-based resolution
29+
30+
---
31+
32+
## Files Modified
33+
34+
| File | Change Type | Description |
35+
|------|-------------|-------------|
36+
| `parameter-sets/custom-palette/parameter-set.json` | Added | Custom palette preset structure |
37+
| `webapps/gantt-chart/webapp.json` | Modified | Added "custom" option + PRESET param |
38+
| `webapps/gantt-chart/backend.py` | Modified | Preset resolution + custom color handling |
39+
| `python-lib/ganttchart/task_transformer.py` | Modified | Added custom_colors to config |
40+
| `python-lib/ganttchart/color_mapper.py` | Modified | Hex validation + custom palette support |
41+
| `webapps/gantt-chart/app.js` | Modified | Luminance calc + CSS injection |
42+
| `plugin.json` | Modified | Version bump to 0.10.1 |
43+
| `plan/specs/feature-v0.10.1-spec.md` | Added | Feature specification |
44+
45+
---
46+
47+
## Testing
48+
49+
- **Unit Tests:** Pre-existing collection errors (unrelated to this feature)
50+
- **Manual Verification:**
51+
- [x] Built-in palettes still work (classic, pastel, dark, dataiku)
52+
- [x] "Custom (Preset)" option appears in dropdown
53+
- [x] PRESET selector appears when "Custom" selected
54+
- [x] Admin can create custom palette presets
55+
- [x] Custom colors apply correctly to task bars
56+
- [x] Text contrast is readable (auto light/dark)
57+
- [x] Switching palettes removes/replaces CSS correctly
58+
59+
---
60+
61+
## Breaking Changes
62+
63+
None
64+
65+
---
66+
67+
## Known Issues
68+
69+
- Unit test collection errors (pre-existing ScenarioConfiguration issue, unrelated to this feature)
70+
71+
---
72+
73+
## Dependencies
74+
75+
None
76+
77+
---
78+
79+
## Related Documents
80+
81+
- Spec: `plan/specs/feature-v0.10.1-spec.md`
82+
- Post-mortem: `plan/post-mortems/v0.10.1-post-mortem.md`

0 commit comments

Comments
 (0)