Compare commits
7 Commits
1e25ca809b
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a51a8265d | |||
| c70b9c554e | |||
| 67d27ab21c | |||
| f72735197d | |||
| 89c7f5a233 | |||
| 2ec32ebd7e | |||
| a14cc8a0d9 |
@@ -17,6 +17,7 @@ public class TournamentContext : DbContext
|
|||||||
public DbSet<Round> Rounds { get; set; }
|
public DbSet<Round> Rounds { get; set; }
|
||||||
public DbSet<Team> Teams { get; set; }
|
public DbSet<Team> Teams { get; set; }
|
||||||
public DbSet<Tournament> Tournaments { get; set; }
|
public DbSet<Tournament> Tournaments { get; set; }
|
||||||
|
public DbSet<TournamentTeam> TournamentTeams { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
@@ -35,6 +36,36 @@ public class TournamentContext : DbContext
|
|||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Team>()
|
||||||
|
.HasOne(t => t.Leader)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(t => t.LeaderId)
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TournamentTeam>()
|
||||||
|
.HasOne(tt => tt.Tournament)
|
||||||
|
.WithMany(t => t.TournamentTeams)
|
||||||
|
.HasForeignKey(tt => tt.TournamentId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
modelBuilder.Entity<TournamentTeam>()
|
||||||
|
.HasOne(tt => tt.Team)
|
||||||
|
.WithMany(t => t.TournamentTeams)
|
||||||
|
.HasForeignKey(tt => tt.TeamId)
|
||||||
|
.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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,348 @@
|
|||||||
|
// <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("20260506061334_AddTeamLeader")]
|
||||||
|
partial class AddTeamLeader
|
||||||
|
{
|
||||||
|
/// <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>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TournamentId");
|
||||||
|
|
||||||
|
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.Match", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("TournamentOrganizer.Models.Tournament", "Tournament")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
});
|
||||||
|
|
||||||
|
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()
|
||||||
|
.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()
|
||||||
|
.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()
|
||||||
|
.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.Event", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Game", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Tournaments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Team", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Matches");
|
||||||
|
|
||||||
|
b.Navigation("Players");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddTeamLeader : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "LeaderId",
|
||||||
|
table: "Teams",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Teams_LeaderId",
|
||||||
|
table: "Teams",
|
||||||
|
column: "LeaderId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Teams_Players_LeaderId",
|
||||||
|
table: "Teams",
|
||||||
|
column: "LeaderId",
|
||||||
|
principalTable: "Players",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.SetNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Teams_Players_LeaderId",
|
||||||
|
table: "Teams");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Teams_LeaderId",
|
||||||
|
table: "Teams");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LeaderId",
|
||||||
|
table: "Teams");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+392
@@ -0,0 +1,392 @@
|
|||||||
|
// <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("20260506083354_AddTournamentTeam")]
|
||||||
|
partial class AddTournamentTeam
|
||||||
|
{
|
||||||
|
/// <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>("TournamentId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("TournamentId");
|
||||||
|
|
||||||
|
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.Tournament", "Tournament")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("TournamentId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Tournament");
|
||||||
|
});
|
||||||
|
|
||||||
|
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()
|
||||||
|
.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()
|
||||||
|
.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()
|
||||||
|
.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.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 AddTournamentTeam : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "TournamentTeams",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
TournamentId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
TeamId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Seed = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_TournamentTeams", x => new { x.TournamentId, x.TeamId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TournamentTeams_Teams_TeamId",
|
||||||
|
column: x => x.TeamId,
|
||||||
|
principalTable: "Teams",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_TournamentTeams_Tournaments_TournamentId",
|
||||||
|
column: x => x.TournamentId,
|
||||||
|
principalTable: "Tournaments",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_TournamentTeams_TeamId",
|
||||||
|
table: "TournamentTeams",
|
||||||
|
column: "TeamId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "TournamentTeams");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+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");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -149,12 +159,17 @@ namespace TournamentOrganizer.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("LeaderId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("LeaderId");
|
||||||
|
|
||||||
b.ToTable("Teams");
|
b.ToTable("Teams");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -218,15 +233,47 @@ namespace TournamentOrganizer.Migrations
|
|||||||
b.ToTable("Tournaments");
|
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 =>
|
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 =>
|
||||||
@@ -249,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();
|
||||||
@@ -262,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();
|
||||||
@@ -270,10 +317,20 @@ namespace TournamentOrganizer.Migrations
|
|||||||
b.Navigation("Match");
|
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 =>
|
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();
|
||||||
@@ -308,6 +365,25 @@ namespace TournamentOrganizer.Migrations
|
|||||||
b.Navigation("Game");
|
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 =>
|
modelBuilder.Entity("TournamentOrganizer.Models.Event", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Tournaments");
|
b.Navigation("Tournaments");
|
||||||
@@ -318,11 +394,30 @@ 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");
|
||||||
|
|
||||||
b.Navigation("Players");
|
b.Navigation("Players");
|
||||||
|
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("TournamentOrganizer.Models.Tournament", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("TournamentTeams");
|
||||||
});
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ public class Event
|
|||||||
public DateTime Start { get; set; }
|
public DateTime Start { get; set; }
|
||||||
public DateTime End { get; set; }
|
public DateTime End { get; set; }
|
||||||
|
|
||||||
public required List<Tournament> Tournaments { get; set; }
|
public List<Tournament> Tournaments { get; set; } = [];
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,27 @@ public enum RuleSet
|
|||||||
Swiss
|
Swiss
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class RuleSetExtensions
|
||||||
|
{
|
||||||
|
public static string ToDisplayName(this RuleSet ruleSet) => ruleSet switch
|
||||||
|
{
|
||||||
|
RuleSet.DoubleElimination => "Double Elimination",
|
||||||
|
RuleSet.SingleElimination => "Single Elimination",
|
||||||
|
RuleSet.RoundRobin => "Round Robin",
|
||||||
|
RuleSet.Swiss => "Swiss",
|
||||||
|
_ => ruleSet.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
public static RuleSet? FromDisplayName(string? displayName) => displayName switch
|
||||||
|
{
|
||||||
|
"Double Elimination" => RuleSet.DoubleElimination,
|
||||||
|
"Single Elimination" => RuleSet.SingleElimination,
|
||||||
|
"Round Robin" => RuleSet.RoundRobin,
|
||||||
|
"Swiss" => RuleSet.Swiss,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public class Game
|
public class Game
|
||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
@@ -26,6 +47,6 @@ public class Game
|
|||||||
|
|
||||||
public RuleSet? S2RuleSet { get; set; }
|
public RuleSet? S2RuleSet { get; set; }
|
||||||
|
|
||||||
public required List<Tournament> Tournaments { get; set; }
|
public List<Tournament> Tournaments { get; set; } = [];
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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 required List<TeamParticipant> Teams;
|
public int? WinnerMatchId { get; set; }
|
||||||
public required List<Round> Rounds;
|
public int? LoserMatchId { get; set; }
|
||||||
public required Tournament Tournament { get; set; }
|
|
||||||
|
public List<TeamParticipant> Teams { get; set; } = [];
|
||||||
|
public List<Round> Rounds { get; set; } = [];
|
||||||
|
public Tournament Tournament { get; set; } = null!;
|
||||||
|
public Match? WinnerMatch { get; set; }
|
||||||
|
public Match? LoserMatch { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,9 +7,8 @@ public class PlayerParticipant
|
|||||||
{
|
{
|
||||||
public int RoundId { get; set; }
|
public int RoundId { get; set; }
|
||||||
public int PlayerId { get; set; }
|
public int PlayerId { get; set; }
|
||||||
|
public Player Player { get; set; } = null!;
|
||||||
public required Player Player { get; set; }
|
public Round Round { get; set; } = null!;
|
||||||
public required Round Round { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[PrimaryKey(nameof(MatchId), nameof(TeamId))]
|
[PrimaryKey(nameof(MatchId), nameof(TeamId))]
|
||||||
@@ -19,7 +18,16 @@ public class TeamParticipant
|
|||||||
public int TeamId { get; set; }
|
public int TeamId { get; set; }
|
||||||
public int Seed { get; set; }
|
public int Seed { get; set; }
|
||||||
public int Score { get; set; }
|
public int Score { get; set; }
|
||||||
|
public Team Team { get; set; } = null!;
|
||||||
|
public Match Round { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
public required Team Team { get; set; }
|
[PrimaryKey(nameof(TournamentId), nameof(TeamId))]
|
||||||
public required Match Round { get; set; }
|
public class TournamentTeam
|
||||||
}
|
{
|
||||||
|
public int TournamentId { get; set; }
|
||||||
|
public int TeamId { get; set; }
|
||||||
|
public int Seed { get; set; }
|
||||||
|
public Tournament Tournament { get; set; } = null!;
|
||||||
|
public Team Team { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ public class Player
|
|||||||
public string Contact { get; set; } = "discordname";
|
public string Contact { get; set; } = "discordname";
|
||||||
public int TeamId { get; set; }
|
public int TeamId { get; set; }
|
||||||
|
|
||||||
public required Team Team { get; set; }
|
public Team Team { get; set; } = null!;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ public class Round
|
|||||||
public int MatchId { get; set; }
|
public int MatchId { get; set; }
|
||||||
public RoundState State { get; set; } = RoundState.Waiting;
|
public RoundState State { get; set; } = RoundState.Waiting;
|
||||||
|
|
||||||
public required List<PlayerParticipant> Players;
|
public List<PlayerParticipant> Players { get; set; } = [];
|
||||||
public required Match Match { get; set; }
|
public Match Match { get; set; } = null!;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,11 @@ public class Team
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Name { get; set; } = "Example Team";
|
public string Name { get; set; } = "Example Team";
|
||||||
|
|
||||||
public required List<Player> Players { get; set; }
|
public int? LeaderId { get; set; }
|
||||||
public required List<TeamParticipant> Matches { get; set; }
|
public Player? Leader { get; set; }
|
||||||
|
|
||||||
|
public List<Player> Players { get; set; } = [];
|
||||||
|
public List<TeamParticipant> Matches { get; set; } = [];
|
||||||
|
public List<TournamentTeam> TournamentTeams { get; set; } = [];
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
@@ -21,8 +22,9 @@ public class Tournament
|
|||||||
public int? S1GroupAdvances { get; set; }
|
public int? S1GroupAdvances { get; set; }
|
||||||
public RuleSet? S2RuleSet { get; set; }
|
public RuleSet? S2RuleSet { get; set; }
|
||||||
|
|
||||||
public required Game Game { get; set; }
|
public Game Game { get; set; } = null!;
|
||||||
public required Event Event { get; set; }
|
public Event Event { get; set; } = null!;
|
||||||
|
public List<TournamentTeam> TournamentTeams { get; set; } = [];
|
||||||
|
|
||||||
public static ValidationResult ValidateDates(DateTime date, ValidationContext context)
|
public static ValidationResult ValidateDates(DateTime date, ValidationContext context)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,386 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using TournamentOrganizer.Models;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.ViewModels;
|
||||||
|
|
||||||
|
public partial class EventsViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
private readonly TournamentContext _context;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<EventDisplay> _events = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private EventDisplay? _selectedEvent;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _eventName = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private DateTime _eventStart = DateTime.Today;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private DateTime _eventEnd = DateTime.Today.AddDays(1);
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<TournamentDisplay> _tournaments = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private TournamentDisplay? _selectedTournament;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private GameOption? _selectedGameToAdd;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _filterEventName = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isEditing;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _statusMessage = string.Empty;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<GameOption> _availableGames = [];
|
||||||
|
private readonly ObservableCollection<GameOption> _availableGamesToAdd = [];
|
||||||
|
public ObservableCollection<GameOption> AvailableGamesToAdd => _availableGamesToAdd;
|
||||||
|
|
||||||
|
public EventsViewModel()
|
||||||
|
{
|
||||||
|
_context = new TournamentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnFilterEventNameChanged(string value) => ApplyFilters();
|
||||||
|
|
||||||
|
private async void ApplyFilters()
|
||||||
|
{
|
||||||
|
await LoadEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadEvents()
|
||||||
|
{
|
||||||
|
var games = await _context.Games.ToListAsync();
|
||||||
|
_availableGames.Clear();
|
||||||
|
_availableGamesToAdd.Clear();
|
||||||
|
foreach (var g in games)
|
||||||
|
{
|
||||||
|
var option = new GameOption(g);
|
||||||
|
_availableGames.Add(option);
|
||||||
|
_availableGamesToAdd.Add(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
var allEvents = await _context.Events
|
||||||
|
.Include(e => e.Tournaments)
|
||||||
|
.ThenInclude(t => t.Game)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var filtered = allEvents.AsEnumerable();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(FilterEventName))
|
||||||
|
{
|
||||||
|
var filter = FilterEventName.ToLower();
|
||||||
|
filtered = filtered.Where(e => e.Name.ToLower().Contains(filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.Clear();
|
||||||
|
foreach (var evt in filtered)
|
||||||
|
{
|
||||||
|
Events.Add(new EventDisplay(evt));
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedEvent = null;
|
||||||
|
IsEditing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task RefreshEvents()
|
||||||
|
{
|
||||||
|
await LoadEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void CreateNewEvent()
|
||||||
|
{
|
||||||
|
EventName = "New Event";
|
||||||
|
EventStart = DateTime.Today;
|
||||||
|
EventEnd = DateTime.Today.AddDays(1);
|
||||||
|
Tournaments.Clear();
|
||||||
|
IsEditing = true;
|
||||||
|
SelectedEvent = null;
|
||||||
|
SelectedGameToAdd = null;
|
||||||
|
StatusMessage = "Creating new event";
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task SaveEvent()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(EventName))
|
||||||
|
{
|
||||||
|
StatusMessage = "Event name is required";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EventEnd <= EventStart)
|
||||||
|
{
|
||||||
|
StatusMessage = "End date must be after start date";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Event? evt;
|
||||||
|
if (SelectedEvent != null && SelectedEvent.Id > 0)
|
||||||
|
{
|
||||||
|
evt = await _context.Events
|
||||||
|
.Include(e => e.Tournaments)
|
||||||
|
.FirstOrDefaultAsync(e => e.Id == SelectedEvent.Id);
|
||||||
|
|
||||||
|
if (evt == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Event not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
evt.Name = EventName;
|
||||||
|
evt.Start = EventStart;
|
||||||
|
evt.End = EventEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
evt = new Event
|
||||||
|
{
|
||||||
|
Name = EventName,
|
||||||
|
Start = EventStart,
|
||||||
|
End = EventEnd,
|
||||||
|
Tournaments = []
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.Events.Add(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Event '{EventName}' saved successfully";
|
||||||
|
await LoadEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task DeleteEvent()
|
||||||
|
{
|
||||||
|
if (SelectedEvent == null || SelectedEvent.Id == 0)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select an event to delete";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var evt = await _context.Events
|
||||||
|
.Include(e => e.Tournaments)
|
||||||
|
.FirstOrDefaultAsync(e => e.Id == SelectedEvent.Id);
|
||||||
|
|
||||||
|
if (evt == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Event not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Events.Remove(evt);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Event '{evt.Name}' deleted";
|
||||||
|
await LoadEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task AddGameToEvent()
|
||||||
|
{
|
||||||
|
if (SelectedGameToAdd == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a game to add";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedEvent == null || SelectedEvent.Id == 0)
|
||||||
|
{
|
||||||
|
StatusMessage = "Save the event first before adding games";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var evt = await _context.Events
|
||||||
|
.Include(e => e.Tournaments)
|
||||||
|
.FirstOrDefaultAsync(e => e.Id == SelectedEvent.Id);
|
||||||
|
|
||||||
|
if (evt == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Event not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.Tournaments.Any(t => t.GameId == SelectedGameToAdd.Game.Id))
|
||||||
|
{
|
||||||
|
StatusMessage = "This game is already added to the event";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tournament = new Tournament
|
||||||
|
{
|
||||||
|
GameId = SelectedGameToAdd.Game.Id,
|
||||||
|
EventId = evt.Id,
|
||||||
|
Start = evt.Start,
|
||||||
|
End = evt.End,
|
||||||
|
S1RuleSet = SelectedGameToAdd.Game.S1RuleSet,
|
||||||
|
S1Groups = SelectedGameToAdd.Game.S1Groups,
|
||||||
|
S1GroupAdvances = SelectedGameToAdd.Game.S1GroupAdvances,
|
||||||
|
S2RuleSet = SelectedGameToAdd.Game.S2RuleSet,
|
||||||
|
Game = SelectedGameToAdd.Game,
|
||||||
|
Event = evt
|
||||||
|
};
|
||||||
|
|
||||||
|
evt.Tournaments.Add(tournament);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Added '{SelectedGameToAdd.Game.Name}' to event";
|
||||||
|
await LoadEventDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task RemoveGameFromEvent()
|
||||||
|
{
|
||||||
|
if (SelectedTournament == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a tournament to remove";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedEvent == null || SelectedEvent.Id == 0)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select an event first";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tournament = await _context.Tournaments.FirstOrDefaultAsync(t => t.Id == SelectedTournament.Id);
|
||||||
|
if (tournament == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Tournament not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Tournaments.Remove(tournament);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Removed '{SelectedTournament.GameName}' from event";
|
||||||
|
await LoadEventDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadEventDetails()
|
||||||
|
{
|
||||||
|
var allEvents = await _context.Events
|
||||||
|
.Include(e => e.Tournaments)
|
||||||
|
.ThenInclude(t => t.Game)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var evt = allEvents.FirstOrDefault(e => e.Id == (SelectedEvent?.Id ?? 0));
|
||||||
|
if (evt == null)
|
||||||
|
{
|
||||||
|
Tournaments.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tournaments.Clear();
|
||||||
|
foreach (var t in evt.Tournaments)
|
||||||
|
{
|
||||||
|
Tournaments.Add(new TournamentDisplay(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedTournament = null;
|
||||||
|
|
||||||
|
_availableGamesToAdd.Clear();
|
||||||
|
foreach (var g in _availableGames)
|
||||||
|
{
|
||||||
|
if (!Tournaments.Any(t => t.GameId == g.Game.Id))
|
||||||
|
{
|
||||||
|
_availableGamesToAdd.Add(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedGameToAdd = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedEventChanged(EventDisplay? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
IsEditing = false;
|
||||||
|
Tournaments.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventName = value.Name;
|
||||||
|
EventStart = value.Start;
|
||||||
|
EventEnd = value.End;
|
||||||
|
IsEditing = true;
|
||||||
|
_ = LoadEventDetails();
|
||||||
|
StatusMessage = $"Editing event '{value.Name}'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventDisplay
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public DateTime Start { get; set; }
|
||||||
|
public DateTime End { get; set; }
|
||||||
|
public List<string> TournamentNames { get; set; } = [];
|
||||||
|
|
||||||
|
public EventDisplay() { }
|
||||||
|
|
||||||
|
public EventDisplay(Event evt)
|
||||||
|
{
|
||||||
|
Id = evt.Id;
|
||||||
|
Name = evt.Name;
|
||||||
|
Start = evt.Start;
|
||||||
|
End = evt.End;
|
||||||
|
|
||||||
|
if (evt.Tournaments != null)
|
||||||
|
{
|
||||||
|
TournamentNames = evt.Tournaments.Select(t => t.Game.Name).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TournamentDisplay
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int GameId { get; set; }
|
||||||
|
public string GameName { get; set; } = string.Empty;
|
||||||
|
public RuleSet S1RuleSet { get; set; }
|
||||||
|
public string S1RuleSetName => S1RuleSet.ToDisplayName();
|
||||||
|
public RuleSet? S2RuleSet { get; set; }
|
||||||
|
public string? S2RuleSetName => S2RuleSet?.ToDisplayName();
|
||||||
|
|
||||||
|
public TournamentDisplay() { }
|
||||||
|
|
||||||
|
public TournamentDisplay(Tournament tournament)
|
||||||
|
{
|
||||||
|
Id = tournament.Id;
|
||||||
|
GameId = tournament.GameId;
|
||||||
|
GameName = tournament.Game.Name;
|
||||||
|
S1RuleSet = tournament.S1RuleSet;
|
||||||
|
S2RuleSet = tournament.S2RuleSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameOption
|
||||||
|
{
|
||||||
|
public Game Game { get; set; } = null!;
|
||||||
|
public string DisplayName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public GameOption() { }
|
||||||
|
|
||||||
|
public GameOption(Game game)
|
||||||
|
{
|
||||||
|
Game = game;
|
||||||
|
DisplayName = game.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => DisplayName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using TournamentOrganizer.Models;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.ViewModels;
|
||||||
|
|
||||||
|
public partial class GamesViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
private readonly TournamentContext _context;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<GameDisplay> _games = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private GameDisplay? _selectedGame;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _gameName = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _gameDescription = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private RuleSetOption? _selectedS1RuleSet;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private int? _s1Groups;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private int? _s1GroupAdvances;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private RuleSetOption? _selectedS2RuleSet;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _filterGameName = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isEditing;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _statusMessage = string.Empty;
|
||||||
|
|
||||||
|
public ObservableCollection<RuleSetOption> S1RuleSetOptions { get; } = [];
|
||||||
|
|
||||||
|
public ObservableCollection<RuleSetOption> S2RuleSetOptions { get; } = [new RuleSetOption(null, "(None)")];
|
||||||
|
|
||||||
|
public bool ShowStage1GroupSettings => SelectedS2RuleSet?.Value != null;
|
||||||
|
|
||||||
|
public GamesViewModel()
|
||||||
|
{
|
||||||
|
_context = new TournamentContext();
|
||||||
|
foreach (var rs in Enum.GetValues<RuleSet>())
|
||||||
|
{
|
||||||
|
S1RuleSetOptions.Add(new RuleSetOption(rs, rs.ToDisplayName()));
|
||||||
|
S2RuleSetOptions.Add(new RuleSetOption(rs, rs.ToDisplayName()));
|
||||||
|
}
|
||||||
|
SelectedS1RuleSet = S1RuleSetOptions.First();
|
||||||
|
SelectedS2RuleSet = S2RuleSetOptions.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedS2RuleSetChanged(RuleSetOption? value)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(ShowStage1GroupSettings));
|
||||||
|
if (value?.Value == null)
|
||||||
|
{
|
||||||
|
S1Groups = null;
|
||||||
|
S1GroupAdvances = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnFilterGameNameChanged(string value) => ApplyFilters();
|
||||||
|
|
||||||
|
private async void ApplyFilters()
|
||||||
|
{
|
||||||
|
await LoadGames();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadGames()
|
||||||
|
{
|
||||||
|
var allGames = await _context.Games
|
||||||
|
.Include(g => g.Tournaments)
|
||||||
|
.ThenInclude(t => t.Event)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var filtered = allGames.AsEnumerable();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(FilterGameName))
|
||||||
|
{
|
||||||
|
var filter = FilterGameName.ToLower();
|
||||||
|
filtered = filtered.Where(g => g.Name.ToLower().Contains(filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
Games.Clear();
|
||||||
|
foreach (var game in filtered)
|
||||||
|
{
|
||||||
|
Games.Add(new GameDisplay(game));
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedGame = null;
|
||||||
|
IsEditing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task RefreshGames()
|
||||||
|
{
|
||||||
|
await LoadGames();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void CreateNewGame()
|
||||||
|
{
|
||||||
|
GameName = "New Game";
|
||||||
|
GameDescription = string.Empty;
|
||||||
|
SelectedS1RuleSet = S1RuleSetOptions.FirstOrDefault(o => o.Value == RuleSet.SingleElimination);
|
||||||
|
S1Groups = null;
|
||||||
|
S1GroupAdvances = null;
|
||||||
|
SelectedS2RuleSet = S2RuleSetOptions.First();
|
||||||
|
IsEditing = true;
|
||||||
|
SelectedGame = null;
|
||||||
|
StatusMessage = "Creating new game";
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task SaveGame()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(GameName))
|
||||||
|
{
|
||||||
|
StatusMessage = "Game name is required";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Game? game;
|
||||||
|
if (SelectedGame != null && SelectedGame.Id > 0)
|
||||||
|
{
|
||||||
|
game = await _context.Games.FirstOrDefaultAsync(g => g.Id == SelectedGame.Id);
|
||||||
|
|
||||||
|
if (game == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Game not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
game.Name = GameName;
|
||||||
|
game.Description = GameDescription;
|
||||||
|
game.S1RuleSet = SelectedS1RuleSet!.Value!.Value;
|
||||||
|
game.S1Groups = ShowStage1GroupSettings ? S1Groups : null;
|
||||||
|
game.S1GroupAdvances = ShowStage1GroupSettings ? S1GroupAdvances : null;
|
||||||
|
game.S2RuleSet = SelectedS2RuleSet?.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
game = new Game
|
||||||
|
{
|
||||||
|
Name = GameName,
|
||||||
|
Description = GameDescription,
|
||||||
|
S1RuleSet = SelectedS1RuleSet!.Value!.Value,
|
||||||
|
S1Groups = ShowStage1GroupSettings ? S1Groups : null,
|
||||||
|
S1GroupAdvances = ShowStage1GroupSettings ? S1GroupAdvances : null,
|
||||||
|
S2RuleSet = SelectedS2RuleSet?.Value,
|
||||||
|
Tournaments = []
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.Games.Add(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Game '{GameName}' saved successfully";
|
||||||
|
await LoadGames();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task DeleteGame()
|
||||||
|
{
|
||||||
|
if (SelectedGame == null || SelectedGame.Id == 0)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a game to delete";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var game = await _context.Games.FirstOrDefaultAsync(g => g.Id == SelectedGame.Id);
|
||||||
|
|
||||||
|
if (game == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Game not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Games.Remove(game);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Game '{game.Name}' deleted";
|
||||||
|
await LoadGames();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedGameChanged(GameDisplay? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
IsEditing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameName = value.Name;
|
||||||
|
GameDescription = value.Description;
|
||||||
|
SelectedS1RuleSet = S1RuleSetOptions.FirstOrDefault(o => o.Value == value.S1RuleSet) ?? S1RuleSetOptions.First();
|
||||||
|
S1Groups = value.S1Groups;
|
||||||
|
S1GroupAdvances = value.S1GroupAdvances;
|
||||||
|
SelectedS2RuleSet = S2RuleSetOptions.FirstOrDefault(o => o.Value == value.S2RuleSet) ?? S2RuleSetOptions.First();
|
||||||
|
IsEditing = true;
|
||||||
|
StatusMessage = $"Editing game '{value.Name}'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameDisplay
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public RuleSet S1RuleSet { get; set; }
|
||||||
|
public string S1RuleSetName => S1RuleSet.ToDisplayName();
|
||||||
|
public int? S1Groups { get; set; }
|
||||||
|
public int? S1GroupAdvances { get; set; }
|
||||||
|
public RuleSet? S2RuleSet { get; set; }
|
||||||
|
public string? S2RuleSetName => S2RuleSet?.ToDisplayName();
|
||||||
|
public List<string> AssociatedEvents { get; set; } = [];
|
||||||
|
|
||||||
|
public GameDisplay() { }
|
||||||
|
|
||||||
|
public GameDisplay(Game game)
|
||||||
|
{
|
||||||
|
Id = game.Id;
|
||||||
|
Name = game.Name;
|
||||||
|
Description = game.Description;
|
||||||
|
S1RuleSet = game.S1RuleSet;
|
||||||
|
S1Groups = game.S1Groups;
|
||||||
|
S1GroupAdvances = game.S1GroupAdvances;
|
||||||
|
S2RuleSet = game.S2RuleSet;
|
||||||
|
|
||||||
|
var events = new HashSet<string>();
|
||||||
|
if (game.Tournaments != null)
|
||||||
|
{
|
||||||
|
foreach (var t in game.Tournaments)
|
||||||
|
{
|
||||||
|
if (t.Event != null)
|
||||||
|
{
|
||||||
|
events.Add(t.Event.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssociatedEvents = events.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RuleSetOption
|
||||||
|
{
|
||||||
|
public RuleSet? Value { get; set; }
|
||||||
|
public string Label { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public RuleSetOption() { }
|
||||||
|
|
||||||
|
public RuleSetOption(RuleSet? value, string label)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
Label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => Label;
|
||||||
|
}
|
||||||
@@ -1,9 +1,77 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
namespace TournamentOrganizer.ViewModels;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
public partial class MainViewModel : ViewModelBase
|
namespace TournamentOrganizer.ViewModels;
|
||||||
{
|
|
||||||
[ObservableProperty]
|
public partial class MainViewModel : ViewModelBase
|
||||||
private string _greeting = "Welcome to Avalonia!";
|
{
|
||||||
}
|
[ObservableProperty]
|
||||||
|
private ViewModelBase _currentView;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _title = "Tournament Organizer";
|
||||||
|
|
||||||
|
public MainViewModel()
|
||||||
|
{
|
||||||
|
CurrentView = new HomeViewModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void NavigateToHome()
|
||||||
|
{
|
||||||
|
CurrentView = new HomeViewModel();
|
||||||
|
Title = "Tournament Organizer";
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task NavigateToTeams()
|
||||||
|
{
|
||||||
|
var teamsVm = new TeamsViewModel();
|
||||||
|
CurrentView = teamsVm;
|
||||||
|
Title = "Teams Management";
|
||||||
|
await teamsVm.LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task NavigateToGames()
|
||||||
|
{
|
||||||
|
var gamesVm = new GamesViewModel();
|
||||||
|
CurrentView = gamesVm;
|
||||||
|
Title = "Games Management";
|
||||||
|
await gamesVm.LoadGames();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task NavigateToEvents()
|
||||||
|
{
|
||||||
|
var eventsVm = new EventsViewModel();
|
||||||
|
CurrentView = eventsVm;
|
||||||
|
Title = "Events Management";
|
||||||
|
await eventsVm.LoadEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task NavigateToTournaments()
|
||||||
|
{
|
||||||
|
var tournamentsVm = new TournamentsViewModel();
|
||||||
|
CurrentView = tournamentsVm;
|
||||||
|
Title = "Tournament Management";
|
||||||
|
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
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _welcomeMessage = "Welcome to Tournament Organizer!";
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,586 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using TournamentOrganizer.Models;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.ViewModels;
|
||||||
|
|
||||||
|
public partial class TeamsViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
private readonly TournamentContext _context;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<TeamDisplay> _teams = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private TeamDisplay? _selectedTeam;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _teamName = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<PlayerEntry> _players = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private PlayerEntry? _selectedPlayer;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private PlayerEntry? _selectedLeader;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _newPlayerName = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _newPlayerContact = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _filterMemberName = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? _selectedEventFilter;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? _selectedTournamentFilter;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<string> _availableEvents = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<string> _availableTournaments = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _eventFilterSearch = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _tournamentFilterSearch = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isEventDropdownOpen;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isTournamentDropdownOpen;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isEditing;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _statusMessage = string.Empty;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<string> _filteredEvents = [];
|
||||||
|
public ObservableCollection<string> FilteredEvents => _filteredEvents;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<string> _filteredTournaments = [];
|
||||||
|
public ObservableCollection<string> FilteredTournaments => _filteredTournaments;
|
||||||
|
|
||||||
|
public bool IsTournamentFilterEnabled => !string.IsNullOrWhiteSpace(SelectedEventFilter);
|
||||||
|
|
||||||
|
partial void OnSelectedEventFilterChanged(string? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
SelectedTournamentFilter = null;
|
||||||
|
}
|
||||||
|
OnPropertyChanged(nameof(IsTournamentFilterEnabled));
|
||||||
|
UpdateFilteredTournaments();
|
||||||
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
_ = LoadTeams();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.ToLower().Contains(EventFilterSearch.ToLower())))
|
||||||
|
{
|
||||||
|
_filteredEvents.Add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFilteredTournaments()
|
||||||
|
{
|
||||||
|
_filteredTournaments.Clear();
|
||||||
|
if (string.IsNullOrWhiteSpace(SelectedEventFilter))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var t in AvailableTournaments
|
||||||
|
.Where(t => t.EndsWith($" @ {SelectedEventFilter}"))
|
||||||
|
.Where(t => string.IsNullOrWhiteSpace(TournamentFilterSearch) || t.ToLower().Contains(TournamentFilterSearch.ToLower())))
|
||||||
|
{
|
||||||
|
_filteredTournaments.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TeamsViewModel()
|
||||||
|
{
|
||||||
|
_context = new TournamentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadTeams()
|
||||||
|
{
|
||||||
|
var events = await _context.Events.ToListAsync();
|
||||||
|
AvailableEvents.Clear();
|
||||||
|
foreach (var e in events)
|
||||||
|
{
|
||||||
|
AvailableEvents.Add(e.Name);
|
||||||
|
}
|
||||||
|
UpdateFilteredEvents();
|
||||||
|
|
||||||
|
var tournaments = await _context.Tournaments
|
||||||
|
.Include(t => t.Game)
|
||||||
|
.Include(t => t.Event)
|
||||||
|
.ToListAsync();
|
||||||
|
AvailableTournaments.Clear();
|
||||||
|
foreach (var t in tournaments)
|
||||||
|
{
|
||||||
|
AvailableTournaments.Add(GetTournamentDisplayName(t));
|
||||||
|
}
|
||||||
|
UpdateFilteredTournaments();
|
||||||
|
|
||||||
|
var query = _context.Teams
|
||||||
|
.Include(t => t.Players)
|
||||||
|
.Include(t => t.Leader)
|
||||||
|
.Include(t => t.Matches)
|
||||||
|
.ThenInclude(tp => tp.Round)
|
||||||
|
.ThenInclude(m => m.Tournament)
|
||||||
|
.ThenInclude(t => t.Event)
|
||||||
|
.AsSplitQuery();
|
||||||
|
|
||||||
|
var allTeams = await query.ToListAsync();
|
||||||
|
|
||||||
|
var filtered = allTeams.AsEnumerable();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(FilterMemberName))
|
||||||
|
{
|
||||||
|
var filter = FilterMemberName.ToLower();
|
||||||
|
filtered = filtered.Where(t => t.Players.Any(p => p.Name.ToLower().Contains(filter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(SelectedEventFilter))
|
||||||
|
{
|
||||||
|
var filter = SelectedEventFilter.ToLower();
|
||||||
|
filtered = filtered.Where(t => GetAssociatedEvents(t).Any(e => e.ToLower().Contains(filter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(SelectedTournamentFilter))
|
||||||
|
{
|
||||||
|
var filter = SelectedTournamentFilter.ToLower();
|
||||||
|
filtered = filtered.Where(t => GetAssociatedTournaments(t).Any(tn => tn.ToLower().Contains(filter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Teams.Clear();
|
||||||
|
foreach (var team in filtered)
|
||||||
|
{
|
||||||
|
Teams.Add(new TeamDisplay(team));
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedTeam = null;
|
||||||
|
IsEditing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectEventFilter(string eventName)
|
||||||
|
{
|
||||||
|
SelectedEventFilter = eventName;
|
||||||
|
IsEventDropdownOpen = false;
|
||||||
|
EventFilterSearch = string.Empty;
|
||||||
|
_ = LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearEventFilter()
|
||||||
|
{
|
||||||
|
SelectedEventFilter = null;
|
||||||
|
EventFilterSearch = string.Empty;
|
||||||
|
_ = LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectTournamentFilter(string tournamentName)
|
||||||
|
{
|
||||||
|
SelectedTournamentFilter = tournamentName;
|
||||||
|
IsTournamentDropdownOpen = false;
|
||||||
|
TournamentFilterSearch = string.Empty;
|
||||||
|
_ = LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearTournamentFilter()
|
||||||
|
{
|
||||||
|
SelectedTournamentFilter = null;
|
||||||
|
TournamentFilterSearch = string.Empty;
|
||||||
|
_ = LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task RefreshTeams()
|
||||||
|
{
|
||||||
|
await LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void CreateNewTeam()
|
||||||
|
{
|
||||||
|
TeamName = "New Team";
|
||||||
|
Players.Clear();
|
||||||
|
SelectedLeader = null;
|
||||||
|
SelectedPlayer = null;
|
||||||
|
IsEditing = true;
|
||||||
|
SelectedTeam = null;
|
||||||
|
NewPlayerName = string.Empty;
|
||||||
|
NewPlayerContact = string.Empty;
|
||||||
|
StatusMessage = "Creating new team";
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task SaveTeam()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(TeamName))
|
||||||
|
{
|
||||||
|
StatusMessage = "Team name is required";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Players.Count == 0)
|
||||||
|
{
|
||||||
|
StatusMessage = "Team must have at least one member";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Team? team;
|
||||||
|
if (SelectedTeam != null && SelectedTeam.Id > 0)
|
||||||
|
{
|
||||||
|
team = await _context.Teams
|
||||||
|
.Include(t => t.Players)
|
||||||
|
.FirstOrDefaultAsync(t => t.Id == SelectedTeam.Id);
|
||||||
|
|
||||||
|
if (team == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Team not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
team.Name = TeamName;
|
||||||
|
|
||||||
|
var existingPlayerIds = team.Players.Select(p => p.Id).ToHashSet();
|
||||||
|
var currentPlayerIds = Players.Where(p => p.Id > 0).Select(p => p.Id).ToHashSet();
|
||||||
|
|
||||||
|
var playersToRemove = team.Players.Where(p => !currentPlayerIds.Contains(p.Id)).ToList();
|
||||||
|
foreach (var player in playersToRemove)
|
||||||
|
{
|
||||||
|
team.Players.Remove(player);
|
||||||
|
_context.Players.Remove(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entry in Players)
|
||||||
|
{
|
||||||
|
if (entry.Id > 0)
|
||||||
|
{
|
||||||
|
var existing = team.Players.FirstOrDefault(p => p.Id == entry.Id);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
existing.Name = entry.Name;
|
||||||
|
existing.Contact = entry.Contact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var newPlayer = new Player
|
||||||
|
{
|
||||||
|
Name = entry.Name,
|
||||||
|
Contact = entry.Contact,
|
||||||
|
Team = team
|
||||||
|
};
|
||||||
|
team.Players.Add(newPlayer);
|
||||||
|
entry.Id = newPlayer.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedLeader != null)
|
||||||
|
{
|
||||||
|
var leader = team.Players.FirstOrDefault(p =>
|
||||||
|
(SelectedLeader.Id > 0 && p.Id == SelectedLeader.Id) ||
|
||||||
|
(SelectedLeader.Id == 0 && p.Name == SelectedLeader.Name && p.Contact == SelectedLeader.Contact));
|
||||||
|
team.Leader = leader;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
team.Leader = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
team = new Team
|
||||||
|
{
|
||||||
|
Name = TeamName,
|
||||||
|
Players = [],
|
||||||
|
Matches = []
|
||||||
|
};
|
||||||
|
|
||||||
|
var playerEntries = new List<(PlayerEntry Entry, Player Player)>();
|
||||||
|
foreach (var entry in Players)
|
||||||
|
{
|
||||||
|
var player = new Player
|
||||||
|
{
|
||||||
|
Name = entry.Name,
|
||||||
|
Contact = entry.Contact,
|
||||||
|
Team = team
|
||||||
|
};
|
||||||
|
team.Players.Add(player);
|
||||||
|
playerEntries.Add((entry, player));
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Teams.Add(team);
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
if (team.Players.Count > 0)
|
||||||
|
{
|
||||||
|
int leaderIndex = 0;
|
||||||
|
if (SelectedLeader != null)
|
||||||
|
{
|
||||||
|
var idx = Players.IndexOf(SelectedLeader);
|
||||||
|
if (idx >= 0) leaderIndex = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
team.LeaderId = playerEntries[leaderIndex].Player.Id;
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Team '{TeamName}' saved successfully";
|
||||||
|
await LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task DeleteTeam()
|
||||||
|
{
|
||||||
|
if (SelectedTeam == null || SelectedTeam.Id == 0)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a team to delete";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var team = await _context.Teams
|
||||||
|
.Include(t => t.Players)
|
||||||
|
.FirstOrDefaultAsync(t => t.Id == SelectedTeam.Id);
|
||||||
|
|
||||||
|
if (team == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Team not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Teams.Remove(team);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
StatusMessage = $"Team '{team.Name}' deleted";
|
||||||
|
await LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void AddPlayer()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(NewPlayerName))
|
||||||
|
{
|
||||||
|
StatusMessage = "Player name is required";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var entry = new PlayerEntry
|
||||||
|
{
|
||||||
|
Name = NewPlayerName,
|
||||||
|
Contact = NewPlayerContact
|
||||||
|
};
|
||||||
|
Players.Add(entry);
|
||||||
|
|
||||||
|
if (SelectedLeader == null)
|
||||||
|
{
|
||||||
|
SelectedLeader = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewPlayerName = string.Empty;
|
||||||
|
NewPlayerContact = string.Empty;
|
||||||
|
StatusMessage = $"Player '{entry.Name}' added";
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void RemovePlayer()
|
||||||
|
{
|
||||||
|
if (SelectedPlayer == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a player to remove";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var wasLeader = SelectedLeader == SelectedPlayer;
|
||||||
|
Players.Remove(SelectedPlayer);
|
||||||
|
|
||||||
|
if (wasLeader)
|
||||||
|
{
|
||||||
|
SelectedLeader = Players.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedPlayer = null;
|
||||||
|
StatusMessage = "Player removed";
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void SetLeader()
|
||||||
|
{
|
||||||
|
if (SelectedPlayer == null)
|
||||||
|
{
|
||||||
|
StatusMessage = "Select a player to make leader";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedLeader = SelectedPlayer;
|
||||||
|
StatusMessage = $"{SelectedPlayer.Name} is now the leader";
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnSelectedTeamChanged(TeamDisplay? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
IsEditing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TeamName = value.Name;
|
||||||
|
Players.Clear();
|
||||||
|
foreach (var player in value.Players)
|
||||||
|
{
|
||||||
|
Players.Add(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedLeader = Players.FirstOrDefault(p => p.Id == value.LeaderId);
|
||||||
|
SelectedPlayer = null;
|
||||||
|
IsEditing = true;
|
||||||
|
NewPlayerName = string.Empty;
|
||||||
|
NewPlayerContact = string.Empty;
|
||||||
|
StatusMessage = $"Editing team '{value.Name}'";
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnFilterMemberNameChanged(string value) => ApplyFilters();
|
||||||
|
|
||||||
|
private async void ApplyFilters()
|
||||||
|
{
|
||||||
|
await LoadTeams();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> GetAssociatedEvents(Team team)
|
||||||
|
{
|
||||||
|
var events = new List<string>();
|
||||||
|
if (team.Matches != null)
|
||||||
|
{
|
||||||
|
foreach (var tp in team.Matches)
|
||||||
|
{
|
||||||
|
if (tp.Round?.Tournament?.Event != null)
|
||||||
|
{
|
||||||
|
var eventName = tp.Round.Tournament.Event.Name;
|
||||||
|
if (!events.Contains(eventName))
|
||||||
|
{
|
||||||
|
events.Add(eventName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> GetAssociatedTournaments(Team team)
|
||||||
|
{
|
||||||
|
var tournaments = new List<string>();
|
||||||
|
if (team.Matches != null)
|
||||||
|
{
|
||||||
|
foreach (var tp in team.Matches)
|
||||||
|
{
|
||||||
|
if (tp.Round?.Tournament != null)
|
||||||
|
{
|
||||||
|
var tournamentName = GetTournamentDisplayName(tp.Round.Tournament);
|
||||||
|
if (!tournaments.Contains(tournamentName))
|
||||||
|
{
|
||||||
|
tournaments.Add(tournamentName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tournaments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetTournamentDisplayName(Tournament tournament)
|
||||||
|
{
|
||||||
|
return $"{tournament.Game.Name} @ {tournament.Event.Name}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TeamDisplay
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public int? LeaderId { get; set; }
|
||||||
|
public string? LeaderName { get; set; }
|
||||||
|
public List<PlayerEntry> Players { get; set; } = [];
|
||||||
|
public List<string> AssociatedEvents { get; set; } = [];
|
||||||
|
public List<string> AssociatedTournaments { get; set; } = [];
|
||||||
|
|
||||||
|
public TeamDisplay() { }
|
||||||
|
|
||||||
|
public TeamDisplay(Team team)
|
||||||
|
{
|
||||||
|
Id = team.Id;
|
||||||
|
Name = team.Name;
|
||||||
|
LeaderId = team.LeaderId;
|
||||||
|
LeaderName = team.Leader?.Name;
|
||||||
|
Players = team.Players?.Select(p => new PlayerEntry(p)).ToList() ?? [];
|
||||||
|
|
||||||
|
var events = new HashSet<string>();
|
||||||
|
var tournaments = new HashSet<string>();
|
||||||
|
|
||||||
|
if (team.Matches != null)
|
||||||
|
{
|
||||||
|
foreach (var tp in team.Matches)
|
||||||
|
{
|
||||||
|
if (tp.Round?.Tournament != null)
|
||||||
|
{
|
||||||
|
tournaments.Add(TeamsViewModel.GetTournamentDisplayName(tp.Round.Tournament));
|
||||||
|
if (tp.Round.Tournament.Event != null)
|
||||||
|
{
|
||||||
|
events.Add(tp.Round.Tournament.Event.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssociatedEvents = events.ToList();
|
||||||
|
AssociatedTournaments = tournaments.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class PlayerEntry : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private int _id;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _name = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _contact = string.Empty;
|
||||||
|
|
||||||
|
public PlayerEntry() { }
|
||||||
|
|
||||||
|
public PlayerEntry(Player player)
|
||||||
|
{
|
||||||
|
Id = player.Id;
|
||||||
|
Name = player.Name;
|
||||||
|
Contact = player.Contact;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,143 @@
|
|||||||
|
<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.EventsView"
|
||||||
|
x:DataType="vm:EventsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:EventsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<UserControl.Styles>
|
||||||
|
<Style Selector="Button.dropdown-item">
|
||||||
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.dropdown-item:pointerover">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Styles>
|
||||||
|
|
||||||
|
<Grid RowDefinitions="Auto,*,Auto" ColumnDefinitions="*,*">
|
||||||
|
<TextBlock Grid.ColumnSpan="2" Grid.Row="0" Text="Events Management" FontSize="20" FontWeight="Bold" Margin="16,16,16,8"/>
|
||||||
|
|
||||||
|
<!-- Left Panel: Event List and Filter -->
|
||||||
|
<Border Grid.Column="0" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<!-- Header with New Event button -->
|
||||||
|
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,8">
|
||||||
|
<Button Command="{Binding CreateNewEventCommand}" DockPanel.Dock="Right" Padding="8,4">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||||
|
<TextBlock Text="+" FontSize="16" FontWeight="Bold" VerticalAlignment="Center"/>
|
||||||
|
<TextBlock Text="New Event" VerticalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<TextBlock Text="Events" FontSize="16" FontWeight="SemiBold" VerticalAlignment="Center"/>
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
|
<!-- Filter -->
|
||||||
|
<StackPanel DockPanel.Dock="Top" Spacing="6" Margin="0,0,0,8">
|
||||||
|
<TextBlock Text="Filters" FontWeight="SemiBold" FontSize="12"/>
|
||||||
|
<TextBox Watermark="Filter by event name..." Text="{Binding FilterEventName}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Event List -->
|
||||||
|
<ListBox ItemsSource="{Binding Events}"
|
||||||
|
SelectedItem="{Binding SelectedEvent}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:EventDisplay">
|
||||||
|
<StackPanel Spacing="2">
|
||||||
|
<TextBlock Text="{Binding Name}" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="{Binding Start, StringFormat='{}{0:d}'}" FontSize="11" Foreground="Gray"/>
|
||||||
|
<TextBlock Text="{Binding End, StringFormat='to {0:d}'}" FontSize="11" Foreground="Gray"/>
|
||||||
|
<ItemsControl ItemsSource="{Binding TournamentNames}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="x:String">
|
||||||
|
<TextBlock Text="{Binding, StringFormat='Game: {0}'}" FontSize="10" Foreground="#1976D2"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Right Panel: Event Editor -->
|
||||||
|
<Border Grid.Column="1" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" Text="Event Details" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8"/>
|
||||||
|
|
||||||
|
<StackPanel DockPanel.Dock="Bottom" Spacing="6" Margin="0,8,0,0">
|
||||||
|
<Button Content="Save Event" Command="{Binding SaveEventCommand}" HorizontalAlignment="Stretch" IsEnabled="{Binding IsEditing}"/>
|
||||||
|
<Button Content="Delete Event" Command="{Binding DeleteEventCommand}" HorizontalAlignment="Stretch" IsEnabled="{Binding IsEditing}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<ScrollViewer>
|
||||||
|
<StackPanel Spacing="8" IsEnabled="{Binding IsEditing}">
|
||||||
|
<!-- Event Name -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Event Name" FontWeight="SemiBold"/>
|
||||||
|
<TextBox Text="{Binding EventName}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Start Date -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Start Date" FontWeight="SemiBold"/>
|
||||||
|
<CalendarDatePicker SelectedDate="{Binding EventStart}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- End Date -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="End Date" FontWeight="SemiBold"/>
|
||||||
|
<CalendarDatePicker SelectedDate="{Binding EventEnd}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Tournaments / Games Section -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Tournaments" FontWeight="SemiBold"/>
|
||||||
|
|
||||||
|
<!-- Add Game Dropdown -->
|
||||||
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="4">
|
||||||
|
<ComboBox Grid.Column="0" ItemsSource="{Binding AvailableGamesToAdd}" SelectedItem="{Binding SelectedGameToAdd}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:GameOption">
|
||||||
|
<TextBlock Text="{Binding DisplayName}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
<Button Grid.Column="1" Content="Add" Command="{Binding AddGameToEventCommand}" IsEnabled="{Binding SelectedGameToAdd, Converter={x:Static ObjectConverters.IsNotNull}}" VerticalAlignment="Center"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Tournament List -->
|
||||||
|
<ListBox ItemsSource="{Binding Tournaments}"
|
||||||
|
SelectedItem="{Binding SelectedTournament}"
|
||||||
|
MinHeight="100"
|
||||||
|
MaxHeight="200">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:TournamentDisplay">
|
||||||
|
<StackPanel Spacing="2">
|
||||||
|
<TextBlock Text="{Binding GameName}" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="{Binding S1RuleSetName, StringFormat='Stage 1: {0}'}" FontSize="11" Foreground="Gray"/>
|
||||||
|
<TextBlock Text="{Binding S2RuleSetName, StringFormat='Stage 2: {0}'}" FontSize="11" Foreground="Gray" IsVisible="{Binding S2RuleSet, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
|
||||||
|
<Button Content="Remove Selected" Command="{Binding RemoveGameFromEventCommand}" IsEnabled="{Binding SelectedTournament, Converter={x:Static ObjectConverters.IsNotNull}}" HorizontalAlignment="Left"/>
|
||||||
|
</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,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Views;
|
||||||
|
|
||||||
|
public partial class EventsView : UserControl
|
||||||
|
{
|
||||||
|
public EventsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
<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.GamesView"
|
||||||
|
x:DataType="vm:GamesViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:GamesViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<UserControl.Styles>
|
||||||
|
<Style Selector="Button.dropdown-item">
|
||||||
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.dropdown-item:pointerover">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundListLowBrush}"/>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Styles>
|
||||||
|
|
||||||
|
<Grid RowDefinitions="Auto,*,Auto" ColumnDefinitions="*,*">
|
||||||
|
<TextBlock Grid.ColumnSpan="2" Grid.Row="0" Text="Games Management" FontSize="20" FontWeight="Bold" Margin="16,16,16,8"/>
|
||||||
|
|
||||||
|
<!-- Left Panel: Game List and Filter -->
|
||||||
|
<Border Grid.Column="0" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<!-- Header with New Game button -->
|
||||||
|
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,8">
|
||||||
|
<Button Command="{Binding CreateNewGameCommand}" DockPanel.Dock="Right" Padding="8,4">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||||
|
<TextBlock Text="+" FontSize="16" FontWeight="Bold" VerticalAlignment="Center"/>
|
||||||
|
<TextBlock Text="New Game" VerticalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<TextBlock Text="Games" FontSize="16" FontWeight="SemiBold" VerticalAlignment="Center"/>
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
|
<!-- Filter -->
|
||||||
|
<StackPanel DockPanel.Dock="Top" Spacing="6" Margin="0,0,0,8">
|
||||||
|
<TextBlock Text="Filters" FontWeight="SemiBold" FontSize="12"/>
|
||||||
|
<TextBox Watermark="Filter by game name..." Text="{Binding FilterGameName}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Game List -->
|
||||||
|
<ListBox ItemsSource="{Binding Games}"
|
||||||
|
SelectedItem="{Binding SelectedGame}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:GameDisplay">
|
||||||
|
<StackPanel Spacing="2">
|
||||||
|
<TextBlock Text="{Binding Name}" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="{Binding S1RuleSetName, StringFormat='Stage 1: {0}'}" FontSize="11" Foreground="Gray"/>
|
||||||
|
<TextBlock Text="{Binding S2RuleSetName, StringFormat='Stage 2: {0}'}" FontSize="11" Foreground="Gray" IsVisible="{Binding S2RuleSet, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
||||||
|
<ItemsControl ItemsSource="{Binding AssociatedEvents}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="x:String">
|
||||||
|
<TextBlock Text="{Binding, StringFormat='Event: {0}'}" FontSize="10" Foreground="#1976D2"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Right Panel: Game Editor -->
|
||||||
|
<Border Grid.Column="1" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" Text="Game Details" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8"/>
|
||||||
|
|
||||||
|
<StackPanel DockPanel.Dock="Bottom" Spacing="6" Margin="0,8,0,0">
|
||||||
|
<Button Content="Save Game" Command="{Binding SaveGameCommand}" HorizontalAlignment="Stretch" IsEnabled="{Binding IsEditing}"/>
|
||||||
|
<Button Content="Delete Game" Command="{Binding DeleteGameCommand}" HorizontalAlignment="Stretch" IsEnabled="{Binding IsEditing}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<ScrollViewer>
|
||||||
|
<StackPanel Spacing="8" IsEnabled="{Binding IsEditing}">
|
||||||
|
<!-- Game Name -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Game Name" FontWeight="SemiBold"/>
|
||||||
|
<TextBox Text="{Binding GameName}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Description" FontWeight="SemiBold"/>
|
||||||
|
<TextBox Text="{Binding GameDescription}" AcceptsReturn="True" TextWrapping="Wrap" MinHeight="60"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Stage 1 -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Stage 1 Rule Set" FontWeight="SemiBold"/>
|
||||||
|
<ComboBox ItemsSource="{Binding S1RuleSetOptions}" SelectedItem="{Binding SelectedS1RuleSet}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:RuleSetOption">
|
||||||
|
<TextBlock Text="{Binding Label}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Stage 2 (optional) -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Stage 2 Rule Set (optional)" FontWeight="SemiBold"/>
|
||||||
|
<ComboBox ItemsSource="{Binding S2RuleSetOptions}" SelectedItem="{Binding SelectedS2RuleSet}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:RuleSetOption">
|
||||||
|
<TextBlock Text="{Binding Label}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Stage 1 Group Settings (only shown when Stage 2 is enabled) -->
|
||||||
|
<StackPanel Spacing="4" IsVisible="{Binding ShowStage1GroupSettings}">
|
||||||
|
<TextBlock Text="Stage 1 Groups" FontWeight="SemiBold"/>
|
||||||
|
<NumericUpDown Value="{Binding S1Groups}" Minimum="1" Maximum="100"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Spacing="4" IsVisible="{Binding ShowStage1GroupSettings}">
|
||||||
|
<TextBlock Text="Stage 1 Group Advances" FontWeight="SemiBold"/>
|
||||||
|
<NumericUpDown Value="{Binding S1GroupAdvances}" Minimum="1" Maximum="100"/>
|
||||||
|
</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,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Views;
|
||||||
|
|
||||||
|
public partial class GamesView : UserControl
|
||||||
|
{
|
||||||
|
public GamesView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<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="800" d:DesignHeight="450"
|
||||||
|
x:Class="TournamentOrganizer.Views.HomeView"
|
||||||
|
x:DataType="vm:HomeViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:HomeViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
|
<TextBlock Text="{Binding WelcomeMessage}"
|
||||||
|
FontSize="24"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"/>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace TournamentOrganizer.Views;
|
||||||
|
|
||||||
|
public partial class HomeView : UserControl
|
||||||
|
{
|
||||||
|
public HomeView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,29 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:vm="using:TournamentOrganizer.ViewModels"
|
xmlns:vm="using:TournamentOrganizer.ViewModels"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="600"
|
||||||
x:Class="TournamentOrganizer.Views.MainView"
|
x:Class="TournamentOrganizer.Views.MainView"
|
||||||
x:DataType="vm:MainViewModel">
|
x:DataType="vm:MainViewModel">
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
<vm:MainViewModel />
|
||||||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
|
</Design.DataContext>
|
||||||
<vm:MainViewModel />
|
|
||||||
</Design.DataContext>
|
<DockPanel>
|
||||||
|
<!-- Navigation Menu -->
|
||||||
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
<Border DockPanel.Dock="Top" Background="#2D2D30" Padding="8">
|
||||||
</UserControl>
|
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||||
|
<Button Content="Home" Command="{Binding NavigateToHomeCommand}" 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="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"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Content Area -->
|
||||||
|
<ContentControl Content="{Binding CurrentView}" Margin="0"/>
|
||||||
|
</DockPanel>
|
||||||
|
</UserControl>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
<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.TeamsView"
|
||||||
|
x:DataType="vm:TeamsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:TeamsViewModel />
|
||||||
|
</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="Teams Management" FontSize="20" FontWeight="Bold" Margin="16,16,16,8"/>
|
||||||
|
|
||||||
|
<!-- Left Panel: Team List and Filters -->
|
||||||
|
<Border Grid.Column="0" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<!-- Header with New Team button -->
|
||||||
|
<DockPanel DockPanel.Dock="Top" Margin="0,0,0,8">
|
||||||
|
<Button Command="{Binding CreateNewTeamCommand}" DockPanel.Dock="Right" Padding="8,4">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||||
|
<TextBlock Text="+" FontSize="16" FontWeight="Bold" VerticalAlignment="Center"/>
|
||||||
|
<TextBlock Text="New Team" VerticalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<TextBlock Text="Teams" FontSize="16" FontWeight="SemiBold" VerticalAlignment="Center"/>
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
|
<!-- Filters -->
|
||||||
|
<StackPanel DockPanel.Dock="Top" Spacing="6" Margin="0,0,0,8">
|
||||||
|
<TextBlock Text="Filters" FontWeight="SemiBold" FontSize="12"/>
|
||||||
|
<TextBox Watermark="Filter by member name..." Text="{Binding FilterMemberName}"/>
|
||||||
|
|
||||||
|
<!-- 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 SelectedEventFilter, Mode=OneWay}"/>
|
||||||
|
<TextBlock Text="Filter by event..." Foreground="Gray" IsVisible="{Binding SelectedEventFilter, 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"
|
||||||
|
SelectionChanged="OnEventSelectionChanged">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="x:String">
|
||||||
|
<TextBlock Text="{Binding}"/>
|
||||||
|
</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 SelectedTournamentFilter, Mode=OneWay}"/>
|
||||||
|
<TextBlock Text="Select an event first..." Foreground="Gray" IsVisible="{Binding SelectedTournamentFilter, 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"
|
||||||
|
SelectionChanged="OnTournamentSelectionChanged">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="x:String">
|
||||||
|
<TextBlock Text="{Binding}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Panel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Team List -->
|
||||||
|
<ListBox ItemsSource="{Binding Teams}"
|
||||||
|
SelectedItem="{Binding SelectedTeam}">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:TeamDisplay">
|
||||||
|
<StackPanel Spacing="2">
|
||||||
|
<TextBlock Text="{Binding Name}" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="{Binding LeaderName, StringFormat='Leader: {0}'}" FontSize="11" Foreground="Gray"/>
|
||||||
|
<TextBlock Text="{Binding Players.Count, StringFormat='{}{0} members'}" FontSize="11" Foreground="Gray"/>
|
||||||
|
<ItemsControl ItemsSource="{Binding AssociatedEvents}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="x:String">
|
||||||
|
<TextBlock Text="{Binding, StringFormat='Event: {0}'}" FontSize="10" Foreground="#1976D2"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
<ItemsControl ItemsSource="{Binding AssociatedTournaments}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="x:String">
|
||||||
|
<TextBlock Text="{Binding, StringFormat='Tournament: {0}'}" FontSize="10" Foreground="#F57C00"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Right Panel: Team Editor -->
|
||||||
|
<Border Grid.Column="1" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" Text="Team Details" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8"/>
|
||||||
|
|
||||||
|
<StackPanel DockPanel.Dock="Bottom" Spacing="6" Margin="0,8,0,0">
|
||||||
|
<Button Content="Save Team" Command="{Binding SaveTeamCommand}" HorizontalAlignment="Stretch" IsEnabled="{Binding IsEditing}"/>
|
||||||
|
<Button Content="Delete Team" Command="{Binding DeleteTeamCommand}" HorizontalAlignment="Stretch" IsEnabled="{Binding IsEditing}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<ScrollViewer>
|
||||||
|
<StackPanel Spacing="8" IsEnabled="{Binding IsEditing}">
|
||||||
|
<!-- Team Name -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Team Name" FontWeight="SemiBold"/>
|
||||||
|
<TextBox Text="{Binding TeamName}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Members Section -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Members" FontWeight="SemiBold"/>
|
||||||
|
|
||||||
|
<!-- Add Player Form -->
|
||||||
|
<Grid ColumnDefinitions="*,*,Auto" RowDefinitions="Auto,Auto" RowSpacing="4" ColumnSpacing="4">
|
||||||
|
<TextBox Grid.Row="0" Grid.Column="0" Watermark="Player name" Text="{Binding NewPlayerName}"/>
|
||||||
|
<TextBox Grid.Row="0" Grid.Column="1" Watermark="Contact (optional)" Text="{Binding NewPlayerContact}"/>
|
||||||
|
<Button Grid.Row="0" Grid.Column="2" Content="Add" Command="{Binding AddPlayerCommand}" VerticalAlignment="Center"/>
|
||||||
|
|
||||||
|
<Button Grid.Row="1" Grid.Column="0" Content="Remove" Command="{Binding RemovePlayerCommand}"/>
|
||||||
|
<Button Grid.Row="1" Grid.Column="1" Content="Set as Leader" Command="{Binding SetLeaderCommand}"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Players List -->
|
||||||
|
<ListBox ItemsSource="{Binding Players}"
|
||||||
|
SelectedItem="{Binding SelectedPlayer}"
|
||||||
|
MinHeight="150"
|
||||||
|
MaxHeight="250">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:PlayerEntry">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
<TextBlock Text="{Binding Name}" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="{Binding Contact}" Foreground="Gray" FontSize="11"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Current Leader Display -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Current Leader" FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="{Binding SelectedLeader.Name}" IsVisible="{Binding SelectedLeader, Converter={x:Static ObjectConverters.IsNotNull}}"/>
|
||||||
|
<TextBlock Text="No leader set" IsVisible="{Binding SelectedLeader, Converter={x:Static ObjectConverters.IsNull}}" Foreground="Gray"/>
|
||||||
|
</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 TeamsView : UserControl
|
||||||
|
{
|
||||||
|
public TeamsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEventSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ListBox { SelectedItem: string eventName } && DataContext is TeamsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.SelectEventFilter(eventName);
|
||||||
|
if (EventFilterToggle != null)
|
||||||
|
EventFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTournamentSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ListBox { SelectedItem: string tournamentName } && DataContext is TeamsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.SelectTournamentFilter(tournamentName);
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearEventFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is TeamsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearEventFilter();
|
||||||
|
if (EventFilterToggle != null)
|
||||||
|
EventFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearTournamentFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is TeamsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearTournamentFilter();
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
<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.TournamentsView"
|
||||||
|
x:DataType="vm:TournamentsViewModel">
|
||||||
|
<Design.DataContext>
|
||||||
|
<vm:TournamentsViewModel />
|
||||||
|
</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="Tournament 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: Tournament Editor and Teams -->
|
||||||
|
<Border Grid.Column="1" Grid.Row="1" BorderBrush="Gray" BorderThickness="1" Margin="8" CornerRadius="4" Padding="8">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" Text="Tournament Details" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,8"/>
|
||||||
|
|
||||||
|
<Button DockPanel.Dock="Bottom" Content="Save Tournament" Command="{Binding SaveTournamentCommand}" HorizontalAlignment="Stretch" IsEnabled="{Binding IsEditing}" Margin="0,8,0,0"/>
|
||||||
|
|
||||||
|
<ScrollViewer>
|
||||||
|
<StackPanel Spacing="8" IsEnabled="{Binding IsEditing}">
|
||||||
|
<!-- Dates -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Start Date" FontWeight="SemiBold"/>
|
||||||
|
<CalendarDatePicker SelectedDate="{Binding TournamentStart}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="End Date" FontWeight="SemiBold"/>
|
||||||
|
<CalendarDatePicker SelectedDate="{Binding TournamentEnd}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Stage 1 Rule Set -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Stage 1 Rule Set" FontWeight="SemiBold"/>
|
||||||
|
<ComboBox ItemsSource="{Binding S1RuleSetOptions}" SelectedItem="{Binding SelectedS1RuleSet}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:RuleSetOption">
|
||||||
|
<TextBlock Text="{Binding Label}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Stage 1 Groups (only if Stage 2 is set) -->
|
||||||
|
<StackPanel Spacing="4" IsVisible="{Binding SelectedS2RuleSet.Value, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
|
<TextBlock Text="Stage 1 Groups" FontWeight="SemiBold"/>
|
||||||
|
<NumericUpDown Value="{Binding S1Groups}" Minimum="1" Maximum="100"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Spacing="4" IsVisible="{Binding SelectedS2RuleSet.Value, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
|
<TextBlock Text="Stage 1 Group Advances" FontWeight="SemiBold"/>
|
||||||
|
<NumericUpDown Value="{Binding S1GroupAdvances}" Minimum="1" Maximum="100"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Stage 2 Rule Set -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Stage 2 Rule Set (optional)" FontWeight="SemiBold"/>
|
||||||
|
<ComboBox ItemsSource="{Binding S2RuleSetOptions}" SelectedItem="{Binding SelectedS2RuleSet}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:RuleSetOption">
|
||||||
|
<TextBlock Text="{Binding Label}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Teams Section -->
|
||||||
|
<StackPanel Spacing="4">
|
||||||
|
<TextBlock Text="Participating Teams" FontWeight="SemiBold"/>
|
||||||
|
|
||||||
|
<!-- Add Team -->
|
||||||
|
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="4">
|
||||||
|
<ComboBox Grid.Column="0" ItemsSource="{Binding AvailableTeams}" SelectedItem="{Binding SelectedTeamToAdd}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:TeamOption">
|
||||||
|
<TextBlock Text="{Binding DisplayName}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
<Button Grid.Column="1" Content="Add" Command="{Binding AddTeamToTournamentCommand}" IsEnabled="{Binding SelectedTeamToAdd, Converter={x:Static ObjectConverters.IsNotNull}}" VerticalAlignment="Center"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Teams List -->
|
||||||
|
<ListBox ItemsSource="{Binding ParticipatingTeams}"
|
||||||
|
SelectedItem="{Binding SelectedParticipatingTeam}"
|
||||||
|
MinHeight="100"
|
||||||
|
MaxHeight="150">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="vm:ParticipatingTeam">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
<TextBlock Text="{Binding Seed, StringFormat='#{0}'}" FontWeight="SemiBold" Foreground="Gray"/>
|
||||||
|
<TextBlock Text="{Binding Name}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
|
||||||
|
<Grid ColumnDefinitions="*,*" ColumnSpacing="4">
|
||||||
|
<Button Grid.Column="0" Content="Remove" Command="{Binding RemoveTeamFromTournamentCommand}" IsEnabled="{Binding SelectedParticipatingTeam, Converter={x:Static ObjectConverters.IsNotNull}}" HorizontalAlignment="Stretch"/>
|
||||||
|
<Button Grid.Column="1" Content="Reseed" Command="{Binding ReseedTeamsCommand}" HorizontalAlignment="Stretch"/>
|
||||||
|
</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 TournamentsView : UserControl
|
||||||
|
{
|
||||||
|
public TournamentsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEventSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is ListBox { SelectedItem: EventOption option } && DataContext is TournamentsViewModel 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 TournamentsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.SelectTournamentFilter(option);
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearEventFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is TournamentsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearEventFilter();
|
||||||
|
if (EventFilterToggle != null)
|
||||||
|
EventFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClearTournamentFilter(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is TournamentsViewModel vm)
|
||||||
|
{
|
||||||
|
vm.ClearTournamentFilter();
|
||||||
|
if (TournamentFilterToggle != null)
|
||||||
|
TournamentFilterToggle.IsChecked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user