Per-type expiry tail on the shopfloor board, and a 2x2 recertification block

This commit is contained in:
2026-08-07 09:28:10 -04:00
parent dd6ccd7a55
commit 2f15610cfd
7 changed files with 277 additions and 25 deletions

View File

@@ -0,0 +1,47 @@
"""Add notificationtypes.gracewindowminutes (post-expiry tail on the board).
The shopfloor feed kept every ended notification on the board for a hardcoded
30 minutes, flagged resolved. A card with an 8:00 end time therefore sat there
until 8:30, and in the carousel/grid/banner sections it did so with no visual
sign it had ended at all. The tail is now per type and defaults to 0, so an end
time means what it says; a type that wants an acknowledged tail opts in.
Idempotent; downgrade drops the column.
Revision ID: notifications0003grace
Revises: notifications0002buidx
"""
from alembic import op
import sqlalchemy as sa
revision = 'notifications0003grace'
down_revision = 'notifications0002buidx'
branch_labels = None
depends_on = None
_TABLE = 'notificationtypes'
_COLUMN = 'gracewindowminutes'
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 not in _column_names(insp, _TABLE):
op.add_column(_TABLE, sa.Column(_COLUMN, sa.Integer(), nullable=False,
server_default='0'))
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)