diff --git a/backend/bracket/routes/stages.py b/backend/bracket/routes/stages.py
index ea70974d..6ab47e16 100644
--- a/backend/bracket/routes/stages.py
+++ b/backend/bracket/routes/stages.py
@@ -61,7 +61,7 @@ async def delete_stage(
detail="Stage contains stage items, please delete those first",
)
- if stage.is_active:
+ if stage.is_active and len(stage.stage_items) > 0:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Stage is active, please activate another stage first",
diff --git a/backend/bracket/routes/tournaments.py b/backend/bracket/routes/tournaments.py
index 0214867f..0a3547ba 100644
--- a/backend/bracket/routes/tournaments.py
+++ b/backend/bracket/routes/tournaments.py
@@ -109,7 +109,14 @@ async def update_tournament_by_id(
async def delete_tournament(
tournament_id: TournamentId, _: UserPublic = Depends(user_authenticated_for_tournament)
) -> SuccessResponse:
- with check_foreign_key_violation({ForeignKey.stages_tournament_id_fkey}):
+ with check_foreign_key_violation(
+ {
+ ForeignKey.stages_tournament_id_fkey,
+ ForeignKey.teams_tournament_id_fkey,
+ ForeignKey.players_tournament_id_fkey,
+ ForeignKey.courts_tournament_id_fkey,
+ }
+ ):
await sql_delete_tournament(tournament_id)
return SuccessResponse()
diff --git a/backend/bracket/utils/errors.py b/backend/bracket/utils/errors.py
index 3174bcac..f4cdc0b6 100644
--- a/backend/bracket/utils/errors.py
+++ b/backend/bracket/utils/errors.py
@@ -16,12 +16,16 @@ class UniqueIndex(EnumAutoStr):
class ForeignKey(EnumAutoStr):
- stages_tournament_id_fkey = auto()
- tournaments_club_id_fkey = auto()
- stage_item_inputs_team_id_fkey = auto()
+ courts_tournament_id_fkey = auto()
matches_team1_id_fkey = auto()
- matches_team2_id_fkey = auto()
matches_team1_winner_from_stage_item_id_fkey = auto()
+ matches_team2_id_fkey = auto()
+ matches_team2_winner_from_stage_item_id_fkey = auto()
+ players_tournament_id_fkey = auto()
+ stage_item_inputs_team_id_fkey = auto()
+ stages_tournament_id_fkey = auto()
+ teams_tournament_id_fkey = auto()
+ tournaments_club_id_fkey = auto()
unique_index_violation_error_lookup = {
@@ -31,13 +35,18 @@ unique_index_violation_error_lookup = {
foreign_key_violation_error_lookup = {
- ForeignKey.stages_tournament_id_fkey: "This tournament still has stages, delete those first",
- ForeignKey.tournaments_club_id_fkey: "This club still has tournaments, delete those first",
- ForeignKey.stage_item_inputs_team_id_fkey: "This team is still used in stage items",
+ ForeignKey.courts_tournament_id_fkey: "This tournament still has courts, delete those first",
ForeignKey.matches_team1_id_fkey: "This team is still part of matches",
- ForeignKey.matches_team2_id_fkey: "This team is still part of matches",
ForeignKey.matches_team1_winner_from_stage_item_id_fkey: "This stage item is referenced by "
"other stage items",
+ ForeignKey.matches_team2_id_fkey: "This team is still part of matches",
+ ForeignKey.matches_team2_winner_from_stage_item_id_fkey: "This stage item is referenced by "
+ "other stage items",
+ ForeignKey.players_tournament_id_fkey: "This tournament still has players, delete those first",
+ ForeignKey.stage_item_inputs_team_id_fkey: "This team is still used in stage items",
+ ForeignKey.stages_tournament_id_fkey: "This tournament still has stages, delete those first",
+ ForeignKey.teams_tournament_id_fkey: "This tournament still has teams, delete those first",
+ ForeignKey.tournaments_club_id_fkey: "This club still has tournaments, delete those first",
}
diff --git a/backend/pyproject.toml b/backend/pyproject.toml
index cc2bbdc7..0f888842 100644
--- a/backend/pyproject.toml
+++ b/backend/pyproject.toml
@@ -70,6 +70,7 @@ disable = [
'unspecified-encoding',
'unused-argument', # Gives false positives.
'wrong-import-position',
+ 'contextmanager-generator-missing-cleanup', # Gives false positives.
]
[tool.bandit]
diff --git a/backend/tests/integration_tests/conftest.py b/backend/tests/integration_tests/conftest.py
index e930814b..0b8871d3 100644
--- a/backend/tests/integration_tests/conftest.py
+++ b/backend/tests/integration_tests/conftest.py
@@ -72,6 +72,5 @@ async def reinit_database(event_loop: AbstractEventLoop, worker_id: str) -> Asyn
@pytest.fixture(scope="session")
async def auth_context(reinit_database: Database) -> AsyncIterator[AuthContext]:
- async with reinit_database:
- async with inserted_auth_context() as auth_context:
- yield auth_context
+ async with reinit_database, inserted_auth_context() as auth_context:
+ yield auth_context
diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json
index b3e7a13e..6172466a 100644
--- a/frontend/public/locales/en/common.json
+++ b/frontend/public/locales/en/common.json
@@ -140,9 +140,11 @@
"negative_match_margin_validation": "Match margin cannot be negative",
"negative_score_validation": "Score cannot be negative",
"next_matches_badge": "Next matches",
- "next_stage_button": "Go to Next Stage",
+ "next_stage_button": "Next Stage",
"no_matches_description": "First, add matches by creating stages and stage items. Then, schedule them using the button in the topright corner.",
"no_matches_title": "No matches scheduled yet",
+ "no_players_title": "No players yet",
+ "no_teams_title": "No teams yet",
"no_round_description": "There are no rounds in this stage item yet",
"no_round_found_description": "Please wait for the organiser to add them.",
"no_round_found_in_stage_description": "There are no rounds in this stage yet",
@@ -168,7 +170,7 @@
"players_spotlight_description": "View, add or delete players",
"players_title": "players",
"policy_not_accepted": "Please indicate that you have read the policy",
- "previous_stage_button": "Go to Previous Stage",
+ "previous_stage_button": "Previous Stage",
"recommended_badge_title": "Recommended",
"remove_logo": "Remove logo",
"remove_match_button": "Remove Match",
diff --git a/frontend/src/components/buttons/create_stage.tsx b/frontend/src/components/buttons/create_stage.tsx
index be143f7c..1bcf4dab 100644
--- a/frontend/src/components/buttons/create_stage.tsx
+++ b/frontend/src/components/buttons/create_stage.tsx
@@ -47,7 +47,7 @@ export function CreateStageButtonLarge({
variant="outline"
color="green"
size="lg"
- style={{ marginRight: 10, width: '25%' }}
+ style={{ marginRight: 10 }}
onClick={async () => {
await createStage(tournament.id);
await swrStagesResponse.mutate();
diff --git a/frontend/src/components/modals/club_modal.tsx b/frontend/src/components/modals/club_modal.tsx
index a4d48cf5..8060afec 100644
--- a/frontend/src/components/modals/club_modal.tsx
+++ b/frontend/src/components/modals/club_modal.tsx
@@ -1,4 +1,4 @@
-import { Button, Group, Modal, TextInput } from '@mantine/core';
+import { Button, Modal, TextInput } from '@mantine/core';
import { useForm } from '@mantine/form';
import { BiEditAlt } from '@react-icons/all-files/bi/BiEditAlt';
import { GoPlus } from '@react-icons/all-files/go/GoPlus';
@@ -23,13 +23,13 @@ export default function ClubModal({
const icon = is_create_form ? : ;
const [opened, setOpened] = useState(false);
const modalOpenButton = is_create_form ? (
-
- setOpened(true)}
- leftSection={}
- title={operation_text}
- />
-
+ setOpened(true)}
+ leftSection={}
+ title={operation_text}
+ />
) : (
setOpened(true)}
leftSection={}
diff --git a/frontend/src/components/tables/players.tsx b/frontend/src/components/tables/players.tsx
index 485c25e0..6068bb24 100644
--- a/frontend/src/components/tables/players.tsx
+++ b/frontend/src/components/tables/players.tsx
@@ -1,4 +1,4 @@
-import { Badge, Table, Text } from '@mantine/core';
+import { Badge, Center, Pagination, Table, Text } from '@mantine/core';
import { useTranslation } from 'next-i18next';
import React from 'react';
import { SWRResponse } from 'swr';
@@ -10,7 +10,7 @@ import DeleteButton from '../buttons/delete';
import { PlayerScore } from '../info/player_score';
import { WinDistribution } from '../info/player_statistics';
import PlayerUpdateModal from '../modals/player_update_modal';
-import { EmptyTableInfo } from '../no_content/empty_table_info';
+import { NoContent } from '../no_content/empty_table_info';
import { DateTime } from '../utils/datetime';
import RequestErrorAlert from '../utils/error_alert';
import { TableSkeletonSingleColumn } from '../utils/skeletons';
@@ -39,10 +39,12 @@ export default function PlayersTable({
swrPlayersResponse,
tournamentData,
tableState,
+ playerCount,
}: {
swrPlayersResponse: SWRResponse;
tournamentData: TournamentMinimal;
tableState: TableState;
+ playerCount: number;
}) {
const { t } = useTranslation();
const players: Player[] =
@@ -111,36 +113,46 @@ export default function PlayersTable({
));
- if (rows.length < 1) return ;
+ if (rows.length < 1) return ;
return (
-
-
-
-
- {t('status')}
-
-
- {t('title')}
-
-
- {t('created')}
-
-
- <>
-
- >
-
-
- {t('elo_score')}
-
-
- {t('swiss_score')}
-
- {null}
-
-
- {rows}
-
+ <>
+
+
+
+
+ {t('status')}
+
+
+ {t('title')}
+
+
+ {t('created')}
+
+
+ <>
+
+ >
+
+
+ {t('elo_score')}
+
+
+ {t('swiss_score')}
+
+ {null}
+
+
+ {rows}
+
+
+
+
+ >
);
}
diff --git a/frontend/src/components/tables/teams.tsx b/frontend/src/components/tables/teams.tsx
index 8cef673f..3fe259e9 100644
--- a/frontend/src/components/tables/teams.tsx
+++ b/frontend/src/components/tables/teams.tsx
@@ -1,4 +1,4 @@
-import { Badge, Table } from '@mantine/core';
+import { Badge, Center, Pagination, Table } from '@mantine/core';
import { useTranslation } from 'next-i18next';
import React from 'react';
import { SWRResponse } from 'swr';
@@ -9,7 +9,7 @@ import { deleteTeam } from '../../services/team';
import DeleteButton from '../buttons/delete';
import PlayerList from '../info/player_list';
import TeamUpdateModal from '../modals/team_update_modal';
-import { EmptyTableInfo } from '../no_content/empty_table_info';
+import { NoContent } from '../no_content/empty_table_info';
import { DateTime } from '../utils/datetime';
import RequestErrorAlert from '../utils/error_alert';
import { TableSkeletonSingleColumn } from '../utils/skeletons';
@@ -20,11 +20,13 @@ export default function TeamsTable({
swrTeamsResponse,
teams,
tableState,
+ teamCount,
}: {
tournamentData: TournamentMinimal;
swrTeamsResponse: SWRResponse;
teams: TeamInterface[];
tableState: TableState;
+ teamCount: number;
}) {
const { t } = useTranslation();
if (swrTeamsResponse.error) return ;
@@ -70,32 +72,43 @@ export default function TeamsTable({
));
- if (rows.length < 1) return ;
+ if (rows.length < 1) return ;
return (
-
-
-
-
- {t('status')}
-
-
- {t('name_table_header')}
-
- {t('members_table_header')}
-
- {t('created')}
-
-
- {t('swiss_score')}
-
-
- {t('elo_score')}
-
- {null}
-
-
- {rows}
-
+ <>
+
+
+
+
+ {t('status')}
+
+
+ {t('name_table_header')}
+
+ {t('members_table_header')}
+
+ {t('created')}
+
+
+ {t('swiss_score')}
+
+
+ {t('elo_score')}
+
+ {null}
+
+
+ {rows}
+
+
+
+
+
+ >
);
}
diff --git a/frontend/src/pages/clubs.tsx b/frontend/src/pages/clubs.tsx
index 6a4d0f57..66ffb058 100644
--- a/frontend/src/pages/clubs.tsx
+++ b/frontend/src/pages/clubs.tsx
@@ -7,6 +7,7 @@ import ClubsTable from '../components/tables/clubs';
import { capitalize } from '../components/utils/util';
import { checkForAuthError, getClubs } from '../services/adapter';
import Layout from './_layout';
+import classes from './index.module.css';
export default function HomePage() {
const swrClubsResponse = getClubs();
@@ -16,11 +17,11 @@ export default function HomePage() {
return (
-
-
+
+
{capitalize(t('clubs_title'))}
-
+
diff --git a/frontend/src/pages/tournaments/[id]/players.tsx b/frontend/src/pages/tournaments/[id]/players.tsx
index e23a964f..27f1560b 100644
--- a/frontend/src/pages/tournaments/[id]/players.tsx
+++ b/frontend/src/pages/tournaments/[id]/players.tsx
@@ -1,4 +1,4 @@
-import { Center, Grid, Pagination, Title } from '@mantine/core';
+import { Grid, Title } from '@mantine/core';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import React from 'react';
@@ -33,18 +33,11 @@ export default function Players() {
-
-
-
);
}
diff --git a/frontend/src/pages/tournaments/[id]/settings.tsx b/frontend/src/pages/tournaments/[id]/settings.tsx
index bee0fb34..0c58e25d 100644
--- a/frontend/src/pages/tournaments/[id]/settings.tsx
+++ b/frontend/src/pages/tournaments/[id]/settings.tsx
@@ -19,6 +19,7 @@ import { IconCalendar, IconCalendarTime } from '@tabler/icons-react';
import assert from 'assert';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
+import { useRouter } from 'next/router';
import React from 'react';
import { SWRResponse } from 'swr';
@@ -32,6 +33,7 @@ import {
getBaseApiUrl,
getClubs,
getTournamentById,
+ handleRequestError,
removeTournamentLogo,
} from '../../../services/adapter';
import { deleteTournament, updateTournament } from '../../../services/tournament';
@@ -53,6 +55,7 @@ function GeneralTournamentForm({
swrTournamentResponse: SWRResponse;
clubs: Club[];
}) {
+ const router = useRouter();
const { t } = useTranslation();
const form = useForm({
@@ -228,7 +231,11 @@ function GeneralTournamentForm({
size="sm"
leftSection={}
onClick={async () => {
- await deleteTournament(tournament.id);
+ await deleteTournament(tournament.id)
+ .then(async () => {
+ await router.push('/');
+ })
+ .catch((response: any) => handleRequestError(response));
}}
>
{t('delete_tournament_button')}
diff --git a/frontend/src/pages/tournaments/[id]/teams.tsx b/frontend/src/pages/tournaments/[id]/teams.tsx
index 9d6acfd6..26b85219 100644
--- a/frontend/src/pages/tournaments/[id]/teams.tsx
+++ b/frontend/src/pages/tournaments/[id]/teams.tsx
@@ -1,4 +1,4 @@
-import { Center, Grid, Pagination, Select, Title } from '@mantine/core';
+import { Grid, Select, Title } from '@mantine/core';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import React, { useState } from 'react';
@@ -95,15 +95,8 @@ export default function Teams() {
tournamentData={tournamentData}
teams={teams}
tableState={tableState}
+ teamCount={teamCount}
/>
-
-
-
);
}
diff --git a/frontend/src/services/tournament.tsx b/frontend/src/services/tournament.tsx
index 75309d8b..84b7cd04 100644
--- a/frontend/src/services/tournament.tsx
+++ b/frontend/src/services/tournament.tsx
@@ -28,9 +28,7 @@ export async function createTournament(
}
export async function deleteTournament(tournament_id: number) {
- return createAxios()
- .delete(`tournaments/${tournament_id}`)
- .catch((response: any) => handleRequestError(response));
+ return createAxios().delete(`tournaments/${tournament_id}`);
}
export async function updateTournament(