Skip to content

Add admin-only color override for group subquestions and MC options#5017

Open
aseckin wants to merge 1 commit into
mainfrom
feature/subquestion-colors
Open

Add admin-only color override for group subquestions and MC options#5017
aseckin wants to merge 1 commit into
mainfrom
feature/subquestion-colors

Conversation

@aseckin

@aseckin aseckin commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Adds an admin-only (is_superuser) color picker to the Create/Edit Question forms, letting admins override the default index-based colors for question group subquestions and multiple choice options.

colorpicker.mp4

UI

  • A color swatch next to each Subquestion Label (group form) and at the end of each Choices row (MC form); clicking opens a small panel with the 18 mc-option palette colors + a reset-to-default cell.
  • Only rendered for superusers; MC colors remain editable even when options are locked by existing forecasts.

Backend

  • Two new nullable Question fields + migration: label_color (palette key, group subquestions) and options_colors (dict of option label → palette key, MC), exposed in read/write serializers with light shape validation.
  • Admin option renames (multiple_choice_rename_option) carry the color along; dict keyed by label is unaffected by reorders.

Rendering

  • Colors are stored as METAC_COLORS["mc-option"] palette keys, so light/dark theme variants keep working.
  • Override applied at the single choke point (generateChoiceItemsFromMultipleChoiceForecast / generateChoiceItemsFromGroupQuestions in choices.ts) with fallback to the existing index-based scale — all timelines, legends, and feed/consumer cards inherit it. Unset or unknown keys behave exactly as before.

Notes

  • No duplicate-color checking by design (admin discretion).
  • No server-side superuser gating: the API is already auth-gated and the field is purely cosmetic.
  • Verified locally: serializer round-trip, chart rendering of overrides + fallbacks on MC and group questions (light/dark), lint/typecheck/ruff clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added color customization for multiple-choice options and subquestion labels.
    • Added a color picker with palette selection and a default/clear option for authorized users.
    • Preserved selected colors when editing drafts or renaming options.
    • Added localized color-related labels in Czech, English, Spanish, Portuguese, Simplified Chinese, and Traditional Chinese.
  • Bug Fixes
    • Custom colors now take precedence over automatically assigned colors when displaying choices and subquestions.

Admins (is_superuser) can now set an explicit color per group
subquestion and per multiple-choice option in the Create/Edit Question
forms, via a small palette swatch picker next to the Subquestion Label
field and at the end of each Choices row.

- New nullable Question fields: label_color (palette key for group
  subquestions) and options_colors (dict of option label -> palette
  key for MC), exposed in read/write serializers with light validation.
- Colors are stored as keys of METAC_COLORS["mc-option"] so light/dark
  theme variants keep working.
- Override applied at the choices.ts choke point with fallback to the
  existing index-based color scale, so all timelines, legends and cards
  inherit it; unset/unknown keys behave exactly as before.
- Option colors keyed by label survive reorders; renames via the admin
  update-options handler carry the color along.
- MC colors stay editable even when options are locked by forecasts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: admin-only color overrides for group subquestions and multiple-choice options.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/subquestion-colors

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.

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Preview Environment

Your preview environment is ready!

Resource Details
🌐 Preview URL https://metaculus-pr-5017-feature-subquestion-colors-preview.mtcl.cc
📦 Docker Image ghcr.io/metaculus/metaculus:feature-subquestion-colors-97e46c7
🗄️ PostgreSQL NeonDB branch preview/pr-5017-feature-subquestion-colors
Redis Fly Redis mtc-redis-pr-5017-feature-subquestion-colors

Details

  • Commit: 80341b032e30f0e1cb09d26e6e50e4c110c58cc0
  • Branch: feature/subquestion-colors
  • Fly App: metaculus-pr-5017-feature-subquestion-colors

ℹ️ Preview Environment Info

Isolation:

  • PostgreSQL and Redis are fully isolated from production
  • Each PR gets its own database branch and Redis instance
  • Changes pushed to this PR will trigger a new deployment

Limitations:

  • Background workers and cron jobs are not deployed in preview environments
  • If you need to test background jobs, use Heroku staging environments

Cleanup:

  • This preview will be automatically destroyed when the PR is closed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
front_end/src/app/(main)/questions/components/group_form.tsx (1)

821-826: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid directly mutating the state object.

React state should be treated as immutable. While mutating the object directly and returning it in a new array will trigger a re-render in this component, it can lead to subtle bugs in memoized child components or hooks that rely on referential equality.

Consider returning a cloned object instead.

♻️ Proposed refactor
                             subQuestions.map((subQuestion, iter_index) => {
                               if (index === iter_index) {
-                                subQuestion["label_color"] = key;
+                                return { ...subQuestion, label_color: key };
                               }
                               return subQuestion;
                             })
🤖 Prompt for 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.

In `@front_end/src/app/`(main)/questions/components/group_form.tsx around lines
821 - 826, Update the subQuestions mapping in the group form so the item
matching iter_index is replaced with a cloned object containing the new
label_color, rather than mutating subQuestion directly. Return unchanged
subQuestion objects for all other entries and preserve the existing array update
behavior.
🤖 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 `@front_end/src/app/`(main)/questions/components/color_picker.tsx:
- Around line 51-66: Add an accessible name to each color swatch button in the
color-picker rendering by deriving a descriptive label from the color/key, and
apply that value to both aria-label and title. Keep the existing selection,
styling, and click behavior unchanged.

---

Nitpick comments:
In `@front_end/src/app/`(main)/questions/components/group_form.tsx:
- Around line 821-826: Update the subQuestions mapping in the group form so the
item matching iter_index is replaced with a cloned object containing the new
label_color, rather than mutating subQuestion directly. Return unchanged
subQuestion objects for all other entries and preserve the existing array update
behavior.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ae2a469d-ac8c-4840-a350-6d5bf50f4d94

📥 Commits

Reviewing files that changed from the base of the PR and between ff66637 and 97e46c7.

📒 Files selected for processing (16)
  • front_end/messages/cs.json
  • front_end/messages/en.json
  • front_end/messages/es.json
  • front_end/messages/pt.json
  • front_end/messages/zh-TW.json
  • front_end/messages/zh.json
  • front_end/src/app/(main)/questions/components/color_picker.tsx
  • front_end/src/app/(main)/questions/components/group_form.tsx
  • front_end/src/app/(main)/questions/components/question_form.tsx
  • front_end/src/constants/colors.ts
  • front_end/src/types/question.ts
  • front_end/src/utils/questions/choices.ts
  • questions/migrations/0038_question_label_color_question_options_colors.py
  • questions/models.py
  • questions/serializers/common.py
  • questions/services/multiple_choice_handlers.py

Comment thread front_end/src/app/(main)/questions/components/color_picker.tsx
@aseckin aseckin requested review from hlbmtc and ncarazon July 15, 2026 15:15
@aseckin aseckin marked this pull request as ready for review July 15, 2026 15:15
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.

1 participant