Self-review of the branch diff (feature/plex-filter-bar-overhaul) against main: - Surprise rail query key omitted `lang` while the backend /surprise now filters against the language-specific genre column → a HU/EN switch under an active genre filter left the rail stale. Key it by scope+lang+filters, matching plexDiscover. - Chip-removing a collection left its entry in `collectionTitles` (hashed into the plex query keys), splitting the cache from the pristine no-collection state and growing the titles map unboundedly. Prune the title on remove, like CollectionPicker. - The saved-views default-mirror effect gained `cfg` in its deps (re-memoized on every live filter edit) → a synchronous localStorage write per keystroke. Depend on the module-stable mirror fn instead. - Collections-browse search input had no accessible name (placeholder only). Add aria-label + type="search". - Extract the tile hue-hash + gradient duplicated between PlexDiscover and plexBrowseLists into a shared lib/hueTile so the two surfaces can't drift. - Document migration 0073 downgrade() as lossy and de-dup non-feed rows before recreating the narrow (user_id, name) constraint (verified by the drift test). - Add unit tests for coercePlexFilters (legacy single-collection migration) and plexFiltersSignature (order-independence, title-ignoring). Gate: tsc/lint/knip/prettier clean, 410 vitest; backend ruff + migration drift + saved-views tests green.
40 lines
1.8 KiB
Python
40 lines
1.8 KiB
Python
"""saved_views.source (ask 4: per-module saved views)
|
|
|
|
Saved "smart views" were feed-only; the Plex module now has them too. Add a `source` discriminator
|
|
(default "feed" so every existing row stays a feed view) and widen the per-user unique name constraint
|
|
to (user_id, source, name) so a feed view and a Plex view can share a name. `source` is NOT NULL with a
|
|
server_default, so the ADD is a metadata-only rewrite-free change; the constraint swap is quick on a
|
|
small per-user table.
|
|
"""
|
|
from typing import Sequence, Union
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision: str = "0073_saved_view_source"
|
|
down_revision: Union[str, None] = "0072_plex_person_bio"
|
|
branch_labels: Union[str, Sequence[str], None] = None
|
|
depends_on: Union[str, Sequence[str], None] = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.add_column(
|
|
"saved_views",
|
|
sa.Column("source", sa.String(length=16), nullable=False, server_default="feed"),
|
|
)
|
|
op.drop_constraint("uq_user_saved_view", "saved_views", type_="unique")
|
|
op.create_unique_constraint(
|
|
"uq_user_source_saved_view", "saved_views", ["user_id", "source", "name"]
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
# LOSSY / effectively forward-only: upgrade lets a user hold a feed view and a plex view of the same
|
|
# name, so re-creating the narrow (user_id, name) constraint can raise IntegrityError on such a pair.
|
|
# De-dup by dropping the non-feed rows first (they can't exist in the pre-0073 schema anyway) so the
|
|
# narrow constraint re-applies cleanly for the drift test's downgrade→re-upgrade cycle.
|
|
op.execute("DELETE FROM saved_views WHERE source <> 'feed'")
|
|
op.drop_constraint("uq_user_source_saved_view", "saved_views", type_="unique")
|
|
op.create_unique_constraint("uq_user_saved_view", "saved_views", ["user_id", "name"])
|
|
op.drop_column("saved_views", "source")
|