Add per-role badge colors

Role badges rendered gray for everything except admin, with no way to tell
roles apart. Add an optional color per role, matching how statuses and types
carry one: new roles.color column (migration 7d27_roles_color), color threaded
through the role API and the user serializer, and a ColorSwatchPicker in the
role editor. Badges use the role's color with contrast-aware text and fall
back to the old admin/gray classes when unset.
This commit is contained in:
cproudlock
2026-07-20 10:05:58 -04:00
parent 0b247ed96f
commit a7ff882e21
5 changed files with 119 additions and 4 deletions

View File

@@ -0,0 +1,49 @@
"""Add roles.color for per-role badge colors
Roles rendered as gray badges everywhere except admin (hardcoded). Give each
role an optional CSS color, matching how statuses/types carry a color column,
so role badges are visually distinct and admin-editable.
Idempotent guard on column presence; real downgrade drops the column.
Revision ID: 7d27_roles_color
Revises: 7d26_settings_description_text
Create Date: 2026-07-20
"""
from alembic import op
import sqlalchemy as sa
revision = '7d27_roles_color'
down_revision = '7d26_settings_description_text'
branch_labels = None
depends_on = None
def _has_color(insp):
return any(c['name'] == 'color' for c in insp.get_columns('roles'))
def upgrade():
bind = op.get_bind()
insp = sa.inspect(bind)
if 'roles' not in insp.get_table_names():
return
if _has_color(insp):
return
op.add_column('roles', sa.Column('color', sa.String(length=20), nullable=True))
def downgrade():
bind = op.get_bind()
insp = sa.inspect(bind)
if 'roles' not in insp.get_table_names():
return
if not _has_color(insp):
return
op.drop_column('roles', 'color')