Add Team functions
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
||||
<link href="@Assets["_content/MudBlazor/MudBlazor.min.css"]" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
<link rel="stylesheet" href="WebApp.styles.css" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<HeadOutlet />
|
||||
</head>
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
using MudBlazor;
|
||||
|
||||
namespace WebApp.Components.Layout
|
||||
{
|
||||
public static class CustomThemes
|
||||
{
|
||||
/*
|
||||
!
|
||||
* Bootswatch v5.3.3 (https://bootswatch.com)
|
||||
* Theme: cerulean
|
||||
* Copyright 2012-2024 Thomas Park
|
||||
* Licensed under MIT
|
||||
* Based on Bootstrap
|
||||
*/
|
||||
public static readonly MudTheme Ceruleantheme = new()
|
||||
{
|
||||
PaletteLight = new PaletteLight()
|
||||
{
|
||||
Black = "#000",
|
||||
White = "#fff",
|
||||
Primary = "#2fa4e7ff",
|
||||
PrimaryContrastText = "#d5edfaff",
|
||||
Secondary = "#e9ecef",
|
||||
SecondaryContrastText = "#495057ff",
|
||||
Tertiary = "#dee2e6ff",
|
||||
TertiaryContrastText = "#495057ff",
|
||||
Info = "#033c73",
|
||||
InfoContrastText = "#cdd8e3",
|
||||
Success = "#73a839",
|
||||
SuccessContrastText = "#e3eed7",
|
||||
Warning = "#dd5600",
|
||||
WarningContrastText = "#f8ddcc",
|
||||
Error = "rgba(244,67,54,1)",
|
||||
ErrorContrastText = "rgba(255,255,255,1)",
|
||||
Dark = "#343a40",
|
||||
DarkContrastText = "#ced4da",
|
||||
TextPrimary = "#13425cff",
|
||||
TextSecondary = "#5d5e60",
|
||||
TextDisabled = "rgba(0,0,0,0.3764705882352941)",
|
||||
ActionDefault = "rgba(0,0,0,0.5372549019607843)",
|
||||
ActionDisabled = "rgba(0,0,0,0.25882352941176473)",
|
||||
ActionDisabledBackground = "rgba(0,0,0,0.11764705882352941)",
|
||||
Background = "rgba(255,255,255,1)",
|
||||
BackgroundGray = "rgba(245,245,245,1)",
|
||||
Surface = "rgba(255,255,255,1)",
|
||||
DrawerBackground = "#e9ecefff",
|
||||
DrawerText = "#495057ff",
|
||||
DrawerIcon = "#e9ecef",
|
||||
AppbarBackground = "#2fa4e7ff",
|
||||
AppbarText = "#d5edfaff",
|
||||
LinesDefault = "rgba(0,0,0,0.11764705882352941)",
|
||||
LinesInputs = "rgba(189,189,189,1)",
|
||||
TableLines = "rgba(224,224,224,1)",
|
||||
TableStriped = "rgba(0,0,0,0.0196078431372549)",
|
||||
TableHover = "rgba(0,0,0,0.0392156862745098)",
|
||||
Divider = "rgba(224,224,224,1)",
|
||||
DividerLight = "rgba(0,0,0,0.8)",
|
||||
PrimaryDarken = "#13425c",
|
||||
PrimaryLighten = "#d5edfa",
|
||||
SecondaryDarken = "#5d5e60",
|
||||
SecondaryLighten = "#fbfbfc",
|
||||
TertiaryDarken = "rgba(73, 80, 87, 0.5)",
|
||||
TertiaryLighten = "rgba(73, 80, 87, 0.5)",
|
||||
InfoDarken = "#01182e",
|
||||
InfoLighten = "#cdd8e3",
|
||||
SuccessDarken = "#2e4317",
|
||||
SuccessLighten = "#e3eed7",
|
||||
WarningDarken = "#582200",
|
||||
WarningLighten = "#f8ddcc",
|
||||
ErrorDarken = "rgb(242,28,13)",
|
||||
ErrorLighten = "rgb(246,96,85)",
|
||||
DarkDarken = "rgb(46,46,46)",
|
||||
DarkLighten = "rgb(87,87,87)",
|
||||
HoverOpacity = 0.06,
|
||||
RippleOpacity = 0.1,
|
||||
RippleOpacitySecondary = 0.2,
|
||||
GrayDefault = "#9E9E9E",
|
||||
GrayLight = "#BDBDBD",
|
||||
GrayLighter = "#E0E0E0",
|
||||
GrayDark = "#757575",
|
||||
GrayDarker = "#616161",
|
||||
OverlayDark = "rgba(33,33,33,0.4980392156862745)",
|
||||
OverlayLight = "rgba(255,255,255,0.4980392156862745)",
|
||||
},
|
||||
PaletteDark = new PaletteDark()
|
||||
{
|
||||
Black = "#000",
|
||||
White = "#fff",
|
||||
Primary = "#2fa4e7ff",
|
||||
PrimaryContrastText = "#d5edfaff",
|
||||
Secondary = "#e9ecef",
|
||||
SecondaryContrastText = "#2f2f30",
|
||||
Tertiary = "rgba(222, 226, 230, 0.5)",
|
||||
TertiaryContrastText = "#2b3035",
|
||||
Info = "#026e8eff",
|
||||
InfoContrastText = "#010c17",
|
||||
Success = "#73a839",
|
||||
SuccessContrastText = "#17220b",
|
||||
Warning = "#dd5600",
|
||||
WarningContrastText = "#2c1100",
|
||||
Error = "rgba(244,67,54,1)",
|
||||
ErrorContrastText = "rgba(255,255,255,1)",
|
||||
Dark = "#343a40ff",
|
||||
DarkContrastText = "#1a1d20",
|
||||
TextPrimary = "#82c8f1",
|
||||
TextSecondary = "#f2f4f5",
|
||||
TextDisabled = "rgba(255,255,255,0.2)",
|
||||
ActionDefault = "rgba(173,173,177,1)",
|
||||
ActionDisabled = "rgba(255,255,255,0.25882352941176473)",
|
||||
ActionDisabledBackground = "rgba(255,255,255,0.11764705882352941)",
|
||||
Background = "rgba(50,51,61,1)",
|
||||
BackgroundGray = "rgba(39,39,47,1)",
|
||||
Surface = "#212529ff",
|
||||
DrawerBackground = "#2f2f30ff",
|
||||
DrawerText = "#e9ecef",
|
||||
DrawerIcon = "#e9ecef",
|
||||
AppbarBackground = "#2fa4e7ff",
|
||||
AppbarText = "#d5edfaff",
|
||||
LinesDefault = "rgba(255,255,255,0.11764705882352941)",
|
||||
LinesInputs = "rgba(255,255,255,0.2980392156862745)",
|
||||
TableLines = "rgba(255,255,255,0.11764705882352941)",
|
||||
TableStriped = "rgba(255,255,255,0.2)",
|
||||
Divider = "#ffffff73",
|
||||
DividerLight = "#ffffff2e",
|
||||
PrimaryDarken = "#82c8f1",
|
||||
PrimaryLighten = "#09212e",
|
||||
SecondaryDarken = "#f2f4f5",
|
||||
SecondaryLighten = "#2f2f30",
|
||||
TertiaryDarken = "rgba(222, 226, 230, 0.5)",
|
||||
TertiaryLighten = "rgba(222, 226, 230, 0.5)",
|
||||
InfoDarken = "#688aab",
|
||||
InfoLighten = "#010c17",
|
||||
SuccessDarken = "#abcb88",
|
||||
SuccessLighten = "#17220b",
|
||||
WarningDarken = "#eb9a66",
|
||||
WarningLighten = "#2c1100",
|
||||
ErrorDarken = "rgb(242,28,13)",
|
||||
ErrorLighten = "rgb(246,96,85)",
|
||||
DarkDarken = "rgb(23,23,28)",
|
||||
DarkLighten = "rgb(56,56,67)",
|
||||
},
|
||||
LayoutProperties = new LayoutProperties()
|
||||
{
|
||||
DefaultBorderRadius = "4px",
|
||||
DrawerMiniWidthLeft = "56px",
|
||||
DrawerMiniWidthRight = "56px",
|
||||
DrawerWidthLeft = "240px",
|
||||
DrawerWidthRight = "240px",
|
||||
AppbarHeight = "64px",
|
||||
},
|
||||
Typography = new Typography()
|
||||
{
|
||||
Default = new DefaultTypography
|
||||
{
|
||||
FontFamily = ["Roboto", "Helvetica", "Arial", "sans-serif"],
|
||||
FontWeight = "400",
|
||||
FontSize = ".875rem",
|
||||
LineHeight = "1.43",
|
||||
LetterSpacing = ".01071em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
H1 = new H1Typography
|
||||
{
|
||||
FontWeight = "300",
|
||||
FontSize = "6rem",
|
||||
LineHeight = "1.167",
|
||||
LetterSpacing = "-.01562em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
H2 = new H2Typography
|
||||
{
|
||||
FontWeight = "300",
|
||||
FontSize = "3.75rem",
|
||||
LineHeight = "1.2",
|
||||
LetterSpacing = "-.00833em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
H3 = new H3Typography
|
||||
{
|
||||
FontWeight = "400",
|
||||
FontSize = "3rem",
|
||||
LineHeight = "1.167",
|
||||
LetterSpacing = "0",
|
||||
TextTransform = "none",
|
||||
},
|
||||
H4 = new H4Typography
|
||||
{
|
||||
FontWeight = "400",
|
||||
FontSize = "2.125rem",
|
||||
LineHeight = "1.235",
|
||||
LetterSpacing = ".00735em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
H5 = new H5Typography
|
||||
{
|
||||
FontWeight = "400",
|
||||
FontSize = "1.5rem",
|
||||
LineHeight = "1.334",
|
||||
LetterSpacing = "0",
|
||||
TextTransform = "none",
|
||||
},
|
||||
H6 = new H6Typography
|
||||
{
|
||||
FontWeight = "500",
|
||||
FontSize = "1.25rem",
|
||||
LineHeight = "1.6",
|
||||
LetterSpacing = ".0075em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
Subtitle1 = new Subtitle1Typography
|
||||
{
|
||||
FontWeight = "400",
|
||||
FontSize = "1rem",
|
||||
LineHeight = "1.75",
|
||||
LetterSpacing = ".00938em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
Subtitle2 = new Subtitle2Typography
|
||||
{
|
||||
FontWeight = "500",
|
||||
FontSize = ".875rem",
|
||||
LineHeight = "1.57",
|
||||
LetterSpacing = ".00714em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
Body1 = new Body1Typography
|
||||
{
|
||||
FontWeight = "400",
|
||||
FontSize = "1rem",
|
||||
LineHeight = "1.5",
|
||||
LetterSpacing = ".00938em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
Body2 = new Body2Typography
|
||||
{
|
||||
FontWeight = "400",
|
||||
FontSize = ".875rem",
|
||||
LineHeight = "1.43",
|
||||
LetterSpacing = ".01071em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
Button = new ButtonTypography
|
||||
{
|
||||
FontWeight = "500",
|
||||
FontSize = ".875rem",
|
||||
LineHeight = "1.75",
|
||||
LetterSpacing = ".02857em",
|
||||
TextTransform = "uppercase",
|
||||
},
|
||||
Caption = new CaptionTypography
|
||||
{
|
||||
FontWeight = "400",
|
||||
FontSize = ".75rem",
|
||||
LineHeight = "1.66",
|
||||
LetterSpacing = ".03333em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
Overline = new OverlineTypography
|
||||
{
|
||||
FontWeight = "400",
|
||||
FontSize = ".75rem",
|
||||
LineHeight = "2.66",
|
||||
LetterSpacing = ".08333em",
|
||||
TextTransform = "none",
|
||||
},
|
||||
},
|
||||
ZIndex = new ZIndex()
|
||||
{
|
||||
Drawer = 1100,
|
||||
Popover = 1200,
|
||||
AppBar = 1300,
|
||||
Dialog = 1400,
|
||||
Snackbar = 1500,
|
||||
Tooltip = 1600,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,32 @@
|
||||
@inherits LayoutComponentBase
|
||||
@inject IConfiguration Configuration
|
||||
|
||||
<MudThemeProvider />
|
||||
<MudThemeProvider Theme="CustomThemes.Ceruleantheme" />
|
||||
<MudPopoverProvider />
|
||||
<MudDialogProvider />
|
||||
|
||||
<div class="page">
|
||||
|
||||
<div class="sidebar">
|
||||
<MudLayout>
|
||||
<MudAppBar Class="no-print">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
|
||||
TSA Chapter Organizer - @Configuration["ChapterSettings:Name"]
|
||||
</MudAppBar>
|
||||
<MudDrawer @bind-Open="@_drawerOpen" Class="no-print">
|
||||
<NavMenu/>
|
||||
</div>
|
||||
</MudDrawer>
|
||||
<MudMainContent>
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge">
|
||||
@Body
|
||||
</MudContainer>
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
@code {
|
||||
bool _drawerOpen = true;
|
||||
|
||||
<main>
|
||||
@* <div class="top-row px-4">
|
||||
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
|
||||
</div> *@
|
||||
|
||||
<article class="content px-4">
|
||||
@Body
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
void DrawerToggle()
|
||||
{
|
||||
_drawerOpen = !_drawerOpen;
|
||||
}
|
||||
}
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
|
||||
@@ -1,43 +1,20 @@
|
||||
<div class="top-row ps-3 navbar navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="">WebApp</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
|
||||
|
||||
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
|
||||
<nav class="flex-column">
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="events">
|
||||
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Events
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="students">
|
||||
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Students
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="teams">
|
||||
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Teams
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="import">
|
||||
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Import
|
||||
</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
@using WebApp.Models
|
||||
@inject IConfiguration Configuration
|
||||
|
||||
<MudPaper Width="250px" Class="d-inline-flex py-3" Elevation="0">
|
||||
<MudNavMenu Class="mud-width-full">
|
||||
<MudText Typo="Typo.h6" Class="px-4">TSA Chapter Organizer</MudText>
|
||||
<MudText Typo="Typo.body2" Class="px-4 mud-text-secondary">@Configuration["ChapterSettings:Name"]</MudText>
|
||||
<MudDivider Class="my-2" />
|
||||
<MudNavLink Href="/events" Icon="@AppIcons.Events">Events</MudNavLink>
|
||||
<MudNavGroup Title="Students" Icon="@Icons.Material.Filled.People" Expanded="true">
|
||||
<MudNavLink Href="/students" Icon="@Icons.Material.Filled.People">Students</MudNavLink>
|
||||
<MudNavLink Href="/students/event-ranking" Icon="@AppIcons.EventRank">Event Ranking</MudNavLink>
|
||||
</MudNavGroup>
|
||||
<MudNavGroup Title="Teams" Icon="@Icons.Material.Outlined.Groups" Expanded="true">
|
||||
<MudNavLink Href="/teams" Icon="@AppIcons.Teams">Teams</MudNavLink>
|
||||
<MudNavLink Href="/teams/assignment" Icon="@AppIcons.TeamAssignment">Event Assignment</MudNavLink>
|
||||
<MudNavLink Href="/teams/scheduler" Icon="@AppIcons.TeamAssignment">Schedule</MudNavLink>
|
||||
</MudNavGroup>
|
||||
</MudNavMenu>
|
||||
</MudPaper>
|
||||
@@ -3,7 +3,7 @@
|
||||
cursor: pointer;
|
||||
width: 3.5rem;
|
||||
height: 2.5rem;
|
||||
color: white;
|
||||
color: blue;
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 1rem;
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
@using Core.Entities
|
||||
@using Data
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@page "/events/descriptions"
|
||||
@inject IConfiguration Configuration
|
||||
@inject AppDbContext Context
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>TSA Events @Configuration["ChapterSettings:CompetitionYear"]</PageTitle>
|
||||
|
||||
<h1>TSA Events @Configuration["ChapterSettings:CompetitionYear"]</h1>
|
||||
|
||||
@if (_events == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div>
|
||||
@foreach (var evt in _events)
|
||||
{
|
||||
<div class="container nobrk">
|
||||
@if (evt.RegionalEvent)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<i>Regional Event</i>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div div class="row">
|
||||
<div class="col-4">
|
||||
<h5>@evt.Name</h5>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
@if (evt.EventFormat is EventFormat.Team)
|
||||
{
|
||||
<html><strong>@evt.EventFormat</strong><br/>Size: <strong>@evt.TeamSize</strong></html>
|
||||
}
|
||||
else
|
||||
{
|
||||
<html>
|
||||
<strong>@evt.EventFormat</strong>
|
||||
</html>
|
||||
}
|
||||
|
||||
</div>
|
||||
<div class="col">
|
||||
Eligibility: @evt.Eligibility
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<strong> Effort</strong>: @evt.LevelOfEffort
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<strong>Activity</strong>: @evt.SemifinalistActivity
|
||||
</div>
|
||||
</div>
|
||||
<div div class="row mt-3">
|
||||
<div class="col">@evt.Description</div></div>
|
||||
@if (!string.IsNullOrEmpty(evt.Theme))
|
||||
{
|
||||
<div div class="row mt-2">
|
||||
<div class="col-3 text-center"><i>Theme for 2025-26:</i></div>
|
||||
<div class="col" style="white-space:pre-wrap;">@evt.Theme</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(evt.Documentation))
|
||||
{
|
||||
<div div class="row mt-2">
|
||||
<div class="col-3 text-center"><i>Materials:</i></div>
|
||||
<div class="col">@evt.Documentation</div>
|
||||
</div>
|
||||
}
|
||||
<hr/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@code {
|
||||
private EventDefinition[]? _events = null;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_events = await Context.Events.OrderBy(e => e.Name).Where(e => e.Name != "Chapter Team").ToArrayAsync();
|
||||
}
|
||||
}
|
||||
@@ -2,27 +2,25 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@inject AppDbContext Context
|
||||
|
||||
|
||||
<PageTitle>Events - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">Events</MudText>
|
||||
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Create" Href="events/create">Create New</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Print" Href="events/printout">Printable Descriptions</MudButton>
|
||||
|
||||
|
||||
<MudDataGrid T="EventDefinition" ServerData="ServerReload" @ref="_dataGrid" Filterable="true" RowsPerPage="50">
|
||||
<MudDataGrid T="EventDefinition" ServerData="ServerReload" @ref="_dataGrid" Filterable="true" RowsPerPage="50" >
|
||||
<Columns>
|
||||
<PropertyColumn Property="@(e => e.Name)" Title="Event Name" Sortable="true" />
|
||||
<PropertyColumn Property="@(e => e.EventFormat)" Title="Event Format" />
|
||||
<PropertyColumn Property="@(e => e.LevelOfEffort)" Title="Level of Effort" />
|
||||
<PropertyColumn Property="@(e => e.SemifinalistActivity)" Title="On-site Activity" />
|
||||
<PropertyColumn Property="@(e => e.RegionalEvent)" Title="Regional Event" />
|
||||
<PropertyColumn Property="@(e => e.Eligibility)" Title="Eligibility" />
|
||||
<TemplateColumn Title="Team Size" CellStyle="white-space:nowrap">
|
||||
<CellTemplate>
|
||||
[@context.Item.MinTeamSize - @context.Item.MaxTeamSize]
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Title="Teams State #">
|
||||
<TemplateColumn Title="TimeSlots State #">
|
||||
<CellTemplate>
|
||||
@context.Item.MaxTeamCountState
|
||||
</CellTemplate>
|
||||
@@ -50,27 +48,6 @@
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
|
||||
@*
|
||||
<QuickGrid Class="table" Items="context.Events">
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.Name" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.EventFormat" />
|
||||
@* <PropertyColumn Property="eventdefinition => eventdefinition.MinTeamSize" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.MaxTeamSize" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.SemifinalistActivity" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.Notes" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.MaxTeamCountState" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.RegionalEvent" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.RegionalPresubmit" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.StatePresubmission" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.StatePretesting" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.StatePreliminaryRound" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.Documentation" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.Eligibility" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.Theme" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.Description" />
|
||||
<PropertyColumn Property="eventdefinition => eventdefinition.LevelOfEffort" />
|
||||
*@
|
||||
|
||||
@code {
|
||||
MudDataGrid<EventDefinition> _dataGrid = null!;
|
||||
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@page "/events/printout"
|
||||
@inject IConfiguration Configuration
|
||||
@inject AppDbContext Context
|
||||
|
||||
<PageTitle>TSA Events @Configuration["ChapterSettings:CompetitionYear"]</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">TSA Events @Configuration["ChapterSettings:CompetitionYear"]</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mb-4">Yearly theme: Unity Through Community</MudText>
|
||||
|
||||
@if (_events == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudContainer>
|
||||
@foreach (var evt in _events)
|
||||
{
|
||||
<MudContainer Class="mt-3 mb-1 nobrk">
|
||||
<MudGrid>
|
||||
<MudItem xs="4">
|
||||
<MudStack>
|
||||
<MudItem>
|
||||
<MudText Class="d-flex py-1" Typo="Typo.h5">@evt.Name</MudText>
|
||||
</MudItem>
|
||||
@if (evt.RegionalEvent)
|
||||
{
|
||||
<MudItem>
|
||||
<MudText Class="d-flex" Typo="Typo.caption"><i>Regional Event</i></MudText>
|
||||
</MudItem>
|
||||
}
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="2">
|
||||
|
||||
<MudText>
|
||||
@if (evt.EventFormat is EventFormat.Team)
|
||||
{
|
||||
<strong>@evt.EventFormat</strong>
|
||||
<br/>
|
||||
<p>Size: <strong>@evt.TeamSize</strong></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<strong>@evt.EventFormat</strong>
|
||||
}
|
||||
</MudText>
|
||||
|
||||
</MudItem>
|
||||
<MudItem xs="3">
|
||||
Eligibility: @evt.Eligibility
|
||||
</MudItem>
|
||||
<MudItem xs="1">
|
||||
<strong> Effort</strong>: @evt.LevelOfEffort
|
||||
</MudItem>
|
||||
<MudItem xs="2">
|
||||
<strong>Activity</strong>: @evt.SemifinalistActivity
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12">
|
||||
<MudText Class="d-flex py-1" Style="white-space:pre-wrap;">@evt.Description</MudText>
|
||||
</MudItem>
|
||||
@if (!string.IsNullOrEmpty(evt.Theme))
|
||||
{
|
||||
<MudItem xs="3">
|
||||
<MudText Class="d-flex py-1">
|
||||
<i>Theme for 2025-26:</i>
|
||||
</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudText Class="d-flex py-1" Style="white-space:pre-wrap;">@evt.Theme</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(evt.Documentation))
|
||||
{
|
||||
<MudItem xs="3">
|
||||
<MudText Class="d-flex py-1">
|
||||
<i>Materials:</i>
|
||||
</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudText Class="d-flex py-1" Style="white-space:pre-wrap;">@evt.Documentation</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
<MudDivider />
|
||||
}
|
||||
</MudContainer>
|
||||
|
||||
<MudContainer>
|
||||
@foreach (var evt in _events)
|
||||
{
|
||||
<MudContainer Class="mt-3 mb-1 nobrk">
|
||||
<MudGrid>
|
||||
<MudItem xs="4">
|
||||
<MudStack>
|
||||
<MudItem>
|
||||
<MudText Class="d-flex py-1" Typo="Typo.h5">@evt.Name</MudText>
|
||||
</MudItem>
|
||||
@if (evt.RegionalEvent)
|
||||
{
|
||||
<MudItem>
|
||||
<MudText Class="d-flex" Typo="Typo.caption"><i>Regional Event</i></MudText>
|
||||
</MudItem>
|
||||
}
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="2">
|
||||
|
||||
<MudText>
|
||||
@if (evt.EventFormat is EventFormat.Team)
|
||||
{
|
||||
<strong>@evt.EventFormat</strong>
|
||||
<br />
|
||||
<p>Size: <strong>@evt.TeamSize</strong></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<strong>@evt.EventFormat</strong>
|
||||
}
|
||||
</MudText>
|
||||
|
||||
</MudItem>
|
||||
<MudItem xs="3">
|
||||
Eligibility: @evt.Eligibility
|
||||
</MudItem>
|
||||
<MudItem xs="1">
|
||||
<strong> Effort</strong>: @evt.LevelOfEffort
|
||||
</MudItem>
|
||||
<MudItem xs="2">
|
||||
<strong>Activity</strong>: @evt.SemifinalistActivity
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12">
|
||||
<MudText Class="d-flex py-1" Style="white-space:pre-wrap;">@evt.Description</MudText>
|
||||
</MudItem>
|
||||
@if (!string.IsNullOrEmpty(evt.Theme))
|
||||
{
|
||||
<MudItem xs="3">
|
||||
<MudText Class="d-flex py-1">
|
||||
<i>Theme for 2025-26:</i>
|
||||
</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudText Class="d-flex py-1" Style="white-space:pre-wrap;">@evt.Theme</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(evt.Documentation))
|
||||
{
|
||||
<MudItem xs="3">
|
||||
<MudText Class="d-flex py-1">
|
||||
<i>Materials:</i>
|
||||
</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudText Class="d-flex py-1" Style="white-space:pre-wrap;">@evt.Documentation</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
<MudDivider />
|
||||
}
|
||||
</MudContainer>
|
||||
}
|
||||
@code {
|
||||
private EventDefinition[]? _events;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_events = await Context.Events.OrderBy(e => e.Name).ToArrayAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<h3>Index</h3>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
@@ -1,16 +1,20 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using WebApp.Models
|
||||
@page "/students/event-ranking"
|
||||
@inject AppDbContext Context
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Student Event Ranks - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3"><MudIcon Icon="@AppIcons.EventRank"></MudIcon> Student Event Ranks</MudText>
|
||||
|
||||
@if (_students == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
<MudTable Items="_students" Hover="true" Breakpoint="Breakpoint.Sm" LoadingProgressColor="Color.Info">
|
||||
<HeaderContent>
|
||||
|
||||
@@ -23,6 +27,10 @@ else
|
||||
<MudTh>4th</MudTh>
|
||||
<MudTh>5th</MudTh>
|
||||
<MudTh>6th</MudTh>
|
||||
<MudTh>7th</MudTh>
|
||||
<MudTh>8th</MudTh>
|
||||
<MudTh>9th</MudTh>
|
||||
<MudTh>10th</MudTh>
|
||||
<MudTh></MudTh>
|
||||
<MudTh>Warnings</MudTh>
|
||||
</HeaderContent>
|
||||
@@ -32,7 +40,7 @@ else
|
||||
<MudTh>@context.Grade</MudTh>
|
||||
<MudTh>@context.TsaYear</MudTh>
|
||||
|
||||
@for (var i = 1; i <= 6; i++)
|
||||
@for (var i = 1; i <= 10; i++)
|
||||
{
|
||||
var st = context.EventRankings.FirstOrDefault(e => e.Rank == i);
|
||||
<MudTd Class="@($"event-rank-{i})")">
|
||||
@@ -40,8 +48,8 @@ else
|
||||
{
|
||||
<span>@st.EventDefinition.ShortName
|
||||
@if(st.EventDefinition.EventFormat == EventFormat.Individual) { <span>ⓘ</span>}
|
||||
@if(st.EventDefinition.RegionalEvent) { <span>ⓡ</span>}
|
||||
@if(st.EventDefinition.OnSiteActivity) { <span>ⓐ</span>}
|
||||
@if(st.EventDefinition.RegionalEvent) {<span>ⓡ</span>}
|
||||
@if(st.EventDefinition.OnSiteActivity) {<span>ⓐ</span>}
|
||||
</span>
|
||||
}
|
||||
</MudTd>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<PageTitle>Student Event Ranks - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">Student Event Ranks</MudText>
|
||||
<MudText Typo="Typo.h3"><MudIcon Icon="@AppIcons.EventRank"></MudIcon> Student Event Ranks</MudText>
|
||||
|
||||
<div>
|
||||
@if (_student == null)
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
<MudText Typo="Typo.h3">Students</MudText>
|
||||
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Create" Href="students/create">Create New</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.AddChart" Href="students/event-ranking">Event Rankings</MudButton>
|
||||
<MudButton StartIcon="@AppIcons.EventRank" Href="students/event-ranking">Event Rankings</MudButton>
|
||||
|
||||
<MudDataGrid T="Student" ServerData="ServerReload" @ref="_dataGrid" Filterable="true" RowsPerPage="25">
|
||||
<Columns>
|
||||
@* <PropertyColumn Property="@(e => e.Name)" Title="First Name" SortBy="e => e.FirstName" /> *@
|
||||
<TemplateColumn Title="Name" SortBy="e => e.FirstName" Sortable="true">
|
||||
<TemplateColumn Title="Name" SortBy="e => e.LastName" Sortable="true" >
|
||||
<CellTemplate>
|
||||
@context.Item.Name
|
||||
@context.Item.LastNameFirstName
|
||||
@if (context.Item.OfficerRole != null)
|
||||
{
|
||||
<MudChip T="string" Icon="@(AppIcons.OfficerRoleIcon(context.Item.OfficerRole.Value))">@context.Item.OfficerRole</MudChip>
|
||||
@@ -56,7 +56,9 @@
|
||||
private async Task<GridData<Student>> ServerReload(GridState<Student> state)
|
||||
{
|
||||
|
||||
var query = Context.Students.Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
||||
var query =
|
||||
Context.Students.OrderBy(e => e.LastName)
|
||||
.Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
||||
|
||||
var totalItems = await query.CountAsync();
|
||||
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync();
|
||||
|
||||
@@ -10,11 +10,108 @@
|
||||
|
||||
<MudText Typo="Typo.h3">Assignment</MudText>
|
||||
|
||||
<MudGrid>
|
||||
<MudItem><MudText>Optimized team assignments based on the student event rankings</MudText></MudItem>
|
||||
<MudItem><MudButton StartIcon="@Icons.Material.Filled.Edit" Href="students/event-ranking">Edit Student Event Rankings</MudButton></MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudText>Optimized team assignments based on the student event rankings</MudText>
|
||||
<MudPaper Class="pa-4 mt-5">
|
||||
<MudGrid>
|
||||
<MudItem Style="width:160px;">
|
||||
<MudNumericField @bind-Value="_parameters.TeamSizeLimit"
|
||||
Label="Team Size Limit" Min="3" Max="8"></MudNumericField>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudTooltip Text="Require at least one On-Site Event">
|
||||
<MudSwitch @bind-Value="_parameters.RequireOnSite" Color="Color.Info"
|
||||
Label="On-Site" />
|
||||
</MudTooltip>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudTooltip Text="Require at least one Regional Event">
|
||||
<MudSwitch @bind-Value="_parameters.RequireRegional" Color="Color.Info"
|
||||
Label="Regional" />
|
||||
</MudTooltip>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudStack Style="width:100px;">
|
||||
<MudTooltip Text="Student Event Count Assignment Range">
|
||||
<MudInputLabel>Event Count</MudInputLabel>
|
||||
</MudTooltip>
|
||||
<MudNumericField @bind-Value="_parameters.EventsLowerBound"
|
||||
Label="At Least" Min="2" Max="4"></MudNumericField>
|
||||
|
||||
<MudNumericField @bind-Value="_parameters.EventsUpperBound"
|
||||
Label="Up to" Min="3" Max="5"></MudNumericField>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudStack Style="width:100px;">
|
||||
<MudTooltip Text="Student Level of Effort Range">
|
||||
<MudInputLabel>LOE</MudInputLabel>
|
||||
</MudTooltip>
|
||||
<MudNumericField @bind-Value="_parameters.EffortLowerBound"
|
||||
Label="At Least" Min="4" Max="7"></MudNumericField>
|
||||
|
||||
<MudNumericField @bind-Value="_parameters.EffortUpperBound"
|
||||
Label="Up to" Min="7" Max="12"></MudNumericField>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudInputLabel>Assignment Requirements</MudInputLabel>
|
||||
<MudTable T="AssignmentRequirement" ServerData="ReloadAssignmentRequirements" @ref="_assignmentRequirementData">
|
||||
|
||||
<RowTemplate Context="item">
|
||||
<MudTd Class="align-center">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.RemoveCircle" Size="Size.Small"
|
||||
OnClick="() => RemoveRequireEvent(item)"></MudIconButton>
|
||||
</MudTd>
|
||||
<MudTd Class="align-center">
|
||||
@item.Student.FirstName
|
||||
@item.EventDefinition.ShortName
|
||||
@if (item.Requirement == Requirement.Include)
|
||||
{
|
||||
<MudIcon Class="ml-3" Icon="@Icons.Material.Filled.ThumbUp" Size="Size.Small"></MudIcon>
|
||||
}
|
||||
@if (item.Requirement == Requirement.Exclude)
|
||||
{
|
||||
<MudIcon Class="ml-3" Icon="@Icons.Material.Filled.ThumbDownAlt" Size="Size.Small"></MudIcon>
|
||||
}
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudInputLabel>Two Team Events</MudInputLabel>
|
||||
<MudTable T="EventDefinition" ServerData="ReloadEventTwoTeam" @ref="_eventTwoTeamData">
|
||||
|
||||
<RowTemplate Context="item">
|
||||
<MudTd Class="align-center">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.RemoveCircle" Size="Size.Small"
|
||||
OnClick="() => RemoveTwoTeam(item)"></MudIconButton>
|
||||
</MudTd>
|
||||
<MudTd Class="align-center">@item.ShortName</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudInputLabel>Omitted Events</MudInputLabel>
|
||||
<MudTable T="EventDefinition" ServerData="ReloadOmittedEvents" @ref="_eventOmittedData">
|
||||
|
||||
<RowTemplate Context="item">
|
||||
<MudTd Class="align-center">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.RemoveCircle" Size="Size.Small"
|
||||
OnClick="() => RemoveOmitted(item)"></MudIconButton>
|
||||
</MudTd>
|
||||
<MudTd Class="align-center">@item.ShortName</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<MudButton Class="ma-3" OnClick="Solve" Variant="Variant.Filled" Color="Color.Primary" Disabled="@_isSolving">Solve</MudButton>
|
||||
</MudPaper>
|
||||
|
||||
<MudGrid>
|
||||
|
||||
<MudItem xs="12" lg="8">
|
||||
<MudText Typo="Typo.h4">Students</MudText>
|
||||
|
||||
@@ -50,7 +147,7 @@
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
<ChildRowContent>
|
||||
<MudTr><td colspan="4">
|
||||
<MudTr><td colspan="4">
|
||||
@{
|
||||
var allStudentEvents =
|
||||
context.Student.EventRankings
|
||||
@@ -68,7 +165,7 @@
|
||||
var eventRank = context.Student.EventRankings.Find(er => er.EventDefinition == e)?.Rank;
|
||||
var isAssigned = context.Events.Contains(e);
|
||||
|
||||
var color = AppIcons.RankedEvent(eventRank ?? 0);
|
||||
var color = AppIcons.RankedEventColor(eventRank ?? 0);
|
||||
var style = string.Empty;
|
||||
|
||||
if (isAssigned)
|
||||
@@ -90,7 +187,8 @@
|
||||
}
|
||||
|
||||
<MudPaper Class="d-inline-flex align-center pa-2 mx-3 my-1 border-solid" Style="@(style)">
|
||||
@e.ShortName
|
||||
@e.ShortName
|
||||
@AppIcons.EventAttributes(e)
|
||||
@{
|
||||
var isIncluded = _assignmentRequirements
|
||||
.Find(ar =>
|
||||
@@ -134,152 +232,106 @@
|
||||
}
|
||||
</MudPaper>
|
||||
}
|
||||
<MudDivider Style="border-width:3px" />
|
||||
<MudDivider Style="border-width:3px" />
|
||||
</td></MudTr>
|
||||
</ChildRowContent>
|
||||
</MudTable>
|
||||
</MudItem>
|
||||
<MudItem xs="12" lg="4">
|
||||
<MudText Typo="Typo.h4">Teams</MudText>
|
||||
<MudTable T="Team" ServerData="SolveAssignments" @ref="_teamData">
|
||||
<ColGroup>
|
||||
<col style="width: 200px;" />
|
||||
<col style="width: 40px; white-space:nowrap" />
|
||||
</ColGroup>
|
||||
<HeaderContent>
|
||||
<MudTh>Team</MudTh>
|
||||
<MudTh><MudTooltip Text="Number of Student Rankings, Number of Teams [Eligibility Lower Bound-Upper Bound]"><MudText Style="white-space:nowrap;">R, # [LB-UB]</MudText> </MudTooltip></MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
@{
|
||||
var thresholds = _eventAssignmentThresholds.First(e => e.Event == context.Event);
|
||||
}
|
||||
<MudTd><b>@context.Event.Name</b></MudTd>
|
||||
<MudTd Style="white-space:nowrap">@thresholds.StudentRankingCount, @thresholds.TeamCount × [@thresholds.LowerBound-@thresholds.UpperBound]</MudTd>
|
||||
|
||||
</RowTemplate>
|
||||
<ChildRowContent>
|
||||
<MudTr>
|
||||
<td colspan="2">
|
||||
@foreach (var student in
|
||||
context.Students
|
||||
.OrderBy(e =>
|
||||
e.EventRankings
|
||||
.Find(er => er.EventDefinition == context.Event)?.Rank ?? 10)
|
||||
.ThenBy(s => s.Grade + s.TsaYear))
|
||||
<MudText Typo="Typo.h4">TimeSlots</MudText>
|
||||
<MudTable T="Team" ServerData="SolveAssignments" @ref="_teamData">
|
||||
<ColGroup>
|
||||
<col style="width: 200px;" />
|
||||
<col style="width: 40px; white-space:nowrap" />
|
||||
</ColGroup>
|
||||
<HeaderContent>
|
||||
<MudTh>Team</MudTh>
|
||||
<MudTh><MudTooltip Text="Number of Student Rankings, Number of TimeSlots [Eligibility Lower Bound-Upper Bound]"><MudText Style="white-space:nowrap;">R, # [LB-UB]</MudText> </MudTooltip></MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
@{
|
||||
var thresholds = _eventAssignmentThresholds.First(e => e.Event == context.Event);
|
||||
}
|
||||
<MudTd>
|
||||
<b>@context.Event.Name</b>
|
||||
<span>@AppIcons.EventEffort(context.Event) @AppIcons.EventAttributes(context.Event)</span>
|
||||
</MudTd>
|
||||
<MudTd Style="white-space:nowrap">
|
||||
|
||||
@thresholds.StudentRankingCount, [@thresholds.LowerBound-@thresholds.UpperBound] × @thresholds.TeamCount
|
||||
|
||||
@if (_eventTwoTeams.Contains(context.Event))
|
||||
{
|
||||
var eventRank =
|
||||
student.EventRankings
|
||||
.Find(e => e.EventDefinition == context.Event)?.Rank;
|
||||
var color = AppIcons.RankedEvent(eventRank ?? 0);
|
||||
|
||||
<MudPaper Class="d-inline-flex pa-2 mx-3 my-1" Style="@($"background:{color};")">
|
||||
@student.FirstName
|
||||
</MudPaper>
|
||||
<MudIconButton Class="ml-3" Size="Size.Small" Color="Color.Default"
|
||||
Icon="@Icons.Material.Filled.PlusOne" Variant="Variant.Filled"
|
||||
OnClick="() => RemoveTwoTeam(context.Event)"></MudIconButton>
|
||||
}
|
||||
else if (thresholds.TeamCount != 2 && context.Event.EventFormat == EventFormat.Team)
|
||||
{
|
||||
<MudIconButton Class="ml-3" Size="Size.Small" Color="Color.Default"
|
||||
Icon="@Icons.Material.Filled.PlusOne"
|
||||
OnClick="() => AddTwoTeam(context.Event)"></MudIconButton>
|
||||
}
|
||||
<MudIconButton Icon="@Icons.Material.Outlined.Remove" Size="Size.Small" Color="Color.Default"
|
||||
OnClick="() => AddOmitted(context.Event)"></MudIconButton>
|
||||
</MudTd>
|
||||
|
||||
</RowTemplate>
|
||||
<ChildRowContent>
|
||||
<MudTr>
|
||||
<td colspan="2">
|
||||
@foreach (var student in
|
||||
context.Students
|
||||
.OrderBy(e =>
|
||||
e.EventRankings
|
||||
.Find(er => er.EventDefinition == context.Event)?.Rank ?? 10)
|
||||
.ThenBy(s => s.Grade + s.TsaYear))
|
||||
{
|
||||
var eventRank =
|
||||
student.EventRankings
|
||||
.Find(e => e.EventDefinition == context.Event)?.Rank;
|
||||
var color = AppIcons.RankedEventColor(eventRank ?? 0);
|
||||
|
||||
<MudPaper Class="d-inline-flex pa-2 mx-3 my-1" Style="@($"background:{color};")">
|
||||
@student.FirstName
|
||||
</MudPaper>
|
||||
}
|
||||
<MudDivider Style="border-width:3px" />
|
||||
</td>
|
||||
</MudTr>
|
||||
</ChildRowContent>
|
||||
<NoRecordsContent>
|
||||
<MudText Color="Color.Warning">Solution status: @_solutionStatus</MudText>
|
||||
</NoRecordsContent>
|
||||
<LoadingContent>
|
||||
<MudText>Loading...</MudText>
|
||||
</LoadingContent>
|
||||
</MudTable>
|
||||
</MudItem>
|
||||
</td>
|
||||
</MudTr>
|
||||
</ChildRowContent>
|
||||
<NoRecordsContent>
|
||||
<MudText Color="Color.Warning">Solution status: @_solutionStatus</MudText>
|
||||
</NoRecordsContent>
|
||||
<LoadingContent>
|
||||
<MudText>Loading...</MudText>
|
||||
</LoadingContent>
|
||||
</MudTable>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<MudPaper Class="pa-4 mt-5">
|
||||
<MudGrid>
|
||||
<MudItem Style="width:160px;">
|
||||
<MudNumericField @bind-Value="_parameters.TeamSizeLimit"
|
||||
Label="Team Size Limit" Min="3" Max="8"></MudNumericField>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudTooltip Text="Require at least one On-Site Event">
|
||||
<MudSwitch @bind-Value="_parameters.RequireOnSite" Color="Color.Info"
|
||||
Label="On-Site"/>
|
||||
</MudTooltip>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudTooltip Text="Require at least one Regional Event">
|
||||
<MudSwitch @bind-Value="_parameters.RequireRegional" Color="Color.Info"
|
||||
Label="Regional"/>
|
||||
</MudTooltip>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudStack Style="width:100px;">
|
||||
<MudTooltip Text="Student Event Count Assignment Range">
|
||||
<MudInputLabel>Event Count</MudInputLabel>
|
||||
</MudTooltip>
|
||||
<MudNumericField @bind-Value="_parameters.EventsLowerBound"
|
||||
Label="At Least" Min="2" Max="4"></MudNumericField>
|
||||
|
||||
<MudNumericField @bind-Value="_parameters.EventsUpperBound"
|
||||
Label="Up to" Min="3" Max="5"></MudNumericField>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudStack Style="width:100px;">
|
||||
<MudTooltip Text="Student Level of Effort Range">
|
||||
<MudInputLabel>LOE</MudInputLabel>
|
||||
</MudTooltip>
|
||||
<MudNumericField @bind-Value="_parameters.EffortLowerBound"
|
||||
Label="At Least" Min="4" Max="7"></MudNumericField>
|
||||
|
||||
<MudNumericField @bind-Value="_parameters.EffortUpperBound"
|
||||
Label="Up to" Min="7" Max="12"></MudNumericField>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem>
|
||||
<MudInputLabel>Assignment Requirements</MudInputLabel>
|
||||
<MudTable T="AssignmentRequirement" ServerData="ReloadAssignmentRequirements" @ref="_assignmentRequirementData">
|
||||
<HeaderContent>
|
||||
<MudTh></MudTh>
|
||||
<MudTh>Student</MudTh>
|
||||
<MudTh>Event</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate Context="item">
|
||||
<MudTd Class="align-center">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.RemoveCircle"
|
||||
OnClick="() => RemoveRequireEvent(item)"></MudIconButton>
|
||||
</MudTd>
|
||||
<MudTd Class="align-center">@item.Student.FirstName</MudTd>
|
||||
<MudTd Class="align-center">
|
||||
@item.EventDefinition.ShortName
|
||||
@if (item.Requirement == Requirement.Include)
|
||||
{
|
||||
<MudIcon Class="ml-3" Icon="@Icons.Material.Filled.ThumbUp" Size="Size.Small"></MudIcon>
|
||||
}
|
||||
@if (item.Requirement == Requirement.Exclude)
|
||||
{
|
||||
<MudIcon Class="ml-3" Icon="@Icons.Material.Filled.ThumbDownAlt" Size="Size.Small"></MudIcon>
|
||||
}
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<MudButton OnClick="Solve" Variant="Variant.Filled" Disabled="@_isSolving">Solve</MudButton>
|
||||
</MudPaper>
|
||||
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Edit" Href="students/event-ranking">Edit Student Event Rankings</MudButton>
|
||||
|
||||
<MudTooltip Text="This will overwrite existing teams">
|
||||
<MudButton Class="ma-3" StartIcon="@Icons.Material.Filled.Warning" Variant="Variant.Filled" Size="Size.Large" OnClick="SaveTeams" Color="Color.Warning">Save</MudButton>
|
||||
</MudTooltip>
|
||||
@code {
|
||||
public bool TestSwitch { get; set; } = false;
|
||||
|
||||
private readonly AssignmentParameters _parameters = new () {LimitTeamsToOne = false};
|
||||
private readonly AssignmentParameters _parameters = new() { RequireOnSite = false, RequireRegional = false };
|
||||
|
||||
private List<EventDefinition>? _events;
|
||||
private List<Student>? _students;
|
||||
private List<EventAssignmentThresholds> _eventAssignmentThresholds = [];
|
||||
|
||||
MudTable<Team> _teamData;
|
||||
private Team[] _teams = [];
|
||||
MudTable<StudentEventStatistics> _statisticData;
|
||||
private List<StudentEventStatistics> _statistics = [];
|
||||
MudTable<AssignmentRequirement> _assignmentRequirementData;
|
||||
private List<AssignmentRequirement> _assignmentRequirements = [];
|
||||
MudTable<EventDefinition> _eventTwoTeamData;
|
||||
private List<EventDefinition> _eventTwoTeams = [];
|
||||
MudTable<EventDefinition> _eventOmittedData;
|
||||
private List<EventDefinition> _eventOmitted = [];
|
||||
|
||||
private string _solutionStatus = string.Empty;
|
||||
|
||||
@@ -302,7 +354,7 @@
|
||||
|
||||
private async Task AddTeam()
|
||||
{
|
||||
//Context.Teams.Add(Team);
|
||||
//Context.TimeSlots.Add(Team);
|
||||
await Context.SaveChangesAsync();
|
||||
//NavigationManager.NavigateTo("/teams");
|
||||
}
|
||||
@@ -320,6 +372,10 @@
|
||||
{
|
||||
eventAssignment.AddAssignmentRequirement(requirement);
|
||||
}
|
||||
eventAssignment.RemoveEvents(_eventOmitted);
|
||||
|
||||
eventAssignment.AllowTwoTeams(_eventTwoTeams);
|
||||
|
||||
var solution = await eventAssignment.Solve();
|
||||
_solutionStatus = solution.Status;
|
||||
_statistics =
|
||||
@@ -330,7 +386,9 @@
|
||||
await _statisticData.ReloadServerData();
|
||||
_isSolving = false;
|
||||
await InvokeAsync(StateHasChanged); // let the UI know that the solution has been found
|
||||
return new TableData<Team> { Items = solution.Teams };
|
||||
_teams = solution.Teams;
|
||||
|
||||
return new TableData<Team> { Items = _teams };
|
||||
}
|
||||
|
||||
private async Task<TableData<StudentEventStatistics>> ReloadStatistics(TableState arg1, CancellationToken arg2)
|
||||
@@ -343,6 +401,17 @@
|
||||
return new TableData<AssignmentRequirement> { Items = _assignmentRequirements };
|
||||
}
|
||||
|
||||
private async Task<TableData<EventDefinition>> ReloadEventTwoTeam(TableState arg1, CancellationToken arg2)
|
||||
{
|
||||
return new TableData<EventDefinition> { Items = _eventTwoTeams };
|
||||
}
|
||||
|
||||
|
||||
private async Task<TableData<EventDefinition>> ReloadOmittedEvents(TableState arg1, CancellationToken arg2)
|
||||
{
|
||||
return new TableData<EventDefinition> { Items = _eventOmitted };
|
||||
}
|
||||
|
||||
private void RequireEvent(EventDefinition evt, Student student, Requirement requirement)
|
||||
{
|
||||
_assignmentRequirements.Add(new AssignmentRequirement(evt, student, requirement));
|
||||
@@ -362,4 +431,39 @@
|
||||
_assignmentRequirements.Remove(assignmentRequirement);
|
||||
_assignmentRequirementData.ReloadServerData();
|
||||
}
|
||||
|
||||
private void AddTwoTeam(EventDefinition evt)
|
||||
{
|
||||
_eventTwoTeams.Add(evt);
|
||||
_eventTwoTeamData.ReloadServerData();
|
||||
}
|
||||
|
||||
private void RemoveTwoTeam(EventDefinition evt)
|
||||
{
|
||||
_eventTwoTeams.Remove(evt);
|
||||
_eventTwoTeamData.ReloadServerData();
|
||||
}
|
||||
|
||||
|
||||
private void AddOmitted(EventDefinition evt)
|
||||
{
|
||||
_eventOmitted.Add(evt);
|
||||
_eventOmittedData.ReloadServerData();
|
||||
}
|
||||
|
||||
private void RemoveOmitted(EventDefinition evt)
|
||||
{
|
||||
_eventOmitted.Remove(evt);
|
||||
_eventOmittedData.ReloadServerData();
|
||||
}
|
||||
|
||||
public async Task SaveTeams()
|
||||
{
|
||||
var teams = await Context.Teams.ExecuteDeleteAsync();
|
||||
|
||||
await Context.Teams.AddRangeAsync(_teams);
|
||||
await Context.SaveChangesAsync();
|
||||
|
||||
NavigationManager.NavigateTo("/teams");
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
<MudSelectItem T="EventDefinition" Value="@(evt)"></MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField T="string" Label="Name" @bind-Value="Team.Name" For="@(() => Team.Name)"></MudTextField>
|
||||
<MudTextField T="int?" Label="Number" @bind-Value="Team.Number" For="@(() => Team.Number)"></MudTextField>
|
||||
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
@@ -46,7 +46,9 @@
|
||||
|
||||
private async Task AddTeam()
|
||||
{
|
||||
Team.TeamId = Team.Event.Name;
|
||||
Context.Teams.Add(Team);
|
||||
|
||||
await Context.SaveChangesAsync();
|
||||
NavigationManager.NavigateTo("/teams");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
@page "/teams/delete"
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@inject AppDbContext context
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<PageTitle>Delete Team</PageTitle>
|
||||
|
||||
<h1>Delete</h1>
|
||||
|
||||
<p>Are you sure you want to delete this?</p>
|
||||
<div>
|
||||
<h2>Team</h2>
|
||||
<hr />
|
||||
@if (team is null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else {
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">Team</dt>
|
||||
<dd class="col-sm-10">@team.Event.Name</dd>
|
||||
</dl>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">Students</dt>
|
||||
<dd class="col-sm-10">@string.Join(",", team.Students.Select(e => e.Name))</dd>
|
||||
</dl>
|
||||
|
||||
<EditForm method="post" Model="team" OnValidSubmit="DeleteTeam" FormName="delete" Enhance>
|
||||
<button type="submit" class="btn btn-danger" disabled="@(team is null)">Delete</button> |
|
||||
<a href="/teams">Back to List</a>
|
||||
</EditForm>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private Team? team;
|
||||
|
||||
[SupplyParameterFromQuery]
|
||||
private int Id { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
team = await context.Teams
|
||||
.Include(e => e.Event)
|
||||
.Include(e => e.Students)
|
||||
.FirstOrDefaultAsync(m => m.Id == Id);
|
||||
|
||||
if (team is null)
|
||||
{
|
||||
NavigationManager.NavigateTo("notfound");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteTeam()
|
||||
{
|
||||
context.Teams.Remove(team!);
|
||||
await context.SaveChangesAsync();
|
||||
NavigationManager.NavigateTo("/teams");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
@page "/teams/edit"
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@inject AppDbContext Context
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<PageTitle>Edit Team - TSA Chapter Organizer</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">Edit</MudText>
|
||||
<MudText Typo="Typo.h4">Team@(Team == null ? "" : $" ({Team.Event.Name} #{Team.Number})")</MudText>
|
||||
|
||||
@if (Team is null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<EditForm method="post" Model="Team" OnValidSubmit="UpdateTeam" FormName="edit" Enhance>
|
||||
<DataAnnotationsValidator/>
|
||||
<MudGrid>
|
||||
<MudItem xs="12" sm="7">
|
||||
<MudPaper Class="pa-4">
|
||||
<MudSelect
|
||||
T="Student"
|
||||
MultiSelection="true"
|
||||
@bind-SelectedValues="@_selectedStudents"
|
||||
ToStringFunc="e => e.Name"
|
||||
Label="Students">
|
||||
|
||||
@foreach (var student in _students.OrderBy(e => e.FirstName))
|
||||
{
|
||||
<MudSelectItem T="Student" Value="@student">@student.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField T="int?" Label="Number" @bind-Value="Team.Number" For="@(() => Team.Number)" Required="false" Clearable="true"></MudTextField>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.ArrowBack" Href="teams">Back</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Save" OnClick="UpdateTeam">Save</MudButton>
|
||||
</EditForm>
|
||||
}
|
||||
|
||||
@code {
|
||||
[SupplyParameterFromQuery]
|
||||
private int Id { get; set; }
|
||||
|
||||
[SupplyParameterFromForm]
|
||||
private Team? Team { get; set; }
|
||||
|
||||
private IEnumerable<Student> _selectedStudents = new HashSet<Student>();
|
||||
private List<Student> _students = [];
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
Team ??= await Context.Teams
|
||||
.Include(e => e.Event)
|
||||
.Include(e => e.Students)
|
||||
.FirstOrDefaultAsync(m => m.Id == Id);
|
||||
_students = await Context.Students.ToListAsync();
|
||||
foreach (var s in Team.Students)
|
||||
{
|
||||
((HashSet<Student>)_selectedStudents).Add(s);
|
||||
}
|
||||
|
||||
if (Team is null)
|
||||
{
|
||||
NavigationManager.NavigateTo("notfound");
|
||||
}
|
||||
}
|
||||
|
||||
// To protect from overposting attacks, enable the specific properties you want to bind to.
|
||||
// For more information, see https://learn.microsoft.com/aspnet/core/blazor/forms/#mitigate-overposting-attacks.
|
||||
private async Task UpdateTeam()
|
||||
{
|
||||
//Context.Attach(Team!).Entity = EntityState.Modified;
|
||||
Team.Students.Clear();
|
||||
foreach (var s in _selectedStudents)
|
||||
{
|
||||
Team.Students.Add(s);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (!TeamExists(Team!.Id))
|
||||
{
|
||||
NavigationManager.NavigateTo("notfound");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
NavigationManager.NavigateTo("/teams");
|
||||
}
|
||||
|
||||
private bool TeamExists(int id)
|
||||
{
|
||||
return Context.Teams.Any(e => e.Id == id);
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,38 @@
|
||||
@using WebApp.Models
|
||||
@inject AppDbContext Context
|
||||
|
||||
<PageTitle>Teams</PageTitle>
|
||||
<PageTitle>TimeSlots</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">Teams</MudText>
|
||||
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Create" Href="teams/create">Create New</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Assignment" Href="teams/assignment">Assignment</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Filled.Print" Href="teams/printout">Printout</MudButton>
|
||||
|
||||
<MudDataGrid T="Team" ServerData="ServerReload" @ref="_dataGrid" Filterable="true" RowsPerPage="25">
|
||||
<MudDataGrid T="Team" ServerData="ServerReload" @ref="_dataGrid" Filterable="true" RowsPerPage="35">
|
||||
<Columns>
|
||||
<PropertyColumn Property="@(e => e.Name)" Title="Name" />
|
||||
<PropertyColumn Property="@(e => e.Event.Name)" Title="Event" />
|
||||
@* <TemplateColumn Title="Name" SortBy="e => e.FirstName" Sortable="true">
|
||||
<PropertyColumn Property="@(e => e.ToString())" Title="Event" />
|
||||
|
||||
<TemplateColumn Title="Students">
|
||||
<CellTemplate>
|
||||
@context.Item.Name
|
||||
@if (context.Item.OfficerRole != null)
|
||||
@foreach (var student in
|
||||
context.Item.Students
|
||||
.OrderBy(e =>
|
||||
e.EventRankings
|
||||
.Find(er => er.EventDefinition == context.Item.Event)?.Rank ?? 10)
|
||||
.ThenBy(s => s.Grade + s.TsaYear))
|
||||
{
|
||||
<MudChip T="string" Icon="@(AppIcons.OfficerRoleIcon(context.Item.OfficerRole.Value))">@context.Item.OfficerRole</MudChip>
|
||||
var eventRank =
|
||||
student.EventRankings
|
||||
.Find(e => e.EventDefinition == context.Item.Event)?.Rank;
|
||||
var color = AppIcons.RankedEventColor(eventRank ?? 0);
|
||||
|
||||
<MudPaper Class="d-inline-flex pa-2 mx-2 my-1" Style="@($"background:{color};")">
|
||||
@student.FirstName
|
||||
</MudPaper>
|
||||
}
|
||||
</CellTemplate>
|
||||
</TemplateColumn> *@
|
||||
</TemplateColumn>
|
||||
@* <TemplateColumn Title="Grade (TSA Year)" SortBy="e => e.Grade" Sortable="true">
|
||||
<CellTemplate>
|
||||
@context.Item.Grade (@context.Item.TsaYear)
|
||||
@@ -60,6 +72,9 @@
|
||||
= Context.Teams
|
||||
.Include(e => e.Event)
|
||||
.Include(e => e.Students)
|
||||
.ThenInclude(e => e.EventRankings)
|
||||
.OrderBy(e => e.Event.Name)
|
||||
.ThenBy(e => e.Number)
|
||||
.Where(state.FilterDefinitions)
|
||||
.OrderBy(state.SortDefinitions);
|
||||
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using WebApp.Models
|
||||
@page "/teams/printout"
|
||||
@inject IConfiguration Configuration
|
||||
@inject AppDbContext Context
|
||||
|
||||
<PageTitle>@Configuration["ChapterSettings:Shortname"] TSA Teams @Configuration["ChapterSettings:CompetitionYear"]</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">@Configuration["ChapterSettings:Shortname"] TSA Teams @Configuration["ChapterSettings:CompetitionYear"]</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mb-4">Yearly theme: Unity Through Community</MudText>
|
||||
|
||||
@if (_teams == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudContainer Class="mt-3 mb-1 nobrk">
|
||||
|
||||
<MudTable Items="_teams">
|
||||
<HeaderContent>
|
||||
<MudTh>Team</MudTh>
|
||||
<MudTh></MudTh>
|
||||
@for (var i = 0; i <= _maxTeamSize; i++)
|
||||
{
|
||||
<MudTh></MudTh>
|
||||
}
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
|
||||
<MudTd>
|
||||
@context.ToString()
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
@AppIcons.EventEffort(context.Event)
|
||||
@AppIcons.EventAttributes(context.Event)
|
||||
</MudTd>
|
||||
|
||||
@{
|
||||
var students
|
||||
= context.Students
|
||||
.OrderBy(s => s.EventRankings.Find(e => e.EventDefinition == context.Event)?.Rank ?? int.MaxValue)
|
||||
.ThenByDescending(e => e.Grade)
|
||||
.ThenBy(e => e.FirstName)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
@for (var i = 0; i <= _maxTeamSize; i++)
|
||||
{
|
||||
var student = i < students.Length ? students[i] : null;
|
||||
if (student != null)
|
||||
{
|
||||
var rank = student.EventRankings
|
||||
.Find(e => e.EventDefinition == context.Event)?.Rank ?? int.MaxValue;
|
||||
|
||||
<MudTd Class="@($"event-rank-{rank}")">
|
||||
@student.Name
|
||||
</MudTd>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTd></MudTd>
|
||||
}
|
||||
}
|
||||
<MudTd>
|
||||
@if (context.Event.EventFormat == EventFormat.Team)
|
||||
{
|
||||
@if (context.Students.Count < context.Event.MinTeamSize)
|
||||
{
|
||||
<span>Min Team Size: @context.Event.MinTeamSize</span>
|
||||
}
|
||||
|
||||
@if (context.Students.Count > context.Event.MaxTeamSize)
|
||||
{
|
||||
<span>Max Team Size: @context.Event.MaxTeamSize</span>
|
||||
}
|
||||
}
|
||||
else if (context.Event.EventFormat == EventFormat.Individual
|
||||
&& context.Students.Count > context.Event.MaxTeamCountState)
|
||||
{
|
||||
<span>Max Team Count State: @context.Event.MaxTeamCountState</span>
|
||||
}
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
|
||||
</MudContainer>
|
||||
|
||||
<MudContainer Class="mt-3 mb-1 nobrk pagebreak">
|
||||
|
||||
<MudTable Items="_students">
|
||||
<HeaderContent>
|
||||
<MudTh>Student</MudTh>
|
||||
<MudTh>Effort</MudTh>
|
||||
@for (var i = 0; i <= 5; i++)
|
||||
{
|
||||
<MudTh></MudTh>
|
||||
}
|
||||
<MudTh></MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
|
||||
<MudTd>@context.Name</MudTd>
|
||||
<MudTd>@context.Teams.Sum(e => e.Event.LevelOfEffort)</MudTd>
|
||||
@{
|
||||
var teams = context.Teams
|
||||
.OrderBy(e =>
|
||||
context.EventRankings.Find(ser => ser.EventDefinition == e.Event)?.Rank ?? int.MaxValue
|
||||
).ToArray();
|
||||
}
|
||||
@for (var i = 0; i <= 5; i++)
|
||||
{
|
||||
var team = i < teams.Length ? teams[i] : null;
|
||||
|
||||
@if (team != null)
|
||||
{
|
||||
var rank = context.EventRankings
|
||||
.Find(e => e.EventDefinition == team.Event)?.Rank ?? int.MaxValue;
|
||||
<MudTh Class="@($"event-rank-{rank}")">
|
||||
@team.ToString()
|
||||
@AppIcons.EventEffort(team.Event)
|
||||
@AppIcons.EventAttributes(team.Event)
|
||||
|
||||
@if (rank == int.MaxValue)
|
||||
{
|
||||
<span>❔</span>
|
||||
}
|
||||
</MudTh>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTh></MudTh>
|
||||
}
|
||||
|
||||
}
|
||||
<MudTd>
|
||||
@if (!context.Teams.Select(e => e.Event).Any(re => re.OnSiteActivity))
|
||||
{
|
||||
<span>No On-Site Activity</span>
|
||||
}
|
||||
@if (!context.Teams.Select(e => e.Event).Any(re => re.RegionalEvent))
|
||||
{
|
||||
<span>No Regional Event</span>
|
||||
}
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
|
||||
</MudContainer>
|
||||
|
||||
|
||||
<MudContainer Class="mt-3 mb-1 nobrk pagebreak">
|
||||
|
||||
<MudTable Items="_students">
|
||||
<HeaderContent>
|
||||
<MudTh>Student</MudTh>
|
||||
<MudTh>Grade, TSA Year</MudTh>
|
||||
<MudTh>Level of Effort</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
|
||||
<MudTd>@context.Name</MudTd>
|
||||
<MudTd>@AppIcons.GetOrdinal(context.Grade), @context.TsaYear</MudTd>
|
||||
<MudTd>@context.Teams.Sum(e => e.Event.LevelOfEffort)
|
||||
@if (!context.Teams.Select(e => e.Event).Any(re => re.OnSiteActivity))
|
||||
{
|
||||
<span>No On-Site Activity</span>
|
||||
}
|
||||
@if (!context.Teams.Select(e => e.Event).Any(re => re.RegionalEvent))
|
||||
{
|
||||
<span>No Regional Event</span>
|
||||
}
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
<ChildRowContent>
|
||||
<MudTr>
|
||||
<MudTable Items="@context.Teams.OrderBy(e =>
|
||||
context.EventRankings.Find(ser => ser.EventDefinition == e.Event)?.Rank ?? int.MaxValue
|
||||
)" Context="team">
|
||||
<RowTemplate>
|
||||
@{ var rank = context.EventRankings
|
||||
.Find(e => e.EventDefinition == team.Event)?.Rank ?? int.MaxValue; }
|
||||
<MudTd Class="@($"event-rank-{rank}")">
|
||||
@team.ToString()
|
||||
@AppIcons.EventEffort(team.Event)
|
||||
@AppIcons.EventAttributes(team.Event)
|
||||
|
||||
@if (rank == int.MaxValue)
|
||||
{
|
||||
<span>❔</span>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>@string.Join(", ", team.Students.Where(e => e != context).Select(e => e.FirstName))</MudTd>
|
||||
<MudTd></MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudTr>
|
||||
</ChildRowContent>
|
||||
</MudTable>
|
||||
|
||||
</MudContainer>
|
||||
|
||||
<MudContainer>
|
||||
@foreach (var studentForEvents in _students)
|
||||
{
|
||||
<MudContainer Class="pagebreak">
|
||||
<MudText Typo="Typo.h4">@studentForEvents.Name</MudText>
|
||||
@foreach (var team in studentForEvents.Teams)
|
||||
{
|
||||
<MudContainer Class="mt-3 mb-1 nobrk">
|
||||
<MudGrid>
|
||||
<MudItem xs="6">
|
||||
<MudStack>
|
||||
<MudItem>
|
||||
<MudText Class="d-flex py-1" Typo="Typo.h5">
|
||||
@team.ToString()
|
||||
</MudText>
|
||||
</MudItem>
|
||||
|
||||
@if (team.Event.RegionalEvent)
|
||||
{
|
||||
<MudItem>
|
||||
<MudText Class="d-flex" Typo="Typo.caption"><i>Regional Event</i></MudText>
|
||||
</MudItem>
|
||||
}
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="2">
|
||||
<MudText>
|
||||
<strong>@team.Event.EventFormat</strong>
|
||||
</MudText>
|
||||
|
||||
</MudItem>
|
||||
<MudItem xs="1">
|
||||
<strong>Effort</strong>: @AppIcons.LevelOfEffortIcon(@team.Event.LevelOfEffort)
|
||||
</MudItem>
|
||||
<MudItem xs="3">
|
||||
<strong>Activity</strong>: @team.Event.SemifinalistActivity
|
||||
</MudItem>
|
||||
@if (team.Event.EventFormat == EventFormat.Team)
|
||||
{
|
||||
<MudItem xs="12">
|
||||
<MudText Class="d-flex py-1" Typo="Typo.h6">
|
||||
Team Members: @string.Join(", ", team.Students.OrderByDescending(e => e.Grade + e.TsaYear).Select(e => e.FirstName))
|
||||
</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
<MudItem xs="12">
|
||||
<MudText Class="d-flex py-1" Style="white-space:pre-wrap;">@team.Event.Description</MudText>
|
||||
</MudItem>
|
||||
@if (!string.IsNullOrEmpty(team.Event.Theme))
|
||||
{
|
||||
<MudItem xs="3">
|
||||
<MudText Class="d-flex py-1">
|
||||
<i>Theme for 2025-26:</i>
|
||||
</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudText Class="d-flex py-1" Style="white-space:pre-wrap;">@team.Event.Theme</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(team.Event.Documentation))
|
||||
{
|
||||
<MudItem xs="3">
|
||||
<MudText Class="d-flex py-1">
|
||||
<i>Materials:</i>
|
||||
</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudText Class="d-flex py-1" Style="white-space:pre-wrap;">@team.Event.Documentation</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
<MudDivider/>
|
||||
}
|
||||
</MudContainer>
|
||||
}
|
||||
</MudContainer>
|
||||
}
|
||||
@code {
|
||||
private Team[]? _teams;
|
||||
private int _maxTeamSize;
|
||||
private Student[]? _students;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_teams
|
||||
= await Context.Teams
|
||||
.Include(e => e.Event)
|
||||
.Include(e => e.Students)
|
||||
.OrderBy(e => e.Event.Name)
|
||||
.ThenBy(e => e.Number)
|
||||
.ToArrayAsync();
|
||||
|
||||
_maxTeamSize = _teams.Max(t => t.Students.Count);
|
||||
_students =
|
||||
await Context.Students
|
||||
.Include(e => e.Teams)
|
||||
.ThenInclude(e => e.Captain)
|
||||
.Include(e => e.EventRankings)
|
||||
.ThenInclude(e => e.EventDefinition)
|
||||
.OrderBy(e => e.FirstName).ToArrayAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
@using Core.Calculation
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@page "/teams/scheduler"
|
||||
@inject IConfiguration Configuration
|
||||
@inject AppDbContext Context
|
||||
|
||||
<PageTitle>@Configuration["ChapterSettings:Shortname"] TSA Schedule @Configuration["ChapterSettings:CompetitionYear"]</PageTitle>
|
||||
|
||||
<MudText Typo="Typo.h3">@Configuration["ChapterSettings:Shortname"] TSA Schedule @Configuration["ChapterSettings:CompetitionYear"]</MudText>
|
||||
|
||||
<MudItem xs="12" lg="4">
|
||||
<MudText Typo="Typo.h4">Time Slots</MudText>
|
||||
<MudTable T="Team[]" ServerData="SolveSchedule" @ref="_solutionData">
|
||||
<HeaderContent>
|
||||
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>
|
||||
@foreach (var t in context)
|
||||
{
|
||||
<MudItem>
|
||||
@t.ToString() -
|
||||
@string.Join(", ", t.Students)
|
||||
</MudItem>
|
||||
}
|
||||
@foreach (var overlap in TeamSchedulerSolution.GetStudentTeamOverlaps(context))
|
||||
{
|
||||
<MudItem>
|
||||
@string.Join(", ", overlap.Item1)
|
||||
</MudItem>
|
||||
}
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudItem>
|
||||
|
||||
@code {
|
||||
private Team[]? _teams;
|
||||
private Student[]? _students;
|
||||
MudTable<Team[]> _solutionData;
|
||||
private TeamSchedulerSolution _solution;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_teams
|
||||
= await Context.Teams
|
||||
.Include(e => e.Event)
|
||||
.Include(e => e.Students)
|
||||
.OrderBy(e => e.Event.Name)
|
||||
.ThenBy(e => e.Number)
|
||||
.ToArrayAsync();
|
||||
|
||||
_students =
|
||||
await Context.Students
|
||||
.Include(e => e.Teams)
|
||||
.ThenInclude(e => e.Captain)
|
||||
.Include(e => e.EventRankings)
|
||||
.ThenInclude(e => e.EventDefinition)
|
||||
.OrderBy(e => e.FirstName).ToArrayAsync();
|
||||
}
|
||||
|
||||
private async Task<TableData<Team[]>> SolveSchedule(TableState arg1, CancellationToken arg2)
|
||||
{
|
||||
//_isSolving = true;
|
||||
|
||||
var scheduleOptions =
|
||||
new TeamSchedulerOptions(
|
||||
timeSlots: 4,
|
||||
mustIncludeEvents:
|
||||
[
|
||||
// "Medical Technology", "Electrical Applications" , "RegionalTeam",
|
||||
// ,"Dragster", "Flight"
|
||||
],
|
||||
extended:
|
||||
[
|
||||
// "Invention", "Construction Challenge", "Mechanical", "Mass", "Micro"
|
||||
//"STEM"
|
||||
//"Community", "Vlogging"// "Microcontroller"
|
||||
],
|
||||
omittedEvents:
|
||||
[
|
||||
// "Vlogging", "Junior", "Community Service Video", "Digital Photography",
|
||||
// "STEM"
|
||||
|
||||
//"Leadership",// "Electrical", //"Construction"
|
||||
// "Forensic",
|
||||
//"CAD"
|
||||
//"I&I Team 1", "I&I Team 2"//, "Website Design",
|
||||
],
|
||||
absentStudents:
|
||||
[
|
||||
]
|
||||
);
|
||||
|
||||
var mustIncludeTeams = _teams;
|
||||
mustIncludeTeams = mustIncludeTeams.Where(t => t.Event.EventFormat == EventFormat.Team).ToArray();
|
||||
|
||||
var teamScheduler = new TeamScheduler(mustIncludeTeams, scheduleOptions.TimeSlots);
|
||||
|
||||
// teamScheduler
|
||||
// .ScheduleSeparate(
|
||||
// _teams.First(e => e.Event.Name.Contains("Data Science")),
|
||||
// _teams.First(e => e.Event.Name.Contains("Microcontroller Design"))
|
||||
// );
|
||||
|
||||
_solution = teamScheduler.Solve();
|
||||
|
||||
await InvokeAsync(StateHasChanged); // let the UI know that the solution has been found
|
||||
|
||||
return new TableData<Team[]> { Items = _solution.TimeSlots};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user