Skip to content

feat: dynamic icons for file groups (#31)#60

Open
z8dn wants to merge 11 commits into
mainfrom
feat/dynamic-icons-issue-31
Open

feat: dynamic icons for file groups (#31)#60
z8dn wants to merge 11 commits into
mainfrom
feat/dynamic-icons-issue-31

Conversation

@z8dn
Copy link
Copy Markdown
Owner

@z8dn z8dn commented May 8, 2026

Summary

Closes #31. Lets users override the icon used for a project file group from a curated set of IntelliJ `AllIcons` entries, with the existing auto-detection as the fallback.

  • New `Icon: [preview] [Choose…] [Reset to auto]` row in the Edit File Group dialog
  • New modal `GroupIconPickerDialog` showing a 6×8-ish grid of 37 curated icons
  • Settings table gets a small leading icon column showing the resolved icon for each group
  • Persistent `iconKey: String?` on `ProjectFileGroup`; `null` preserves auto-detect, so existing groups upgrade with no migration

Architecture

  • `utils/GroupIconCatalog.kt` — registry of `(key, displayName, AllIcons icon)` triples; built defensively via `runCatching` so a missing icon on a future SDK silently filters out
  • `utils/GroupIconResolver.kt` — pure resolver: `catalog.find(key)?.icon ?: autoDetect()`
  • `nodes/ProjectFileGroupNode.kt` — calls the resolver; auto-detect logic stays in the node because it depends on `FileTypeManager`
  • `settings/GroupIconPickerDialog.kt` — modal `DialogWrapper` with horizontal-wrap `JBList`
  • `settings/ProjectFileGroupDialog.kt` — adds the icon row and wires it to the picker
  • `settings/AndroidViewSettingsConfigurable.kt` — adds icon column; also fixes `apply`/`reset` to round-trip `iconKey`

Spec: `docs/superpowers/specs/2026-05-07-dynamic-icons-design.md`
Plan: `docs/superpowers/plans/2026-05-08-dynamic-icons.md`

Tests

`./gradlew check` is green. New unit tests:

  • `GroupIconCatalogTest` — 5 cases covering `find(null)`, unknown keys, non-empty entries, every entry findable by its key, non-blank display names
  • `GroupIconResolverTest` — 3 cases covering null fallback, unknown-key fallback, known-key wins

UI/Swing tests are intentionally omitted — there is no Swing test infrastructure in the repo and #31 doesn't justify setting that up.

Test plan

  • `./gradlew check` — already green locally
  • `./gradlew runIde` smoke test:
    • Tools → Customize Android Tree View… → Add a file group with patterns `*.md`. Icon row shows "(Auto-detected)" with a Markdown icon preview.
    • Click Choose…, pick "Settings", click OK. Preview updates to gear + "Settings".
    • Save settings. Project tree group renders with the gear icon. Settings table icon column shows it for that row.
    • Edit, click Reset to auto, save. Tree falls back to the auto-detected Markdown icon.
    • Restart sandbox IDE; chosen icon persists.

Out of scope

  • Custom uploaded SVG/PNG icons (file picker)
  • Searchable browsing of all `AllIcons.*`
  • Search scope icons (`ProjectFileGroupScope` doesn't surface icons)
  • Drag-to-reorder, favorites, or recently-used in the picker

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Select custom icons for project file groups from a curated icon set in the Edit File Group dialog.
    • Icon preview, choose/reset controls, and an icon column in the file groups settings table.
    • Falls back to existing auto-detection when no custom icon is set.
  • Documentation

    • Added design and implementation plan docs for dynamic/group icons and updated changelog.
  • Tests

    • Added unit tests covering the icon catalog and resolver behavior.

z8dn and others added 10 commits May 7, 2026 23:48
Captures the brainstorming outcome: AllIcons-only, curated 40-icon grid,
optional override with auto-detect fallback, compact picker row in the
Edit File Group dialog.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: 0c7c7943d240
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the new persistent field that will hold a user-selected icon override
key. Default null preserves existing behavior (auto-detection).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
37 entries spanning Nodes, General, Actions, FileTypes, Toolwindows, Vcs,
and Debugger groups. Each entry built defensively via runCatching so a
missing AllIcons member on a future SDK silently filters out instead of
breaking class init.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extracts the override-or-fallback decision into a pure function that's
trivially testable without IntelliJ test fixtures. The auto-detect logic
stays inside ProjectFileGroupNode because it depends on FileTypeManager.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Modal DialogWrapper presenting GroupIconCatalog.entries as a horizontally-
wrapping JBList with 48x48 cells. Pre-selects the entry matching the
caller's initialKey, or the first available entry. Returns the selected
key on OK; Cancel returns null.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New 'Icon: [preview] [Choose…] [Reset to auto]' row between the group
name field and the patterns section. The Reset button is disabled when
no override is active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a leading 28-px icon column to the settings table that renders the
custom icon (or auto-detected fallback) for each file group. Also fixes
apply()/reset() to preserve iconKey when round-tripping ProjectFileGroup
through settings — the previous two-arg constructor calls silently
dropped the new field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 02de7f98-8c14-4841-ab9a-2de639bdb1c9

📥 Commits

Reviewing files that changed from the base of the PR and between 55617d3 and d69532b.

📒 Files selected for processing (4)
  • src/main/kotlin/com/z8dn/plugins/a2pt/nodes/ProjectFileGroupNode.kt
  • src/main/kotlin/com/z8dn/plugins/a2pt/settings/AndroidViewSettingsConfigurable.kt
  • src/main/kotlin/com/z8dn/plugins/a2pt/settings/ProjectFileGroupDialog.kt
  • src/main/kotlin/com/z8dn/plugins/a2pt/utils/GroupIconResolver.kt

📝 Walkthrough

Walkthrough

Adds optional persisted per-group iconKey, a curated GroupIconCatalog, GroupIconResolver (catalog-first, auto-detect fallback), UI for picking/resetting icons and preview, settings-table icon column, node wiring, unit tests, docs, and a changelog entry.

Changes

Dynamic Icons for File Groups

Layer / File(s) Summary
Data Model
src/main/kotlin/.../settings/AndroidViewSettings.kt
ProjectFileGroup gains optional iconKey: String? = null for persisted selections.
Icon Catalog & Entries
src/main/kotlin/.../utils/GroupIconCatalog.kt
GroupIconEntry and GroupIconCatalog lazily build a curated list of key→(displayName, Icon) entries with defensive resolution and find(key).
Icon Resolver
src/main/kotlin/.../utils/GroupIconResolver.kt
GroupIconResolver.resolve(iconKey, autoDetect) prefers catalog entry.icon; resolve(iconKey, patterns) uses autoDetectFromPatterns to fallback to file-type or folder icons.
Node Icon Wiring
src/main/kotlin/.../nodes/ProjectFileGroupNode.kt
Node update() uses GroupIconResolver.resolve(fileGroup.iconKey, fileGroup.patterns); prior inline pattern-based detection removed.
Icon Picker Dialog
src/main/kotlin/.../settings/GroupIconPickerDialog.kt
New GroupIconPickerDialog shows catalog entries in a scrollable list with icons/tooltips, supports preselection by initialKey, and exposes getSelectedKey().
File Group Dialog UI
src/main/kotlin/.../settings/ProjectFileGroupDialog.kt
Adds icon row (preview label, choose/reset buttons), currentIconKey state, refreshIconRow() using catalog or resolver auto-detect, and returns ProjectFileGroup with iconKey.
Settings Table Integration
src/main/kotlin/.../settings/AndroidViewSettingsConfigurable.kt
Table model expanded to 3 columns (icon, group name, patterns); icon column fixed-width; resolveIcon delegates to GroupIconResolver; apply()/reset() persist/restore iconKey.
i18n Bundle
src/main/resources/messages/AndroidViewBundle.properties
New keys for icon field label, choose/reset action labels, auto-detected indicator, and picker dialog title.
Catalog & Resolver Tests
src/test/kotlin/.../utils/GroupIconCatalogTest.kt, GroupIconResolverTest.kt
Tests: catalog lookup returns null for null/unknown keys, entries non-empty, round-trip findability, displayName non-blank, and resolver fallback/known-key identity.
Design & Implementation Docs
docs/superpowers/specs/2026-05-07-dynamic-icons-design.md, docs/superpowers/plans/2026-05-08-dynamic-icons.md
Specification and task-based implementation plan with file map, TDD steps, verification checklist, risks/mitigations, and out-of-scope items.
Changelog
CHANGELOG.md
Added [Unreleased] → Added entry describing custom icon support with auto-detection fallback (issue #31).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through code with careful paws,
I snapped a key from a curated cause,
If keys are missing, I sniff patterns instead,
Fallback to folders keeps the tree well led,
Now groups wear icons like a dapper little hat.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.23% 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 PR title 'feat: dynamic icons for file groups (#31)' clearly and concisely summarizes the main feature addition of enabling users to customize icons for file groups from a curated set, which aligns with the changeset.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #31: enabling icon customization via a curated IntelliJ icon set, providing UI in the Edit File Group dialog for selection, and improving visual navigation through custom icons.
Out of Scope Changes check ✅ Passed All changes align with the scope defined in issue #31; no unrelated modifications are present. The PR includes necessary documentation, tests, UI components, and model changes solely for dynamic icon support.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/dynamic-icons-issue-31

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Qodana for JVM

37 new problems were found

Inspection name Severity Problems
Lambda argument inside parentheses ◽️ Notice 37

☁️ View the detailed Qodana report

Contact Qodana team

Contact us at qodana-support@jetbrains.com

Copy link
Copy Markdown

@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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/kotlin/com/z8dn/plugins/a2pt/settings/AndroidViewSettingsConfigurable.kt`:
- Around line 195-210: The settings class duplicates fallback icon detection
from ProjectFileGroupNode.autoDetectIcon(), causing drift; extract the logic
into a shared utility (e.g., GroupIconResolver with a function like
resolveFallbackIcon(group: ProjectFileGroup): Icon) and replace the local logic
in AndroidViewSettingsConfigurable.resolveIcon and the fallback branch inside
ProjectFileGroupNode.autoDetectIcon to call
GroupIconResolver.resolveFallbackIcon instead, preserving the current checks
(GroupIconCatalog lookup, single inclusion pattern handling, extension and
filename heuristics, and default AllIcons.Nodes.Folder) so both callers use the
identical implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 77bcd0d6-c577-45f9-82e8-2688df821a59

📥 Commits

Reviewing files that changed from the base of the PR and between 6630e20 and 55617d3.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • docs/superpowers/plans/2026-05-08-dynamic-icons.md
  • docs/superpowers/specs/2026-05-07-dynamic-icons-design.md
  • src/main/kotlin/com/z8dn/plugins/a2pt/nodes/ProjectFileGroupNode.kt
  • src/main/kotlin/com/z8dn/plugins/a2pt/settings/AndroidViewSettings.kt
  • src/main/kotlin/com/z8dn/plugins/a2pt/settings/AndroidViewSettingsConfigurable.kt
  • src/main/kotlin/com/z8dn/plugins/a2pt/settings/GroupIconPickerDialog.kt
  • src/main/kotlin/com/z8dn/plugins/a2pt/settings/ProjectFileGroupDialog.kt
  • src/main/kotlin/com/z8dn/plugins/a2pt/utils/GroupIconCatalog.kt
  • src/main/kotlin/com/z8dn/plugins/a2pt/utils/GroupIconResolver.kt
  • src/main/resources/messages/AndroidViewBundle.properties
  • src/test/kotlin/com/z8dn/plugins/a2pt/utils/GroupIconCatalogTest.kt
  • src/test/kotlin/com/z8dn/plugins/a2pt/utils/GroupIconResolverTest.kt

Comment thread src/main/kotlin/com/z8dn/plugins/a2pt/settings/AndroidViewSettingsConfigurable.kt Outdated
Centralize the pattern-based auto-detect logic in GroupIconResolver and
reuse it from ProjectFileGroupNode, the settings table, and the Edit
File Group dialog. The dialog preview now reflects the icon that will
actually render in the tree (e.g. Kotlin icon for *.kt) instead of a
hardcoded folder, and refreshes as the user edits patterns.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Dynamic Icons for File Groups

1 participant