Board row ordering, type-derived row colours, and clearer upcoming events

This commit is contained in:
2026-08-08 14:24:28 -04:00
parent 3ebc1f353a
commit 4344adabf1
11 changed files with 450 additions and 72 deletions

View File

@@ -0,0 +1,61 @@
"""Add notificationtypes.boardorder (row order on the shopfloor board).
Rows were ordered by display style and then type name, so what led the screen
was an accident of styling and the alphabet. A site decides its own running
order now: low first, and rows sharing a category sort by the lowest order
among their types.
Existing rows default to 100. Recognition and Recertification are seeded ahead
of that (10 and 20) so the out-of-the-box board keeps the order sites already
expect, without pinning anything a site has since renamed.
Idempotent; downgrade drops the column.
Revision ID: notifications0005boardorder
Revises: notifications0004category
"""
from alembic import op
import sqlalchemy as sa
revision = 'notifications0005boardorder'
down_revision = 'notifications0004category'
branch_labels = None
depends_on = None
_TABLE = 'notificationtypes'
_COLUMN = 'boardorder'
# Only the two types every site starts with; anything else keeps the default.
_SEEDED_ORDER = (('Recognition', 10), ('Recertification', 20))
def _column_names(insp, table):
return {c['name'] for c in insp.get_columns(table)}
def upgrade():
bind = op.get_bind()
insp = sa.inspect(bind)
if _TABLE not in insp.get_table_names():
return
if _COLUMN in _column_names(insp, _TABLE):
return
op.add_column(_TABLE, sa.Column(_COLUMN, sa.Integer(), nullable=False,
server_default='100'))
# Seed the shipped types' order. Guarded on the default so a site that has
# already set an order (re-running after a manual add) is left alone.
for typename, order in _SEEDED_ORDER:
bind.execute(
sa.text('UPDATE notificationtypes SET boardorder = :order '
'WHERE typename = :typename AND boardorder = 100'),
{'order': order, 'typename': typename})
def downgrade():
bind = op.get_bind()
insp = sa.inspect(bind)
if _TABLE not in insp.get_table_names():
return
if _COLUMN in _column_names(insp, _TABLE):
op.drop_column(_TABLE, _COLUMN)