978959bdc4
Operator feedback: thumbnails too small to judge order, no obvious way to mark
'this installment is Part 2', and the permanent two-pane picker was busy and
competed with the ordering work.
- Full-width parts, each a card with a big page grid (150px, contain so whole
pages are visible) and drag-to-reorder; positional page number as a badge.
- Editable Part # (hero field) backed by new series_chapter.stated_part —
separate from the auto-managed chapter_number, mirroring the page_number vs
stated_page split so reorder/delete renumbering can't wipe a hand-set part.
Missing-Part hints when consecutive parts' stated_part jump >1.
- Each part labels its source post (derived from pages' primary_post_id) and
shows the printed-page range with clear labels.
- Picker demoted to an on-demand right slide-over ('Add pages') with a target-
part selector; part actions (move/merge/delete) collapsed into an overflow ⋮.
alembic 0042 adds series_chapter.stated_part (nullable int).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
33 lines
1003 B
Python
33 lines
1003 B
Python
"""series chapter stated_part: operator-facing Part N label (FC-6.4)
|
|
|
|
Revision ID: 0042
|
|
Revises: 0041
|
|
Create Date: 2026-06-07
|
|
|
|
A chapter's positional chapter_number is auto-managed (rewritten 1..N on
|
|
reorder/delete), so it can't double as the installment number the operator wants
|
|
to type (e.g. a series authored from a post that is Part 2). Add a nullable
|
|
stated_part alongside it — the same split as series_page.page_number (order) vs
|
|
series_page.stated_page (printed number). Nullable; the UI falls back to
|
|
chapter_number when unset.
|
|
"""
|
|
from typing import Sequence, Union
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision: str = "0042"
|
|
down_revision: Union[str, None] = "0041"
|
|
branch_labels: Union[str, Sequence[str], None] = None
|
|
depends_on: Union[str, Sequence[str], None] = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.add_column(
|
|
"series_chapter", sa.Column("stated_part", sa.Integer, nullable=True)
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_column("series_chapter", "stated_part")
|