Implement autoscheduling with parameters (#348)

This commit is contained in:
Erik Vroon
2023-11-25 12:08:54 +01:00
committed by GitHub
parent 165c816a3a
commit b8cedd2a8e
12 changed files with 45 additions and 35 deletions

View File

@@ -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(

View File

@@ -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

View File

@@ -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))

View File

@@ -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>

View File

@@ -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} />

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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">

View File

@@ -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

View File

@@ -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));
}