diff --git a/backend/bracket/logic/scheduling/handle_stage_activation.py b/backend/bracket/logic/scheduling/handle_stage_activation.py
index d11909ec0..da2c9e81e 100644
--- a/backend/bracket/logic/scheduling/handle_stage_activation.py
+++ b/backend/bracket/logic/scheduling/handle_stage_activation.py
@@ -1,12 +1,18 @@
from collections import defaultdict
+from fastapi import HTTPException
from pydantic import BaseModel
+from starlette import status
from bracket.logic.ranking.elo import (
determine_team_ranking_for_stage_item,
)
from bracket.logic.ranking.statistics import TeamStatistics
-from bracket.models.db.stage_item_inputs import StageItemInputFinal, StageItemInputTentative
+from bracket.models.db.stage_item_inputs import (
+ StageItemInputEmpty,
+ StageItemInputFinal,
+ StageItemInputTentative,
+)
from bracket.models.db.team import Team
from bracket.models.db.util import StageWithStageItems
from bracket.sql.matches import clear_scores_for_matches_in_stage_item
@@ -65,7 +71,15 @@ async def get_team_update_for_input(
target_stage_item_input = await get_stage_item_input_by_id(
tournament_id, target_stage_item_input_id
)
- assert isinstance(target_stage_item_input, StageItemInputFinal)
+ if isinstance(target_stage_item_input, StageItemInputEmpty):
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="Please first assign teams to all stage items in the current stage.",
+ )
+
+ assert isinstance(
+ target_stage_item_input, StageItemInputFinal
+ ), f"Unexpected stage item type: {type(target_stage_item_input)}"
return StageItemInputUpdate(
stage_item_input=stage_item_input, team=target_stage_item_input.team
)
diff --git a/backend/bracket/routes/stages.py b/backend/bracket/routes/stages.py
index a51549cbd..ccdddd869 100644
--- a/backend/bracket/routes/stages.py
+++ b/backend/bracket/routes/stages.py
@@ -126,12 +126,13 @@ async def activate_next_stage(
stages = await get_full_tournament_details(tournament_id)
deactivated_stage = next((stage for stage in stages if stage.is_active), None)
- await sql_activate_next_stage(new_active_stage_id, tournament_id)
if stage_body.direction == "next":
await update_matches_in_activated_stage(tournament_id, new_active_stage_id)
else:
if deactivated_stage:
await update_matches_in_deactivated_stage(tournament_id, deactivated_stage)
+
+ await sql_activate_next_stage(new_active_stage_id, tournament_id)
return SuccessResponse()
diff --git a/frontend/src/components/modals/activate_next_stage_modal.tsx b/frontend/src/components/modals/activate_next_stage_modal.tsx
index f0247066d..457814eb9 100644
--- a/frontend/src/components/modals/activate_next_stage_modal.tsx
+++ b/frontend/src/components/modals/activate_next_stage_modal.tsx
@@ -1,4 +1,4 @@
-import { Alert, Button, Container, Grid, Loader, Modal, Title } from '@mantine/core';
+import { Alert, Button, Container, Grid, Modal, Title } from '@mantine/core';
import { useForm } from '@mantine/form';
import { FaArrowRight } from '@react-icons/all-files/fa/FaArrowRight';
import { IconAlertCircle, IconSquareArrowRight } from '@tabler/icons-react';
@@ -11,6 +11,8 @@ import { StageItemInput, formatStageItemInput } from '../../interfaces/stage_ite
import { TeamInterface } from '../../interfaces/team';
import { getStageItemLookup } from '../../services/lookups';
import { activateNextStage } from '../../services/stage';
+import RequestErrorAlert from '../utils/error_alert';
+import { GenericSkeleton } from '../utils/skeletons';
type Update = { stage_item_input: StageItemInput; team: TeamInterface };
type StageItemUpdate = { updates: Update[]; stageItem: StageItemWithRounds };
@@ -47,7 +49,10 @@ function UpdatesToStageItemInputsTables({
swrRankingsPerStageItemResponse: SWRResponse;
}) {
if (swrRankingsPerStageItemResponse.isLoading) {
- return ;
+ return ;
+ }
+ if (swrRankingsPerStageItemResponse.error) {
+ return ;
}
const items = swrRankingsPerStageItemResponse.data.data;
diff --git a/frontend/src/components/utils/error_alert.tsx b/frontend/src/components/utils/error_alert.tsx
index 604532d72..528dbaebf 100644
--- a/frontend/src/components/utils/error_alert.tsx
+++ b/frontend/src/components/utils/error_alert.tsx
@@ -4,7 +4,13 @@ import React from 'react';
export function ErrorAlert({ title, message }: { title: string; message: string }) {
return (
- } title={title} color="red" radius="lg">
+ }
+ title={title}
+ color="red"
+ radius="lg"
+ variant="outline"
+ >
{message}
);
diff --git a/frontend/src/components/utils/skeletons.tsx b/frontend/src/components/utils/skeletons.tsx
index 387513223..8938e2b6a 100644
--- a/frontend/src/components/utils/skeletons.tsx
+++ b/frontend/src/components/utils/skeletons.tsx
@@ -2,11 +2,15 @@ import { Center, Grid, Skeleton } from '@mantine/core';
import React from 'react';
export function GenericSkeleton() {
+ return ;
+}
+
+export function GenericSkeletonThreeRows() {
return (
<>
-
-
-
+
+
+
>
);
}
diff --git a/frontend/src/pages/tournaments/[id]/settings.tsx b/frontend/src/pages/tournaments/[id]/settings.tsx
index bb4fb07bc..0cc0b9e8b 100644
--- a/frontend/src/pages/tournaments/[id]/settings.tsx
+++ b/frontend/src/pages/tournaments/[id]/settings.tsx
@@ -25,7 +25,7 @@ import { SWRResponse } from 'swr';
import NotFoundTitle from '../../404';
import { DropzoneButton } from '../../../components/utils/file_upload';
-import { GenericSkeleton } from '../../../components/utils/skeletons';
+import { GenericSkeletonThreeRows } from '../../../components/utils/skeletons';
import { capitalize, getBaseURL, getTournamentIdFromRouter } from '../../../components/utils/util';
import { Club } from '../../../interfaces/club';
import { Tournament } from '../../../interfaces/tournament';
@@ -266,7 +266,7 @@ export default function SettingsPage() {
let content = ;
if (swrTournamentResponse.isLoading || swrClubsResponse.isLoading) {
- content = ;
+ content = ;
}
if (tournamentDataFull != null) {