From a4f814e66e99ddf32e077d142a818248c3f9b40d Mon Sep 17 00:00:00 2001 From: Julian Tabel Date: Sun, 8 Feb 2026 14:55:26 +0100 Subject: [PATCH] Add section field to boss battles for run progression dividers Adds a nullable `section` column to boss battles (e.g. "Main Story", "Endgame") with dividers rendered in the run view between sections. Admin UI gets a Section column in the table and a text input in the form. Co-Authored-By: Claude Opus 4.6 --- ...progression-dividers-main-story-endgame.md | 11 ++ ...5a6b7c8d9e0_add_section_to_boss_battles.py | 26 ++++ backend/src/app/models/boss_battle.py | 1 + backend/src/app/schemas/boss.py | 12 ++ .../components/admin/BossBattleFormModal.tsx | 13 ++ frontend/src/pages/RunEncounters.tsx | 35 +++++- frontend/src/pages/admin/AdminGameDetail.tsx | 117 +++++++++++++++--- frontend/src/types/admin.ts | 7 ++ frontend/src/types/game.ts | 1 + 9 files changed, 199 insertions(+), 24 deletions(-) create mode 100644 .beans/nuzlocke-tracker-704x--run-progression-dividers-main-story-endgame.md create mode 100644 backend/src/app/alembic/versions/f5a6b7c8d9e0_add_section_to_boss_battles.py diff --git a/.beans/nuzlocke-tracker-704x--run-progression-dividers-main-story-endgame.md b/.beans/nuzlocke-tracker-704x--run-progression-dividers-main-story-endgame.md new file mode 100644 index 0000000..3e8be75 --- /dev/null +++ b/.beans/nuzlocke-tracker-704x--run-progression-dividers-main-story-endgame.md @@ -0,0 +1,11 @@ +--- +# nuzlocke-tracker-704x +title: Run progression dividers (main story / endgame) +status: completed +type: feature +priority: normal +created_at: 2026-02-08T13:46:12Z +updated_at: 2026-02-08T13:48:28Z +--- + +Add section field to boss battles to enable visual dividers between game progression phases (Main Story, Endgame, etc.) in both admin and run views. \ No newline at end of file diff --git a/backend/src/app/alembic/versions/f5a6b7c8d9e0_add_section_to_boss_battles.py b/backend/src/app/alembic/versions/f5a6b7c8d9e0_add_section_to_boss_battles.py new file mode 100644 index 0000000..c21a956 --- /dev/null +++ b/backend/src/app/alembic/versions/f5a6b7c8d9e0_add_section_to_boss_battles.py @@ -0,0 +1,26 @@ +"""add section to boss battles + +Revision ID: f5a6b7c8d9e0 +Revises: e4f5a6b7c8d9 +Create Date: 2026-02-08 20:00:00.000000 + +""" +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + + +# revision identifiers, used by Alembic. +revision: str = 'f5a6b7c8d9e0' +down_revision: Union[str, Sequence[str], None] = 'e4f5a6b7c8d9' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.add_column('boss_battles', sa.Column('section', sa.String(100), nullable=True)) + + +def downgrade() -> None: + op.drop_column('boss_battles', 'section') diff --git a/backend/src/app/models/boss_battle.py b/backend/src/app/models/boss_battle.py index b4012f2..03b5013 100644 --- a/backend/src/app/models/boss_battle.py +++ b/backend/src/app/models/boss_battle.py @@ -24,6 +24,7 @@ class BossBattle(Base): ForeignKey("routes.id"), index=True, default=None ) location: Mapped[str] = mapped_column(String(200)) + section: Mapped[str | None] = mapped_column(String(100), default=None) sprite_url: Mapped[str | None] = mapped_column(String(500)) version_group: Mapped["VersionGroup"] = relationship( diff --git a/backend/src/app/schemas/boss.py b/backend/src/app/schemas/boss.py index 3ad605b..61476f3 100644 --- a/backend/src/app/schemas/boss.py +++ b/backend/src/app/schemas/boss.py @@ -23,6 +23,7 @@ class BossBattleResponse(CamelModel): order: int after_route_id: int | None location: str + section: str | None sprite_url: str | None pokemon: list[BossPokemonResponse] = [] @@ -48,6 +49,7 @@ class BossBattleCreate(CamelModel): order: int after_route_id: int | None = None location: str + section: str | None = None sprite_url: str | None = None @@ -60,6 +62,7 @@ class BossBattleUpdate(CamelModel): order: int | None = None after_route_id: int | None = None location: str | None = None + section: str | None = None sprite_url: str | None = None @@ -75,6 +78,15 @@ class BossResultCreate(CamelModel): attempts: int = 1 +class BossReorderItem(CamelModel): + id: int + order: int + + +class BossReorderRequest(CamelModel): + bosses: list[BossReorderItem] + + class BossResultUpdate(CamelModel): result: str | None = None attempts: int | None = None diff --git a/frontend/src/components/admin/BossBattleFormModal.tsx b/frontend/src/components/admin/BossBattleFormModal.tsx index 88ec4fc..a89f105 100644 --- a/frontend/src/components/admin/BossBattleFormModal.tsx +++ b/frontend/src/components/admin/BossBattleFormModal.tsx @@ -43,6 +43,7 @@ export function BossBattleFormModal({ const [order, setOrder] = useState(String(boss?.order ?? nextOrder)) const [afterRouteId, setAfterRouteId] = useState(String(boss?.afterRouteId ?? '')) const [location, setLocation] = useState(boss?.location ?? '') + const [section, setSection] = useState(boss?.section ?? '') const [spriteUrl, setSpriteUrl] = useState(boss?.spriteUrl ?? '') const handleSubmit = (e: FormEvent) => { @@ -56,6 +57,7 @@ export function BossBattleFormModal({ order: Number(order), afterRouteId: afterRouteId ? Number(afterRouteId) : null, location, + section: section || null, spriteUrl: spriteUrl || null, }) } @@ -146,6 +148,17 @@ export function BossBattleFormModal({ +
+ + setSection(e.target.value)} + placeholder="e.g. Main Story, Endgame" + className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600" + /> +
+