mirror of
https://github.com/evroon/bracket.git
synced 2026-01-31 01:21:18 -05:00
Implement autoscheduling with parameters (#348)
This commit is contained in:
@@ -115,11 +115,6 @@ async def create_team(
|
||||
tournament_id: int,
|
||||
_: UserPublic = Depends(user_authenticated_for_tournament),
|
||||
) -> SingleTeamResponse:
|
||||
tournament_teams = await get_teams_with_members(tournament_id)
|
||||
for team in tournament_teams:
|
||||
if team.player_ids != [] and sorted(team.player_ids) == sorted(team_to_insert.player_ids):
|
||||
return SingleTeamResponse(data=team)
|
||||
|
||||
last_record_id = await database.execute(
|
||||
query=teams.insert(),
|
||||
values=TeamToInsert(
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { Button } from '@mantine/core';
|
||||
import { IconTool } from '@tabler/icons-react';
|
||||
import React from 'react';
|
||||
import { SWRResponse } from 'swr';
|
||||
|
||||
import { SchedulerSettings } from '../../interfaces/match';
|
||||
import { Tournament } from '../../interfaces/tournament';
|
||||
import { createMatchesAuto } from '../../services/round';
|
||||
|
||||
export function AutoCreateMatchesButton({
|
||||
@@ -9,7 +12,14 @@ export function AutoCreateMatchesButton({
|
||||
swrStagesResponse,
|
||||
swrUpcomingMatchesResponse,
|
||||
roundId,
|
||||
}: any) {
|
||||
schedulerSettings,
|
||||
}: {
|
||||
schedulerSettings: SchedulerSettings;
|
||||
roundId: number;
|
||||
tournamentData: Tournament;
|
||||
swrStagesResponse: SWRResponse;
|
||||
swrUpcomingMatchesResponse: SWRResponse;
|
||||
}) {
|
||||
if (roundId == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -21,9 +31,15 @@ export function AutoCreateMatchesButton({
|
||||
color="indigo"
|
||||
leftIcon={<IconTool size={24} />}
|
||||
onClick={async () => {
|
||||
await createMatchesAuto(tournamentData.id, roundId);
|
||||
swrStagesResponse.mutate();
|
||||
swrUpcomingMatchesResponse.mutate();
|
||||
await createMatchesAuto(
|
||||
tournamentData.id,
|
||||
roundId,
|
||||
schedulerSettings.eloThreshold,
|
||||
schedulerSettings.onlyRecommended,
|
||||
schedulerSettings.iterations
|
||||
);
|
||||
await swrStagesResponse.mutate();
|
||||
await swrUpcomingMatchesResponse.mutate();
|
||||
}}
|
||||
>
|
||||
Add new matches automatically
|
||||
|
||||
@@ -9,12 +9,12 @@ export default function PlayerList({
|
||||
team: TeamInterface;
|
||||
displaySettings?: BracketDisplaySettings | null;
|
||||
}) {
|
||||
if (team.players.length < 1) {
|
||||
return <i>No members</i>;
|
||||
}
|
||||
if (displaySettings != null && displaySettings.teamNamesDisplay === 'team-names') {
|
||||
return <span>{team.name}</span>;
|
||||
}
|
||||
if (team.players.length < 1) {
|
||||
return <i>No members</i>;
|
||||
}
|
||||
|
||||
const playerNames = team.players
|
||||
.map((player) => truncateString(player.name, 15))
|
||||
|
||||
@@ -12,10 +12,6 @@ import { AutoCreateMatchesButton } from '../buttons/create_matches_auto';
|
||||
import UpcomingMatchesTable from '../tables/upcoming_matches';
|
||||
import SwissSettings from './settings/ladder_fixed';
|
||||
|
||||
function StageSettings({ schedulerSettings }: { schedulerSettings: SchedulerSettings }) {
|
||||
return <SwissSettings schedulerSettings={schedulerSettings} />;
|
||||
}
|
||||
|
||||
function SchedulingSystem({
|
||||
activeStage,
|
||||
tournamentData,
|
||||
@@ -73,7 +69,7 @@ export default function Scheduler({
|
||||
</h2>
|
||||
<Grid>
|
||||
<Grid.Col span="auto">
|
||||
<StageSettings schedulerSettings={schedulerSettings} />
|
||||
<SwissSettings schedulerSettings={schedulerSettings} />
|
||||
</Grid.Col>
|
||||
<Grid.Col span="content">
|
||||
<Group position="right">
|
||||
@@ -82,6 +78,7 @@ export default function Scheduler({
|
||||
swrUpcomingMatchesResponse={swrUpcomingMatchesResponse}
|
||||
tournamentData={tournamentData}
|
||||
roundId={roundId}
|
||||
schedulerSettings={schedulerSettings}
|
||||
/>
|
||||
</Group>
|
||||
</Grid.Col>
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function ClubsTable({ swrClubsResponse }: { swrClubsResponse: SWR
|
||||
const rows = clubs
|
||||
.sort((p1: Club, p2: Club) => sortTableEntries(p1, p2, tableState))
|
||||
.map((club) => (
|
||||
<tr key={club.name}>
|
||||
<tr key={club.id}>
|
||||
<td>{club.name}</td>
|
||||
<td>
|
||||
<ClubModal swrClubsResponse={swrClubsResponse} club={club} />
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function CourtsTable({
|
||||
const rows = courts
|
||||
.sort((s1: Court, s2: Court) => sortTableEntries(s1, s2, tableState))
|
||||
.map((court) => (
|
||||
<tr key={court.name}>
|
||||
<tr key={court.id}>
|
||||
<td>{court.name}</td>
|
||||
<td>
|
||||
<DeleteButton
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function PlayersTable({
|
||||
const rows = players
|
||||
.sort((p1: Player, p2: Player) => sortTableEntries(p1, p2, tableState))
|
||||
.map((player) => (
|
||||
<tr key={player.name}>
|
||||
<tr key={player.id}>
|
||||
<td>
|
||||
{player.active ? (
|
||||
<Badge color="green">Active</Badge>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default function TeamsTable({
|
||||
const rows = teams
|
||||
.sort((p1: TeamInterface, p2: TeamInterface) => sortTableEntries(p1, p2, tableState))
|
||||
.map((team) => (
|
||||
<tr key={team.name}>
|
||||
<tr key={team.id}>
|
||||
<td>
|
||||
{team.active ? <Badge color="green">Active</Badge> : <Badge color="red">Inactive</Badge>}
|
||||
</td>
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function TournamentsTable({
|
||||
const rows = tournaments
|
||||
.sort((p1: Tournament, p2: Tournament) => sortTableEntries(p1, p2, tableState))
|
||||
.map((tournament) => (
|
||||
<tr key={tournament.name}>
|
||||
<tr key={tournament.id}>
|
||||
<td>
|
||||
<Link href={`/tournaments/${tournament.id}`}>{tournament.name}</Link>
|
||||
</td>
|
||||
|
||||
@@ -5,7 +5,6 @@ import { SWRResponse } from 'swr';
|
||||
|
||||
import { BracketDisplaySettings } from '../../interfaces/brackets';
|
||||
import { MatchCreateBodyInterface, UpcomingMatchInterface } from '../../interfaces/match';
|
||||
import { TeamInterface } from '../../interfaces/team';
|
||||
import { Tournament } from '../../interfaces/tournament';
|
||||
import { createMatch } from '../../services/match';
|
||||
import PlayerList from '../info/player_list';
|
||||
@@ -13,10 +12,6 @@ import { EmptyTableInfo } from '../utils/empty_table_info';
|
||||
import RequestErrorAlert from '../utils/error_alert';
|
||||
import TableLayout, { ThNotSortable, ThSortable, getTableState, sortTableEntries } from './table';
|
||||
|
||||
function getPlayerIds(team: TeamInterface) {
|
||||
return team.players.map((p) => p.id.toString());
|
||||
}
|
||||
|
||||
export default function UpcomingMatchesTable({
|
||||
round_id,
|
||||
tournamentData,
|
||||
@@ -62,7 +57,7 @@ export default function UpcomingMatchesTable({
|
||||
sortTableEntries(m1, m2, tableState)
|
||||
)
|
||||
.map((upcoming_match: UpcomingMatchInterface) => (
|
||||
<tr key={`${getPlayerIds(upcoming_match.team1)} - ${getPlayerIds(upcoming_match.team2)}`}>
|
||||
<tr key={`${upcoming_match.team1.id} - ${upcoming_match.team2.id}`}>
|
||||
<td>
|
||||
{upcoming_match.is_recommended ? (
|
||||
<Badge leftSection={<IconCheck size={18} />} color="blue">
|
||||
|
||||
@@ -27,7 +27,7 @@ function StageItemSelect({
|
||||
return (
|
||||
<Select
|
||||
data={data}
|
||||
label="Filter group stages"
|
||||
label="Filter on stage item"
|
||||
placeholder="No filter"
|
||||
dropdownPosition="bottom"
|
||||
clearable
|
||||
@@ -51,9 +51,6 @@ export default function Teams() {
|
||||
const stageItemTeamLookup = responseIsValid(swrStagesResponse)
|
||||
? getStageItemTeamIdsLookup(swrStagesResponse)
|
||||
: {};
|
||||
const groupStageItems = Object.values(stageItemInputLookup).filter(
|
||||
([stageItem]: [StageItemWithRounds]) => stageItem.type === 'ROUND_ROBIN'
|
||||
);
|
||||
|
||||
let teams: TeamInterface[] = swrTeamsResponse.data != null ? swrTeamsResponse.data.data : [];
|
||||
|
||||
@@ -72,7 +69,7 @@ export default function Teams() {
|
||||
<Grid.Col span={6}>
|
||||
<Group position="right">
|
||||
<StageItemSelect
|
||||
groupStageItems={groupStageItems}
|
||||
groupStageItems={Object.values(stageItemInputLookup)}
|
||||
setFilteredStageItemId={setFilteredStageItemId}
|
||||
/>
|
||||
<TeamCreateModal
|
||||
|
||||
@@ -9,9 +9,19 @@ export async function createRound(tournament_id: number, stage_item_id: number)
|
||||
.catch((response: any) => handleRequestError(response));
|
||||
}
|
||||
|
||||
export async function createMatchesAuto(tournament_id: number, round_id: number) {
|
||||
export async function createMatchesAuto(
|
||||
tournament_id: number,
|
||||
round_id: number,
|
||||
elo_diff_threshold: number,
|
||||
only_recommended: string,
|
||||
iterations: number
|
||||
) {
|
||||
return createAxios()
|
||||
.post(`tournaments/${tournament_id}/rounds/${round_id}/schedule_auto`)
|
||||
.post(`tournaments/${tournament_id}/rounds/${round_id}/schedule_auto`, {
|
||||
elo_diff_threshold,
|
||||
only_recommended,
|
||||
iterations,
|
||||
})
|
||||
.catch((response: any) => handleRequestError(response));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user