mirror of
https://github.com/hansjone/netx.git
synced 2026-10-14 18:30:47 +08:00
Let users pick and order their workbench module tiles.
Per-user layout lives in the new app_user.prefs JSON column, read via /v1/auth/me and written via PUT /v1/auth/me/prefs/workbench. The workbench gets an in-place edit mode (gear -> drag to reorder, x to remove, tray to add back, reset/done). Reset stores empty prefs so registry changes still apply; ids of modules the user can't currently see are kept on save. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
313706595d
commit
2307f19779
16 changed files with 906 additions and 23 deletions
52
alembic/versions/20261013_user_prefs.py
Normal file
52
alembic/versions/20261013_user_prefs.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
"""Add app_user.prefs JSON for per-user UI preferences.
|
||||
|
||||
Revision ID: 20261013_user_prefs
|
||||
Revises: 20260922_biz_state_queued
|
||||
Create Date: 2026-10-13
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision: str = "20261013_user_prefs"
|
||||
down_revision: Union[str, Sequence[str], None] = "20260922_biz_state_queued"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
bind = op.get_bind()
|
||||
dialect = str(getattr(bind.dialect, "name", "") or "").lower()
|
||||
if dialect.startswith("postgres"):
|
||||
op.execute(
|
||||
"ALTER TABLE app_user ADD COLUMN IF NOT EXISTS prefs JSON DEFAULT '{}'::json NOT NULL"
|
||||
)
|
||||
# Ensure NOT NULL + default for brownfield rows that already had a nullable column.
|
||||
op.execute("UPDATE app_user SET prefs = '{}'::json WHERE prefs IS NULL")
|
||||
op.execute("ALTER TABLE app_user ALTER COLUMN prefs SET DEFAULT '{}'::json")
|
||||
op.execute("ALTER TABLE app_user ALTER COLUMN prefs SET NOT NULL")
|
||||
else:
|
||||
insp = sa.inspect(bind)
|
||||
if "app_user" in insp.get_table_names():
|
||||
cols = {c["name"] for c in insp.get_columns("app_user")}
|
||||
if "prefs" not in cols:
|
||||
op.add_column(
|
||||
"app_user",
|
||||
sa.Column("prefs", sa.JSON(), nullable=False, server_default="{}"),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
bind = op.get_bind()
|
||||
dialect = str(getattr(bind.dialect, "name", "") or "").lower()
|
||||
if dialect.startswith("postgres"):
|
||||
op.execute("ALTER TABLE app_user DROP COLUMN IF EXISTS prefs")
|
||||
else:
|
||||
try:
|
||||
op.drop_column("app_user", "prefs")
|
||||
except Exception:
|
||||
pass
|
||||
Loading…
Add table
Add a link
Reference in a new issue