Match management view
This commit is contained in:
@@ -54,6 +54,18 @@ public class TournamentContext : DbContext
|
|||||||
.WithMany(t => t.TournamentTeams)
|
.WithMany(t => t.TournamentTeams)
|
||||||
.HasForeignKey(tt => tt.TeamId)
|
.HasForeignKey(tt => tt.TeamId)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Match>()
|
||||||
|
.HasOne(m => m.WinnerMatch)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(m => m.WinnerMatchId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Match>()
|
||||||
|
.HasOne(m => m.LoserMatch)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(m => m.LoserMatchId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+434
@@ -0,0 +1,434 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using TournamentOrganizer;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TournamentContext))]
|
||||||
|
[Migration("20260506122131_AddMatchBracketNavigation")]
|
||||||
|
partial class AddMatchBracketNavigation
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "10.0.5");
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Event", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("End")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Start")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Events");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Game", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("S1GroupAdvances")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1Groups")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("S1RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S2RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Games");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("LoserMatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("LoserSlot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("WinnerMatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("WinnerSlot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LoserMatchId");
|
||||||
|
|
||||||
|
b.HasIndex("TournamentId");
|
||||||
|
|
||||||
|
b.HasIndex("WinnerMatchId");
|
||||||
|
|
||||||
|
b.ToTable("Matches");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Player", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Contact")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("Players");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RoundId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("RoundId", "PlayerId");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId");
|
||||||
|
|
||||||
|
b.ToTable("PlayerParticipants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("MatchId");
|
||||||
|
|
||||||
|
b.ToTable("Rounds");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("LeaderId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LeaderId");
|
||||||
|
|
||||||
|
b.ToTable("Teams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("MatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Score")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Seed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("MatchId", "TeamId");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("TeamParticipants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("End")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("EventId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GameId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1GroupAdvances")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1Groups")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("S1RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S2RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Start")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("EventId");
|
||||||
|
|
||||||
|
b.HasIndex("GameId");
|
||||||
|
|
||||||
|
b.ToTable("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Seed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("TournamentId", "TeamId");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "LoserMatch")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LoserMatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "WinnerMatch")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("WinnerMatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("LoserMatch");
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
|
||||||
|
b.Navigation("WinnerMatch");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Player", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("Players")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Player", "Player")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PlayerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Round", "Round")
|
||||||
|
.WithMany("Players")
|
||||||
|
.HasForeignKey("RoundId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Player");
|
||||||
|
|
||||||
|
b.Navigation("Round");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "Match")
|
||||||
|
.WithMany("Rounds")
|
||||||
|
.HasForeignKey("MatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Match");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Player", "Leader")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LeaderId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Leader");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "Round")
|
||||||
|
.WithMany("Teams")
|
||||||
|
.HasForeignKey("MatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("Matches")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Round");
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Event", "Event")
|
||||||
|
.WithMany("Tournaments")
|
||||||
|
.HasForeignKey("EventId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Game", "Game")
|
||||||
|
.WithMany("Tournaments")
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Event");
|
||||||
|
|
||||||
|
b.Navigation("Game");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Event", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Game", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Rounds");
|
||||||
|
|
||||||
|
b.Navigation("Teams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Players");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Matches");
|
||||||
|
|
||||||
|
b.Navigation("Players");
|
||||||
|
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddMatchBracketNavigation : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "LoserMatchId",
|
||||||
|
table: "Matches",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "LoserSlot",
|
||||||
|
table: "Matches",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "WinnerMatchId",
|
||||||
|
table: "Matches",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "WinnerSlot",
|
||||||
|
table: "Matches",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Matches_LoserMatchId",
|
||||||
|
table: "Matches",
|
||||||
|
column: "LoserMatchId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Matches_WinnerMatchId",
|
||||||
|
table: "Matches",
|
||||||
|
column: "WinnerMatchId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Matches_Matches_LoserMatchId",
|
||||||
|
table: "Matches",
|
||||||
|
column: "LoserMatchId",
|
||||||
|
principalTable: "Matches",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Matches_Matches_WinnerMatchId",
|
||||||
|
table: "Matches",
|
||||||
|
column: "WinnerMatchId",
|
||||||
|
principalTable: "Matches",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Matches_Matches_LoserMatchId",
|
||||||
|
table: "Matches");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Matches_Matches_WinnerMatchId",
|
||||||
|
table: "Matches");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Matches_LoserMatchId",
|
||||||
|
table: "Matches");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Matches_WinnerMatchId",
|
||||||
|
table: "Matches");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LoserMatchId",
|
||||||
|
table: "Matches");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LoserSlot",
|
||||||
|
table: "Matches");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "WinnerMatchId",
|
||||||
|
table: "Matches");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "WinnerSlot",
|
||||||
|
table: "Matches");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+437
@@ -0,0 +1,437 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using TournamentOrganizer;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TournamentContext))]
|
||||||
|
[Migration("20260506131153_AddTeamParticipantSlot")]
|
||||||
|
partial class AddTeamParticipantSlot
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "10.0.5");
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Event", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("End")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Start")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Events");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Game", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("S1GroupAdvances")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1Groups")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("S1RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S2RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Games");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("LoserMatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("LoserSlot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("WinnerMatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("WinnerSlot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LoserMatchId");
|
||||||
|
|
||||||
|
b.HasIndex("TournamentId");
|
||||||
|
|
||||||
|
b.HasIndex("WinnerMatchId");
|
||||||
|
|
||||||
|
b.ToTable("Matches");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Player", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Contact")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("Players");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RoundId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("RoundId", "PlayerId");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId");
|
||||||
|
|
||||||
|
b.ToTable("PlayerParticipants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("MatchId");
|
||||||
|
|
||||||
|
b.ToTable("Rounds");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("LeaderId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LeaderId");
|
||||||
|
|
||||||
|
b.ToTable("Teams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("MatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Score")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Seed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Slot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("MatchId", "TeamId");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("TeamParticipants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("End")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("EventId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GameId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1GroupAdvances")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1Groups")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("S1RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S2RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Start")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("EventId");
|
||||||
|
|
||||||
|
b.HasIndex("GameId");
|
||||||
|
|
||||||
|
b.ToTable("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Seed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("TournamentId", "TeamId");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "LoserMatch")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LoserMatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "WinnerMatch")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("WinnerMatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("LoserMatch");
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
|
||||||
|
b.Navigation("WinnerMatch");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Player", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("Players")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Player", "Player")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PlayerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Round", "Round")
|
||||||
|
.WithMany("Players")
|
||||||
|
.HasForeignKey("RoundId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Player");
|
||||||
|
|
||||||
|
b.Navigation("Round");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "Match")
|
||||||
|
.WithMany("Rounds")
|
||||||
|
.HasForeignKey("MatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Match");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Player", "Leader")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LeaderId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Leader");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "Round")
|
||||||
|
.WithMany("Teams")
|
||||||
|
.HasForeignKey("MatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("Matches")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Round");
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Event", "Event")
|
||||||
|
.WithMany("Tournaments")
|
||||||
|
.HasForeignKey("EventId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Game", "Game")
|
||||||
|
.WithMany("Tournaments")
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Event");
|
||||||
|
|
||||||
|
b.Navigation("Game");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Event", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Game", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Rounds");
|
||||||
|
|
||||||
|
b.Navigation("Teams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Players");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Matches");
|
||||||
|
|
||||||
|
b.Navigation("Players");
|
||||||
|
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddTeamParticipantSlot : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "Slot",
|
||||||
|
table: "TeamParticipants",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Slot",
|
||||||
|
table: "TeamParticipants");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+428
@@ -0,0 +1,428 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using TournamentOrganizer;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TournamentContext))]
|
||||||
|
[Migration("20260506134330_RemoveUnnecessarySlots")]
|
||||||
|
partial class RemoveUnnecessarySlots
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "10.0.5");
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Event", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("End")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Start")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Events");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Game", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("S1GroupAdvances")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1Groups")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("S1RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S2RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Games");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("LoserMatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("WinnerMatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LoserMatchId");
|
||||||
|
|
||||||
|
b.HasIndex("TournamentId");
|
||||||
|
|
||||||
|
b.HasIndex("WinnerMatchId");
|
||||||
|
|
||||||
|
b.ToTable("Matches");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Player", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Contact")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("Players");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RoundId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PlayerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("RoundId", "PlayerId");
|
||||||
|
|
||||||
|
b.HasIndex("PlayerId");
|
||||||
|
|
||||||
|
b.ToTable("PlayerParticipants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("MatchId");
|
||||||
|
|
||||||
|
b.ToTable("Rounds");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("LeaderId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LeaderId");
|
||||||
|
|
||||||
|
b.ToTable("Teams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("MatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Score")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Seed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("MatchId", "TeamId");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("TeamParticipants");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("End")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("EventId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GameId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1GroupAdvances")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S1Groups")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("S1RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("S2RuleSet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Start")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("EventId");
|
||||||
|
|
||||||
|
b.HasIndex("GameId");
|
||||||
|
|
||||||
|
b.ToTable("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("TeamId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Seed")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("TournamentId", "TeamId");
|
||||||
|
|
||||||
|
b.HasIndex("TeamId");
|
||||||
|
|
||||||
|
b.ToTable("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "LoserMatch")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LoserMatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "WinnerMatch")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("WinnerMatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("LoserMatch");
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
|
||||||
|
b.Navigation("WinnerMatch");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Player", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("Players")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.PlayerParticipant", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Player", "Player")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PlayerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Round", "Round")
|
||||||
|
.WithMany("Players")
|
||||||
|
.HasForeignKey("RoundId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Player");
|
||||||
|
|
||||||
|
b.Navigation("Round");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "Match")
|
||||||
|
.WithMany("Rounds")
|
||||||
|
.HasForeignKey("MatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Match");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Player", "Leader")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LeaderId")
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
b.Navigation("Leader");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "Round")
|
||||||
|
.WithMany("Teams")
|
||||||
|
.HasForeignKey("MatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("Matches")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Round");
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Event", "Event")
|
||||||
|
.WithMany("Tournaments")
|
||||||
|
.HasForeignKey("EventId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Game", "Game")
|
||||||
|
.WithMany("Tournaments")
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Event");
|
||||||
|
|
||||||
|
b.Navigation("Game");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.TournamentTeam", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Team", "Team")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TeamId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
|
.WithMany("TournamentTeams")
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Team");
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Event", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Game", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Rounds");
|
||||||
|
|
||||||
|
b.Navigation("Teams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Players");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Matches");
|
||||||
|
|
||||||
|
b.Navigation("Players");
|
||||||
|
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class RemoveUnnecessarySlots : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Slot",
|
||||||
|
table: "TeamParticipants");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LoserSlot",
|
||||||
|
table: "Matches");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "WinnerSlot",
|
||||||
|
table: "Matches");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "Slot",
|
||||||
|
table: "TeamParticipants",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "LoserSlot",
|
||||||
|
table: "Matches",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "WinnerSlot",
|
||||||
|
table: "Matches",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,13 +75,23 @@ namespace TournamentOrganizer.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("LoserMatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<int>("TournamentId")
|
b.Property<int>("TournamentId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("WinnerMatchId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LoserMatchId");
|
||||||
|
|
||||||
b.HasIndex("TournamentId");
|
b.HasIndex("TournamentId");
|
||||||
|
|
||||||
|
b.HasIndex("WinnerMatchId");
|
||||||
|
|
||||||
b.ToTable("Matches");
|
b.ToTable("Matches");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -243,13 +253,27 @@ namespace TournamentOrganizer.Migrations
|
|||||||
|
|
||||||
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
{
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "LoserMatch")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LoserMatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("TournamentId")
|
.HasForeignKey("TournamentId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Match", "WinnerMatch")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("WinnerMatchId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.Navigation("LoserMatch");
|
||||||
|
|
||||||
b.Navigation("Tournament");
|
b.Navigation("Tournament");
|
||||||
|
|
||||||
|
b.Navigation("WinnerMatch");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TournamentOrganizer.Models.Player", b =>
|
modelBuilder.Entity("TournamentOrganizer.Models.Player", b =>
|
||||||
@@ -272,7 +296,7 @@ namespace TournamentOrganizer.Migrations
|
|||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
b.HasOne("TournamentOrganizer.Models.Round", "Round")
|
b.HasOne("TournamentOrganizer.Models.Round", "Round")
|
||||||
.WithMany()
|
.WithMany("Players")
|
||||||
.HasForeignKey("RoundId")
|
.HasForeignKey("RoundId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
@@ -285,7 +309,7 @@ namespace TournamentOrganizer.Migrations
|
|||||||
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("TournamentOrganizer.Models.Match", "Match")
|
b.HasOne("TournamentOrganizer.Models.Match", "Match")
|
||||||
.WithMany()
|
.WithMany("Rounds")
|
||||||
.HasForeignKey("MatchId")
|
.HasForeignKey("MatchId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
@@ -306,7 +330,7 @@ namespace TournamentOrganizer.Migrations
|
|||||||
modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b =>
|
modelBuilder.Entity("TournamentOrganizer.Models.TeamParticipant", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("TournamentOrganizer.Models.Match", "Round")
|
b.HasOne("TournamentOrganizer.Models.Match", "Round")
|
||||||
.WithMany()
|
.WithMany("Teams")
|
||||||
.HasForeignKey("MatchId")
|
.HasForeignKey("MatchId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
@@ -370,6 +394,18 @@ namespace TournamentOrganizer.Migrations
|
|||||||
b.Navigation("Tournaments");
|
b.Navigation("Tournaments");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Match", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Rounds");
|
||||||
|
|
||||||
|
b.Navigation("Teams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Round", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Players");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Matches");
|
b.Navigation("Matches");
|
||||||
|
|||||||
@@ -11,8 +11,13 @@ public class Match
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int TournamentId { get; set; }
|
public int TournamentId { get; set; }
|
||||||
|
|
||||||
|
public int? WinnerMatchId { get; set; }
|
||||||
|
public int? LoserMatchId { get; set; }
|
||||||
|
|
||||||
public List<TeamParticipant> Teams { get; set; } = [];
|
public List<TeamParticipant> Teams { get; set; } = [];
|
||||||
public List<Round> Rounds { get; set; } = [];
|
public List<Round> Rounds { get; set; } = [];
|
||||||
public Tournament Tournament { get; set; } = null!;
|
public Tournament Tournament { get; set; } = null!;
|
||||||
|
public Match? WinnerMatch { get; set; }
|
||||||
|
public Match? LoserMatch { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -59,6 +59,15 @@ public partial class MainViewModel : ViewModelBase
|
|||||||
Title = "Tournament Management";
|
Title = "Tournament Management";
|
||||||
await tournamentsVm.LoadTournaments();
|
await tournamentsVm.LoadTournaments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task NavigateToMatches()
|
||||||
|
{
|
||||||
|
var matchesVm = new MatchesViewModel();
|
||||||
|
CurrentView = matchesVm;
|
||||||
|
Title = "Match Management";
|
||||||
|
await matchesVm.LoadEvents();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class HomeViewModel : ViewModelBase
|
public partial class HomeViewModel : ViewModelBase
|
||||||
|
|||||||
@@ -0,0 +1,526 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using TournamentOrganizer;
|
||||||
|
using TournamentOrganizer.Models;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.ViewModels;
|
||||||
|
|
||||||
|
public partial class MatchesViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
private readonly TournamentContext _context;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<EventOption> _availableEvents = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private EventOption? _selectedEvent;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<TournamentOption> _availableTournaments = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private TournamentOption? _selectedTournament;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<MatchDisplay> _matches = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private MatchDisplay? _selectedMatch;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<TeamParticipantDisplay> _matchTeams = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<RoundDisplay> _rounds = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private RoundDisplay? _selectedRound;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _eventFilterSearch = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _tournamentFilterSearch = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isEventDropdownOpen;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isTournamentDropdownOpen;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _statusMessage = string.Empty;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<EventOption> _filteredEvents = [];
|
||||||
|
public ObservableCollection<EventOption> FilteredEvents => _filteredEvents;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<TournamentOption> _filteredTournaments = [];
|
||||||
|
public ObservableCollection<TournamentOption> FilteredTournaments => _filteredTournaments;
|
||||||
|
|
||||||
|
public bool IsTournamentFilterEnabled => SelectedEvent != null;
|
||||||
|
|
||||||
|
public bool CanCreateRound => Rounds.Count == 0 || Rounds.All(r => r.State == RoundState.Finished);
|
||||||
|
|
||||||
|
public bool CanStartRound => SelectedRound != null && SelectedRound.State == RoundState.Waiting;
|
||||||
|
|
||||||
|
public bool CanAwardVictory => SelectedRound != null && SelectedRound.State == RoundState.Started;
|
||||||
|
|
||||||
|
public MatchesViewModel()
|
||||||
|
{
|
||||||
|
_context = new TournamentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadEvents()
|
||||||
|
{
|
||||||
|
var events = await _context.Events
|
||||||
|
.Include(e => e.Tournaments)
|
||||||
|
.ThenInclude(t => t.Game)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
AvailableEvents.Clear();
|
||||||
|
_filteredEvents.Clear();
|
||||||
|
foreach (var e in events)
|
||||||
|
{
|
||||||
|
var option = new EventOption(e);
|
||||||
|
AvailableEvents.Add(option);
|
||||||
|
_filteredEvents.Add(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAvailableTournaments();
|
||||||
|
UpdateFilteredTournaments();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAvailableTournaments()
|
||||||
|
{
|
||||||
|
AvailableTournaments.Clear();
|
||||||
|
if (SelectedEvent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var t in SelectedEvent.Event.Tournaments)
|
||||||
|
{
|
||||||
|
AvailableTournaments.Add(new TournamentOption(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadMatches()
|
||||||
|
{
|
||||||
|
if (SelectedTournament == null)
|
||||||
|
{
|
||||||
|
Matches.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int? selectedMatchId = SelectedMatch?.Id;
|
||||||
|
|
||||||
|
var matches = await _context.Matches
|
||||||
|
.Where(m => m.TournamentId == SelectedTournament.Tournament.Id)
|
||||||
|
.Include(m => m.Teams)
|
||||||
|
.ThenInclude(tp => tp.Team)
|
||||||
|
.Include(m => m.Rounds)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
Matches.Clear();
|
||||||
|
MatchDisplay? newSelectedMatch = null;
|
||||||
|
foreach (var match in matches)
|
||||||
|
{
|
||||||
|
var matchDisplay = new MatchDisplay(match);
|
||||||
|
Matches.Add(matchDisplay);
|
||||||
|
if (match.Id == selectedMatchId)
|
||||||
|
{
|
||||||
|
newSelectedMatch = matchDisplay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newSelectedMatch != null)
|
||||||
|
{
|
||||||
|
SelectedMatch = newSelectedMatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadMatchDetails()
|
||||||
|
{
|
||||||
|
if (SelectedMatch == null)
|
||||||
|
{
|
||||||
|
MatchTeams.Clear();
|
||||||
|
Rounds.Clear();
|
||||||
|
_lastLoadedMatchId = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastLoadedMatchId = SelectedMatch.Id;
|
||||||
|
|
||||||
|
var match = await _context.Matches
|
||||||
|
.Where(m => m.Id == SelectedMatch.Id)
|
||||||
|
.Include(m => m.Teams)
|
||||||
|
.ThenInclude(tp => tp.Team)
|
||||||
|
.Include(m => m.Rounds)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (match == null)
|
||||||
|
{
|
||||||
|
MatchTeams.Clear();
|
||||||
|
Rounds.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatchTeams.Clear();
|
||||||
|
foreach (var team in match.Teams)
|
||||||
|
{
|
||||||
|
MatchTeams.Add(new TeamParticipantDisplay(team));
|
||||||
|
}
|
||||||
|
|
||||||
|
Rounds.Clear();
|
||||||
|
foreach (var round in match.Rounds)
|
||||||
|
{
|
||||||
|
Rounds.Add(new RoundDisplay(round));
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPropertyChanged(nameof(CanCreateRound));
|
||||||
|
OnPropertyChanged(nameof(CanStartRound));
|
||||||
|
OnPropertyChanged(nameof(CanAwardVictory));
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedEventChanged(EventOption? value)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(IsTournamentFilterEnabled));
|
||||||
|
UpdateAvailableTournaments();
|
||||||
|
UpdateFilteredTournaments();
|
||||||
|
SelectedTournament = null;
|
||||||
|
Matches.Clear();
|
||||||
|
MatchTeams.Clear();
|
||||||
|
Rounds.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedTournamentChanged(TournamentOption? value)
|
||||||
|
{
|
||||||
|
_ = LoadMatches();
|
||||||
|
MatchTeams.Clear();
|
||||||
|
Rounds.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int? _lastLoadedMatchId;
|
||||||
|
|
||||||
|
partial void OnSelectedMatchChanged(MatchDisplay? value)
|
||||||
|
{
|
||||||
|
if (value?.Id == _lastLoadedMatchId)
|
||||||
|
return;
|
||||||
|
_ = LoadMatchDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedRoundChanged(RoundDisplay? value)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(CanStartRound));
|
||||||
|
OnPropertyChanged(nameof(CanAwardVictory));
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnEventFilterSearchChanged(string value) => UpdateFilteredEvents();
|
||||||
|
|
||||||
|
partial void OnTournamentFilterSearchChanged(string value) => UpdateFilteredTournaments();
|
||||||
|
|
||||||
|
private void UpdateFilteredEvents()
|
||||||
|
{
|
||||||
|
_filteredEvents.Clear();
|
||||||
|
foreach (var e in AvailableEvents.Where(e => string.IsNullOrWhiteSpace(EventFilterSearch) || e.DisplayName.ToLower().Contains(EventFilterSearch.ToLower())))
|
||||||
|
{
|
||||||
|
_filteredEvents.Add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFilteredTournaments()
|
||||||
|
{
|
||||||
|
_filteredTournaments.Clear();
|
||||||
|
if (SelectedEvent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var t in AvailableTournaments.Where(t => string.IsNullOrWhiteSpace(TournamentFilterSearch) || t.DisplayName.ToLower().Contains(TournamentFilterSearch.ToLower())))
|
||||||
|
{
|
||||||
|
_filteredTournaments.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectEventFilter(EventOption option)
|
||||||
|
{
|
||||||
|
SelectedEvent = option;
|
||||||
|
IsEventDropdownOpen = false;
|
||||||
|
EventFilterSearch = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearEventFilter()
|
||||||
|
{
|
||||||
|
SelectedEvent = null;
|
||||||
|
EventFilterSearch = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectTournamentFilter(TournamentOption option)
|
||||||
|
{
|
||||||
|
SelectedTournament = option;
|
||||||
|
IsTournamentDropdownOpen = false;
|
||||||
|
TournamentFilterSearch = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearTournamentFilter()
|
||||||
|
{
|
||||||
|
SelectedTournament = null;
|
||||||
|
TournamentFilterSearch = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task CreateRound()
|
||||||
|
{
|
||||||
|
if (SelectedMatch == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a match first";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var match = await _context.Matches
|
||||||
|
.Where(m => m.Id == SelectedMatch.Id)
|
||||||
|
.Include(m => m.Rounds)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (match == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Match not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match.Rounds.Any(r => r.State != RoundState.Finished))
|
||||||
|
{
|
||||||
|
StatusMessage = "All rounds must be finished before creating a new round";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var round = new Round
|
||||||
|
{
|
||||||
|
MatchId = match.Id,
|
||||||
|
Match = match,
|
||||||
|
State = RoundState.Waiting,
|
||||||
|
Players = []
|
||||||
|
};
|
||||||
|
|
||||||
|
match.Rounds.Add(round);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
StatusMessage = "Round created";
|
||||||
|
await LoadMatches();
|
||||||
|
await LoadMatchDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task StartRound()
|
||||||
|
{
|
||||||
|
if (SelectedRound == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a round to start";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var round = await _context.Rounds.FindAsync(SelectedRound.Id);
|
||||||
|
if (round == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Round not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (round.State != RoundState.Waiting)
|
||||||
|
{
|
||||||
|
StatusMessage = "Round must be in Waiting state to start";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
round.State = RoundState.Started;
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
StatusMessage = "Round started";
|
||||||
|
await LoadMatches();
|
||||||
|
await LoadMatchDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task AwardVictory(object? parameter)
|
||||||
|
{
|
||||||
|
if (SelectedRound == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a round first";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedMatch == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "No match selected";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedRound.State != RoundState.Started)
|
||||||
|
{
|
||||||
|
StatusMessage = "Round must be in Started state to award victory";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(parameter?.ToString(), out int teamIndex))
|
||||||
|
{
|
||||||
|
StatusMessage = "Invalid team index";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var round = await _context.Rounds.FindAsync(SelectedRound.Id);
|
||||||
|
if (round == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Round not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
round.State = RoundState.Finished;
|
||||||
|
|
||||||
|
var match = await _context.Matches
|
||||||
|
.Where(m => m.Id == SelectedMatch.Id)
|
||||||
|
.Include(m => m.Teams)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (match != null && teamIndex >= 0 && teamIndex < match.Teams.Count)
|
||||||
|
{
|
||||||
|
match.Teams[teamIndex].Score++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
// Promote winner and loser to next matches
|
||||||
|
await PromoteTeams(match);
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var teamName = teamIndex < MatchTeams.Count ? MatchTeams[teamIndex].TeamName : "Unknown";
|
||||||
|
StatusMessage = $"Victory awarded to {teamName}";
|
||||||
|
await LoadMatches();
|
||||||
|
await LoadMatchDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PromoteTeams(Match? match)
|
||||||
|
{
|
||||||
|
if (match == null || match.Teams.Count < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Determine winner (higher score) and loser
|
||||||
|
var sortedTeams = match.Teams.OrderByDescending(t => t.Score).ToList();
|
||||||
|
var winner = sortedTeams[0];
|
||||||
|
var loser = sortedTeams[1];
|
||||||
|
|
||||||
|
// Promote winner to WinnerMatch
|
||||||
|
if (match.WinnerMatchId.HasValue)
|
||||||
|
{
|
||||||
|
var winnerMatch = await _context.Matches.FindAsync(match.WinnerMatchId.Value);
|
||||||
|
if (winnerMatch != null && !winnerMatch.Teams.Any(t => t.TeamId == winner.TeamId))
|
||||||
|
{
|
||||||
|
winnerMatch.Teams.Add(new TeamParticipant
|
||||||
|
{
|
||||||
|
TeamId = winner.TeamId,
|
||||||
|
Seed = winner.Seed,
|
||||||
|
Score = 0,
|
||||||
|
Team = winner.Team,
|
||||||
|
MatchId = winnerMatch.Id,
|
||||||
|
Round = null!
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if winnerMatch now has a bye (only 1 team) and needs recursive promotion
|
||||||
|
if (winnerMatch.Teams.Count == 1 && winnerMatch.WinnerMatchId.HasValue)
|
||||||
|
{
|
||||||
|
await PromoteRecursive(winnerMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Promote loser to LoserMatch (for double elimination)
|
||||||
|
// Only if this match has a LoserMatchId (meaning it's a winner bracket match)
|
||||||
|
if (match.LoserMatchId.HasValue)
|
||||||
|
{
|
||||||
|
var loserMatch = await _context.Matches.FindAsync(match.LoserMatchId.Value);
|
||||||
|
if (loserMatch != null && !loserMatch.Teams.Any(t => t.TeamId == loser.TeamId))
|
||||||
|
{
|
||||||
|
loserMatch.Teams.Add(new TeamParticipant
|
||||||
|
{
|
||||||
|
TeamId = loser.TeamId,
|
||||||
|
Seed = loser.Seed,
|
||||||
|
Score = 0,
|
||||||
|
Team = loser.Team,
|
||||||
|
MatchId = loserMatch.Id,
|
||||||
|
Round = null!
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if loserMatch now has a bye and needs recursive promotion
|
||||||
|
if (loserMatch.Teams.Count == 1 && loserMatch.WinnerMatchId.HasValue)
|
||||||
|
{
|
||||||
|
await PromoteRecursive(loserMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PromoteRecursive(Match match)
|
||||||
|
{
|
||||||
|
if (match.Teams.Count != 1 || !match.WinnerMatchId.HasValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var team = match.Teams.First();
|
||||||
|
var nextMatch = await _context.Matches.FindAsync(match.WinnerMatchId.Value);
|
||||||
|
|
||||||
|
if (nextMatch != null && !nextMatch.Teams.Any(t => t.TeamId == team.TeamId))
|
||||||
|
{
|
||||||
|
nextMatch.Teams.Add(new TeamParticipant
|
||||||
|
{
|
||||||
|
TeamId = team.TeamId,
|
||||||
|
Seed = team.Seed,
|
||||||
|
Score = 0,
|
||||||
|
Team = team.Team,
|
||||||
|
MatchId = nextMatch.Id,
|
||||||
|
Round = null!
|
||||||
|
});
|
||||||
|
|
||||||
|
// Continue recursive promotion if needed
|
||||||
|
if (nextMatch.Teams.Count == 1 && nextMatch.WinnerMatchId.HasValue)
|
||||||
|
{
|
||||||
|
await PromoteRecursive(nextMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TeamParticipantDisplay
|
||||||
|
{
|
||||||
|
public int TeamId { get; set; }
|
||||||
|
public string TeamName { get; set; } = string.Empty;
|
||||||
|
public int Score { get; set; }
|
||||||
|
public int Seed { get; set; }
|
||||||
|
|
||||||
|
public TeamParticipantDisplay() { }
|
||||||
|
|
||||||
|
public TeamParticipantDisplay(TeamParticipant tp)
|
||||||
|
{
|
||||||
|
TeamId = tp.TeamId;
|
||||||
|
TeamName = tp.Team.Name;
|
||||||
|
Score = tp.Score;
|
||||||
|
Seed = tp.Seed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RoundDisplay
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public RoundState State { get; set; }
|
||||||
|
|
||||||
|
public RoundDisplay() { }
|
||||||
|
|
||||||
|
public RoundDisplay(Round round)
|
||||||
|
{
|
||||||
|
Id = round.Id;
|
||||||
|
State = round.State;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -489,9 +489,111 @@ public partial class TournamentsViewModel : ViewModelBase
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-promote teams with byes (TBD opponents with no parent match)
|
||||||
|
await AutoPromoteByeTeams(tournament.Id);
|
||||||
|
|
||||||
await LoadMatches();
|
await LoadMatches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task AutoPromoteByeTeams(int tournamentId)
|
||||||
|
{
|
||||||
|
// Find matches where a team has a TBD opponent (only 1 team in match) and no parent match
|
||||||
|
var matchesToPromote = await _context.Matches
|
||||||
|
.Where(m => m.TournamentId == tournamentId && m.Teams.Count == 1)
|
||||||
|
.Include(m => m.Teams)
|
||||||
|
.Include(m => m.WinnerMatch)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (var match in matchesToPromote)
|
||||||
|
{
|
||||||
|
// Check if this match has no incoming teams (no parent matches pointing to it)
|
||||||
|
var hasParent = await _context.Matches
|
||||||
|
.AnyAsync(m => m.WinnerMatchId == match.Id || m.LoserMatchId == match.Id);
|
||||||
|
|
||||||
|
if (!hasParent && match.WinnerMatchId.HasValue)
|
||||||
|
{
|
||||||
|
// This is a bye match - promote the team to the next match
|
||||||
|
var team = match.Teams.First();
|
||||||
|
var winnerMatch = match.WinnerMatch;
|
||||||
|
if (winnerMatch != null)
|
||||||
|
{
|
||||||
|
// Add team to the winner match (position doesn't matter)
|
||||||
|
if (!winnerMatch.Teams.Any(t => t.TeamId == team.TeamId))
|
||||||
|
{
|
||||||
|
winnerMatch.Teams.Add(new TeamParticipant
|
||||||
|
{
|
||||||
|
TeamId = team.TeamId,
|
||||||
|
Seed = team.Seed,
|
||||||
|
Score = 0,
|
||||||
|
Team = team.Team,
|
||||||
|
MatchId = winnerMatch.Id,
|
||||||
|
Round = null!
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the current match's round as finished since it was a bye
|
||||||
|
if (match.Rounds.Any())
|
||||||
|
{
|
||||||
|
match.Rounds.Last().State = RoundState.Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively check if the destination match now has all teams and is also a bye
|
||||||
|
if (winnerMatch.Teams.Count == 1)
|
||||||
|
{
|
||||||
|
var winnerHasParent = await _context.Matches
|
||||||
|
.AnyAsync(m => m.WinnerMatchId == winnerMatch.Id || m.LoserMatchId == winnerMatch.Id);
|
||||||
|
|
||||||
|
if (!winnerHasParent && winnerMatch.WinnerMatchId.HasValue)
|
||||||
|
{
|
||||||
|
// Recursively promote
|
||||||
|
await PromoteRecursive(winnerMatch, tournamentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PromoteRecursive(Match match, int tournamentId)
|
||||||
|
{
|
||||||
|
if (match.Teams.Count != 1 || !match.WinnerMatchId.HasValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var team = match.Teams.First();
|
||||||
|
var winnerMatch = await _context.Matches
|
||||||
|
.FindAsync(match.WinnerMatchId.Value);
|
||||||
|
|
||||||
|
if (winnerMatch != null)
|
||||||
|
{
|
||||||
|
// Add team to the winner match (position doesn't matter)
|
||||||
|
if (!winnerMatch.Teams.Any(t => t.TeamId == team.TeamId))
|
||||||
|
{
|
||||||
|
winnerMatch.Teams.Add(new TeamParticipant
|
||||||
|
{
|
||||||
|
TeamId = team.TeamId,
|
||||||
|
Seed = team.Seed,
|
||||||
|
Score = 0,
|
||||||
|
Team = team.Team,
|
||||||
|
MatchId = winnerMatch.Id,
|
||||||
|
Round = null!
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match.Rounds.Any())
|
||||||
|
{
|
||||||
|
match.Rounds.Last().State = RoundState.Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we need to continue promoting
|
||||||
|
if (winnerMatch.Teams.Count == 1 && winnerMatch.WinnerMatchId.HasValue)
|
||||||
|
{
|
||||||
|
await PromoteRecursive(winnerMatch, tournamentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task GenerateSingleElimination(Tournament tournament, List<TeamParticipant> teams)
|
private async Task GenerateSingleElimination(Tournament tournament, List<TeamParticipant> teams)
|
||||||
{
|
{
|
||||||
int numTeams = teams.Count;
|
int numTeams = teams.Count;
|
||||||
@@ -504,6 +606,7 @@ public partial class TournamentsViewModel : ViewModelBase
|
|||||||
int totalRounds = (int)Math.Log2(nextPowerOf2);
|
int totalRounds = (int)Math.Log2(nextPowerOf2);
|
||||||
var allMatches = new List<Match>();
|
var allMatches = new List<Match>();
|
||||||
|
|
||||||
|
// Create all matches first
|
||||||
for (int round = 0; round < totalRounds; round++)
|
for (int round = 0; round < totalRounds; round++)
|
||||||
{
|
{
|
||||||
int matchesInRound = nextPowerOf2 / (int)Math.Pow(2, round + 1);
|
int matchesInRound = nextPowerOf2 / (int)Math.Pow(2, round + 1);
|
||||||
@@ -511,7 +614,24 @@ public partial class TournamentsViewModel : ViewModelBase
|
|||||||
for (int i = 0; i < matchesInRound; i++)
|
for (int i = 0; i < matchesInRound; i++)
|
||||||
{
|
{
|
||||||
var match = CreateMatch(tournament);
|
var match = CreateMatch(tournament);
|
||||||
|
allMatches.Add(match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Matches.AddRange(allMatches);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
// Now set up bracket navigation
|
||||||
|
int matchIndex = 0;
|
||||||
|
for (int round = 0; round < totalRounds; round++)
|
||||||
|
{
|
||||||
|
int matchesInRound = nextPowerOf2 / (int)Math.Pow(2, round + 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < matchesInRound; i++)
|
||||||
|
{
|
||||||
|
var match = allMatches[matchIndex];
|
||||||
|
|
||||||
|
// Set up teams for first round
|
||||||
if (round == 0)
|
if (round == 0)
|
||||||
{
|
{
|
||||||
int highSeed = i + 1;
|
int highSeed = i + 1;
|
||||||
@@ -523,11 +643,25 @@ public partial class TournamentsViewModel : ViewModelBase
|
|||||||
AddTeamToMatch(match, teams[lowSeed - 1], lowSeed);
|
AddTeamToMatch(match, teams[lowSeed - 1], lowSeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
allMatches.Add(match);
|
// Set winner goes to next round match
|
||||||
|
if (round < totalRounds - 1)
|
||||||
|
{
|
||||||
|
int nextRoundMatches = nextPowerOf2 / (int)Math.Pow(2, round + 2);
|
||||||
|
int nextMatchIndex = 0;
|
||||||
|
for (int r = 0; r <= round; r++)
|
||||||
|
{
|
||||||
|
nextMatchIndex += nextPowerOf2 / (int)Math.Pow(2, r + 1);
|
||||||
|
}
|
||||||
|
int nextMatchInRound = i / 2;
|
||||||
|
int targetMatchIndex = nextMatchIndex + nextMatchInRound;
|
||||||
|
|
||||||
|
match.WinnerMatchId = allMatches[targetMatchIndex].Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
matchIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.Matches.AddRange(allMatches);
|
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,6 +677,7 @@ public partial class TournamentsViewModel : ViewModelBase
|
|||||||
int wbRounds = (int)Math.Log2(nextPowerOf2);
|
int wbRounds = (int)Math.Log2(nextPowerOf2);
|
||||||
var allMatches = new List<Match>();
|
var allMatches = new List<Match>();
|
||||||
|
|
||||||
|
// Create winners bracket matches
|
||||||
var wbMatchesByRound = new List<List<Match>>();
|
var wbMatchesByRound = new List<List<Match>>();
|
||||||
for (int r = 0; r < wbRounds; r++)
|
for (int r = 0; r < wbRounds; r++)
|
||||||
{
|
{
|
||||||
@@ -556,9 +691,10 @@ public partial class TournamentsViewModel : ViewModelBase
|
|||||||
wbMatchesByRound.Add(roundMatches);
|
wbMatchesByRound.Add(roundMatches);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create losers bracket matches
|
||||||
|
var lbMatchesByRound = new List<List<Match>>();
|
||||||
if (numTeams > 2)
|
if (numTeams > 2)
|
||||||
{
|
{
|
||||||
var lbMatchesByRound = new List<List<Match>>();
|
|
||||||
for (int r = 0; r < wbRounds - 1; r++)
|
for (int r = 0; r < wbRounds - 1; r++)
|
||||||
{
|
{
|
||||||
int matchesInRound = nextPowerOf2 / 4;
|
int matchesInRound = nextPowerOf2 / 4;
|
||||||
@@ -573,11 +709,89 @@ public partial class TournamentsViewModel : ViewModelBase
|
|||||||
|
|
||||||
var lbFinal = CreateMatch(tournament);
|
var lbFinal = CreateMatch(tournament);
|
||||||
allMatches.Add(lbFinal);
|
allMatches.Add(lbFinal);
|
||||||
|
lbMatchesByRound.Add(new List<Match> { lbFinal });
|
||||||
|
|
||||||
var grandFinals = CreateMatch(tournament);
|
var grandFinals = CreateMatch(tournament);
|
||||||
allMatches.Add(grandFinals);
|
allMatches.Add(grandFinals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save all matches first to get IDs
|
||||||
|
_context.Matches.AddRange(allMatches);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
// Set up winners bracket navigation
|
||||||
|
int wbMatchIndex = 0;
|
||||||
|
for (int r = 0; r < wbRounds; r++)
|
||||||
|
{
|
||||||
|
int matchesInRound = nextPowerOf2 / (int)Math.Pow(2, r + 1);
|
||||||
|
for (int i = 0; i < matchesInRound; i++)
|
||||||
|
{
|
||||||
|
var match = wbMatchesByRound[r][i];
|
||||||
|
|
||||||
|
// Winner goes to next WB round
|
||||||
|
if (r < wbRounds - 1)
|
||||||
|
{
|
||||||
|
var nextMatch = wbMatchesByRound[r + 1][i / 2];
|
||||||
|
match.WinnerMatchId = nextMatch.Id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// WB final winner goes to grand finals
|
||||||
|
var grandFinals = allMatches.Last();
|
||||||
|
match.WinnerMatchId = grandFinals.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loser drops to losers bracket
|
||||||
|
if (r > 0 && lbMatchesByRound.Count > 0)
|
||||||
|
{
|
||||||
|
int lbRound = r - 1;
|
||||||
|
if (lbRound < lbMatchesByRound.Count - 1) // Not LB final
|
||||||
|
{
|
||||||
|
int lbMatchIndex = i / 2;
|
||||||
|
if (lbMatchIndex < lbMatchesByRound[lbRound].Count)
|
||||||
|
{
|
||||||
|
var lbMatch = lbMatchesByRound[lbRound][lbMatchIndex];
|
||||||
|
match.LoserMatchId = lbMatch.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (r == 0 && lbMatchesByRound.Count > 0)
|
||||||
|
{
|
||||||
|
// First round losers go to first LB round
|
||||||
|
int lbMatchIndex = i / 2;
|
||||||
|
if (lbMatchIndex < lbMatchesByRound[0].Count)
|
||||||
|
{
|
||||||
|
var lbMatch = lbMatchesByRound[0][lbMatchIndex];
|
||||||
|
match.LoserMatchId = lbMatch.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up losers bracket navigation
|
||||||
|
for (int r = 0; r < lbMatchesByRound.Count; r++)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < lbMatchesByRound[r].Count; i++)
|
||||||
|
{
|
||||||
|
var match = lbMatchesByRound[r][i];
|
||||||
|
|
||||||
|
if (r < lbMatchesByRound.Count - 2)
|
||||||
|
{
|
||||||
|
// Winner goes to next LB round
|
||||||
|
var nextMatch = lbMatchesByRound[r + 1][i / 2];
|
||||||
|
match.WinnerMatchId = nextMatch.Id;
|
||||||
|
}
|
||||||
|
else if (r == lbMatchesByRound.Count - 2)
|
||||||
|
{
|
||||||
|
// LB final winner goes to grand finals
|
||||||
|
var grandFinals = allMatches.Last();
|
||||||
|
match.WinnerMatchId = grandFinals.Id;
|
||||||
|
}
|
||||||
|
// LB losers are eliminated - no LoserMatchId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up teams for first round
|
||||||
var firstRoundMatches = wbMatchesByRound[0];
|
var firstRoundMatches = wbMatchesByRound[0];
|
||||||
for (int i = 0; i < nextPowerOf2 / 2; i++)
|
for (int i = 0; i < nextPowerOf2 / 2; i++)
|
||||||
{
|
{
|
||||||
@@ -591,7 +805,6 @@ public partial class TournamentsViewModel : ViewModelBase
|
|||||||
AddTeamToMatch(match, teams[lowSeed - 1], lowSeed);
|
AddTeamToMatch(match, teams[lowSeed - 1], lowSeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.Matches.AddRange(allMatches);
|
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
<Button Content="Events" Command="{Binding NavigateToEventsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
<Button Content="Events" Command="{Binding NavigateToEventsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
<Button Content="Games" Command="{Binding NavigateToGamesCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
<Button Content="Games" Command="{Binding NavigateToGamesCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
<Button Content="Tournaments" Command="{Binding NavigateToTournamentsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
<Button Content="Tournaments" Command="{Binding NavigateToTournamentsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
|
<Button Content="Matches" Command="{Binding NavigateToMatchesCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
<Button Content="Teams" Command="{Binding NavigateToTeamsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
<Button Content="Teams" Command="{Binding NavigateToTeamsCommand}" Padding="16,8" FontSize="14" Foreground="White" Background="Transparent" BorderThickness="0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:vm="using:TournamentOrganizer.ViewModels"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="600"
|
||||||
|
x:Class="TournamentOrganizer.Views.MatchesView"
|
||||||
|
x:DataType="vm:MatchesViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:MatchesViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<UserControl.Styles>
|
||||||
|
<Style Selector="ListBoxItem.dropdown-item">
|
||||||
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.dropdown-item:selected">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ListBoxItem.dropdown-item:pointerover">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.dropdown-action">
|
||||||
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.dropdown-action:pointerover">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Styles>
|
||||||
|
|
||||||
|
<Grid RowDefinitions="Auto,*,Auto" ColumnDefinitions="*,*">
|
||||||
|
<TextBlock Grid.ColumnSpan="2" Grid.Row="0" Text="Match Management" FontSize="20" FontWeight="Bold" Margin="16,16,16,8"/>
|
||||||
|
|
||||||
|
<!-- Left Panel: Filters and Matches -->
|
||||||
|
<Border Grid.Column="0" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" Text="Matches" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8"/>
|
||||||
|
|
||||||
|
<!-- Filters -->
|
||||||
|
<StackPanel DockPanel.Dock="Top" Spacing="6" Margin="0,0,0,8">
|
||||||
|
<TextBlock Text="Filters" FontWeight="SemiBold" FontSize="12"/>
|
||||||
|
|
||||||
|
<!-- Event Filter Dropdown -->
|
||||||
|
<Panel Name="EventFilterPanel">
|
||||||
|
<ToggleButton Name="EventFilterToggle" HorizontalContentAlignment="Left" HorizontalAlignment="Stretch" Padding="8,6"
|
||||||
|
IsChecked="{Binding IsEventDropdownOpen}">
|
||||||
|
<ToggleButton.Template>
|
||||||
|
<ControlTemplate TargetType="ToggleButton">
|
||||||
|
<Border Background="{TemplateBinding Background}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
|
<ContentPresenter Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}" HorizontalAlignment="Left"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</ToggleButton.Template>
|
||||||
|
<ToggleButton.Content>
|
||||||
|
<Panel>
|
||||||
|
<TextBlock Text="{Binding SelectedEvent.DisplayName, Mode=OneWay}" IsVisible="{Binding SelectedEvent, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
||||||
|
<TextBlock Text="Select an event..." Foreground="Gray" IsVisible="{Binding SelectedEvent, Converter={x:Static ObjectConverters.IsNull}}"/>
|
||||||
|
</Panel>
|
||||||
|
</ToggleButton.Content>
|
||||||
|
</ToggleButton>
|
||||||
|
<Popup IsOpen="{Binding IsEventDropdownOpen}" PlacementTarget="{Binding #EventFilterToggle}" Width="{Binding Bounds.Width, ElementName=EventFilterToggle}">
|
||||||
|
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
|
<DockPanel MaxHeight="200">
|
||||||
|
<TextBox DockPanel.Dock="Top" Text="{Binding EventFilterSearch}" Watermark="Search events..." Margin="4" Padding="6,4"/>
|
||||||
|
<Button DockPanel.Dock="Bottom" Content="All" Classes="dropdown-action" Foreground="Gray" Margin="4,0,4,4"
|
||||||
|
Click="OnClearEventFilter"/>
|
||||||
|
<ListBox ItemsSource="{Binding FilteredEvents}" MaxHeight="160" SelectionMode="Single" Classes="dropdown-item"
|
||||||
|
SelectionChanged="OnEventSelectionChanged">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:EventOption">
|
||||||
|
<TextBlock Text="{Binding DisplayName}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
|
<!-- Tournament Filter Dropdown -->
|
||||||
|
<Panel Name="TournamentFilterPanel">
|
||||||
|
<ToggleButton Name="TournamentFilterToggle" HorizontalContentAlignment="Left" HorizontalAlignment="Stretch" Padding="8,6"
|
||||||
|
IsChecked="{Binding IsTournamentDropdownOpen}" IsEnabled="{Binding IsTournamentFilterEnabled}">
|
||||||
|
<ToggleButton.Template>
|
||||||
|
<ControlTemplate TargetType="ToggleButton">
|
||||||
|
<Border Background="{TemplateBinding Background}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
|
<ContentPresenter Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}" HorizontalAlignment="Left"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</ToggleButton.Template>
|
||||||
|
<ToggleButton.Content>
|
||||||
|
<Panel>
|
||||||
|
<TextBlock Text="{Binding SelectedTournament.DisplayName, Mode=OneWay}" IsVisible="{Binding SelectedTournament, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
||||||
|
<TextBlock Text="Select an event first..." Foreground="Gray" IsVisible="{Binding SelectedTournament, Converter={x:Static ObjectConverters.IsNull}}"/>
|
||||||
|
</Panel>
|
||||||
|
</ToggleButton.Content>
|
||||||
|
</ToggleButton>
|
||||||
|
<Popup IsOpen="{Binding IsTournamentDropdownOpen}" PlacementTarget="{Binding #TournamentFilterToggle}" Width="{Binding Bounds.Width, ElementName=TournamentFilterToggle}">
|
||||||
|
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}" BorderBrush="Gray" BorderThickness="1" CornerRadius="4">
|
||||||
|
<DockPanel MaxHeight="200">
|
||||||
|
<TextBox DockPanel.Dock="Top" Text="{Binding TournamentFilterSearch}" Watermark="Search tournaments..." Margin="4" Padding="6,4"/>
|
||||||
|
<Button DockPanel.Dock="Bottom" Content="All" Classes="dropdown-action" Foreground="Gray" Margin="4,0,4,4"
|
||||||
|
Click="OnClearTournamentFilter"/>
|
||||||
|
<ListBox ItemsSource="{Binding FilteredTournaments}" MaxHeight="160" SelectionMode="Single" Classes="dropdown-item"
|
||||||
|
SelectionChanged="OnTournamentSelectionChanged">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:TournamentOption">
|
||||||
|
<TextBlock Text="{Binding DisplayName}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Panel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Matches List -->
|
||||||
|
<ListBox ItemsSource="{Binding Matches}"
|
||||||
|
SelectedItem="{Binding SelectedMatch}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:MatchDisplay">
|
||||||
|
<StackPanel Spacing="2">
|
||||||
|
<TextBlock Text="{Binding TeamsText}" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="{Binding State}" FontSize="11" Foreground="Gray"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Right Panel: Match Details -->
|
||||||
|
<Border Grid.Column="1" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8"
|
||||||
|
IsVisible="{Binding SelectedMatch, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" Text="Match Details" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8"/>
|
||||||
|
|
||||||
|
<ScrollViewer>
|
||||||
|
<StackPanel Spacing="12">
|
||||||
|
<!-- Teams and Scores -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Teams" FontWeight="SemiBold"/>
|
||||||
|
<ItemsControl ItemsSource="{Binding MatchTeams}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:TeamParticipantDisplay">
|
||||||
|
<Grid ColumnDefinitions="*,Auto,Auto" Margin="0,4,0,0">
|
||||||
|
<TextBlock Grid.Column="0" Text="{Binding TeamName}" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding Score, StringFormat='Score: {0}'}" Margin="8,0"/>
|
||||||
|
<TextBlock Grid.Column="2" Text="{Binding Seed, StringFormat='#{0}'}" Foreground="Gray"/>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Rounds -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<Grid ColumnDefinitions="*,Auto">
|
||||||
|
<TextBlock Grid.Column="0" Text="Rounds" FontWeight="SemiBold"/>
|
||||||
|
<Button Grid.Column="1" Content="Create Round" Command="{Binding CreateRoundCommand}"
|
||||||
|
IsEnabled="{Binding CanCreateRound}"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<ListBox ItemsSource="{Binding Rounds}"
|
||||||
|
SelectedItem="{Binding SelectedRound}"
|
||||||
|
MinHeight="60">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:RoundDisplay">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
<TextBlock Text="{Binding Id, StringFormat='Round #{0}'}" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="{Binding State}" Foreground="Gray"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Round Actions -->
|
||||||
|
<StackPanel Spacing="4" IsVisible="{Binding SelectedRound, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
|
<TextBlock Text="Round Actions" FontWeight="SemiBold"/>
|
||||||
|
|
||||||
|
<Button Content="Start Round" Command="{Binding StartRoundCommand}"
|
||||||
|
IsEnabled="{Binding CanStartRound}" HorizontalAlignment="Stretch"/>
|
||||||
|
|
||||||
|
<TextBlock Text="Award Victory:" FontSize="12" Foreground="Gray"/>
|
||||||
|
<Grid ColumnDefinitions="*,*" ColumnSpacing="4">
|
||||||
|
<Button Grid.Column="0" Content="{Binding MatchTeams[0].TeamName, StringFormat='Victory: {0}'}"
|
||||||
|
Command="{Binding AwardVictoryCommand}"
|
||||||
|
CommandParameter="0"
|
||||||
|
IsEnabled="{Binding CanAwardVictory}"/>
|
||||||
|
<Button Grid.Column="1" Content="{Binding MatchTeams[1].TeamName, StringFormat='Victory: {0}'}"
|
||||||
|
Command="{Binding AwardVictoryCommand}"
|
||||||
|
CommandParameter="1"
|
||||||
|
IsEnabled="{Binding CanAwardVictory}"/>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Status Bar -->
|
||||||
|
<TextBlock Grid.ColumnSpan="2" Grid.Row="2" Text="{Binding StatusMessage}" Margin="8" Foreground="Gray" FontSize="12"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using TournamentOrganizer.ViewModels;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Views;
|
||||||
|
|
||||||
|
public partial class MatchesView : UserControl
|
||||||
|
{
|
||||||
|
public MatchesView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEventSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ListBox { SelectedItem: EventOption option } && DataContext is MatchesViewModel vm)
|
||||||
|
{
|
||||||
|
vm.SelectEventFilter(option);
|
||||||
|
if (EventFilterToggle != null)
|
||||||
|
EventFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTournamentSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ListBox { SelectedItem: TournamentOption option } && DataContext is MatchesViewModel vm)
|
||||||
|
{
|
||||||
|
vm.SelectTournamentFilter(option);
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearEventFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is MatchesViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearEventFilter();
|
||||||
|
if (EventFilterToggle != null)
|
||||||
|
EventFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearTournamentFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is MatchesViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearTournamentFilter();
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user