Refactor collection initializers to use C# 12 collection expressions
This commit updates various files across the Core and WebApp projects to replace traditional collection initializers with C# 12 collection expressions. Changes include modifications to EventAssignment.cs, TeamScheduler_DecisionTree.cs, CareerField.cs, EventDefinition.cs, and several components in the WebApp. These updates enhance code readability and maintainability by adhering to modern C# syntax standards.
This commit is contained in:
@@ -254,7 +254,7 @@ namespace Core.Calculation
|
|||||||
private void AddStudentConstraint(CpModel model, BoolVar[,] x,
|
private void AddStudentConstraint(CpModel model, BoolVar[,] x,
|
||||||
Func<EventDefinition, bool> eventFilter, Action<CpModel, List<ILiteral>> constraintAction)
|
Func<EventDefinition, bool> eventFilter, Action<CpModel, List<ILiteral>> constraintAction)
|
||||||
{
|
{
|
||||||
var buffer = new List<ILiteral>();
|
List<ILiteral> buffer = [];
|
||||||
foreach (var s in _allStudents)
|
foreach (var s in _allStudents)
|
||||||
{
|
{
|
||||||
buffer.Clear();
|
buffer.Clear();
|
||||||
@@ -273,7 +273,7 @@ namespace Core.Calculation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void IndividualEventsMustBeRanked(CpModel model, BoolVar[,] x)
|
private void IndividualEventsMustBeRanked(CpModel model, BoolVar[,] x)
|
||||||
{
|
{
|
||||||
var prohibitVar = new List<IntVar>(1);
|
List<IntVar> prohibitVar = [];
|
||||||
|
|
||||||
foreach (var s in _allStudents)
|
foreach (var s in _allStudents)
|
||||||
{
|
{
|
||||||
@@ -328,7 +328,7 @@ namespace Core.Calculation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void LimitStudentAssignment(CpModel model, BoolVar[,] x)
|
private void LimitStudentAssignment(CpModel model, BoolVar[,] x)
|
||||||
{
|
{
|
||||||
var studentCapacity = new List<IntVar>();
|
List<IntVar> studentCapacity = [];
|
||||||
|
|
||||||
foreach (var s in _allStudents)
|
foreach (var s in _allStudents)
|
||||||
{
|
{
|
||||||
@@ -418,7 +418,7 @@ namespace Core.Calculation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void AddEventConstraint(CpModel model, BoolVar[,] x, int eventIndex, int lb, int ub)
|
private void AddEventConstraint(CpModel model, BoolVar[,] x, int eventIndex, int lb, int ub)
|
||||||
{
|
{
|
||||||
var eventCapacity = new List<IntVar>();
|
List<IntVar> eventCapacity = [];
|
||||||
foreach (var s in _allStudents)
|
foreach (var s in _allStudents)
|
||||||
{
|
{
|
||||||
eventCapacity.Add(x[eventIndex, s]);
|
eventCapacity.Add(x[eventIndex, s]);
|
||||||
@@ -455,7 +455,7 @@ namespace Core.Calculation
|
|||||||
model.AddAssumption(x[e, s]);
|
model.AddAssumption(x[e, s]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var prohibitVar = new List<IntVar>(1);
|
List<IntVar> prohibitVar = [];
|
||||||
foreach (var excludedAssignment in _assignmentRequirements.Where(a => a.Requirement == Requirement.Exclude))
|
foreach (var excludedAssignment in _assignmentRequirements.Where(a => a.Requirement == Requirement.Exclude))
|
||||||
{
|
{
|
||||||
var e = _events.IndexOf(excludedAssignment.EventDefinition);
|
var e = _events.IndexOf(excludedAssignment.EventDefinition);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class TeamScheduler_DecisionTree
|
|||||||
{
|
{
|
||||||
var timeSlots = new IList<Team>[_timeSlotCount];
|
var timeSlots = new IList<Team>[_timeSlotCount];
|
||||||
for (var i = 0; i < _timeSlotCount; i++)
|
for (var i = 0; i < _timeSlotCount; i++)
|
||||||
timeSlots[i] = new List<Team>();
|
timeSlots[i] = [];
|
||||||
|
|
||||||
foreach (var team in _teams.OrderByDescending(t => t.Students.Count))
|
foreach (var team in _teams.OrderByDescending(t => t.Students.Count))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,13 +43,10 @@ public class CareerField
|
|||||||
Id = id;
|
Id = id;
|
||||||
Name = name;
|
Name = name;
|
||||||
Description = description;
|
Description = description;
|
||||||
DirectCareerMatches = directCareerMatches ?? Array.Empty<string>();
|
DirectCareerMatches = directCareerMatches ?? [];
|
||||||
PatternKeywords = patternKeywords ?? Array.Empty<string>();
|
PatternKeywords = patternKeywords ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString() => Name;
|
||||||
{
|
|
||||||
return Name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,21 +37,6 @@ public class EventDefinition
|
|||||||
=> SemifinalistActivity != null && (SemifinalistActivity.Contains("Interview") || SemifinalistActivity.Contains("Presentation"));
|
=> SemifinalistActivity != null && (SemifinalistActivity.Contains("Interview") || SemifinalistActivity.Contains("Presentation"));
|
||||||
|
|
||||||
public bool OnSiteActivity { get; set; }
|
public bool OnSiteActivity { get; set; }
|
||||||
//=> SemifinalistActivity != null
|
|
||||||
// && (SemifinalistActivity.Contains("Challenge")
|
|
||||||
// || SemifinalistActivity.Contains("Race")
|
|
||||||
// || SemifinalistActivity.Contains("Speech")
|
|
||||||
// || SemifinalistActivity.Contains("Test")
|
|
||||||
// || SemifinalistActivity.Contains("Flight")
|
|
||||||
// || Name.Contains("Leadership")
|
|
||||||
// || Name.Contains("Forensic")
|
|
||||||
// || Name.Contains("Flight")
|
|
||||||
// || Name.Contains("Coding")
|
|
||||||
// || SemifinalistActivity.Contains("Debate")
|
|
||||||
// || SemifinalistActivity.Contains("Photography")
|
|
||||||
// || SemifinalistActivity.Contains("Build")
|
|
||||||
// || Name.Contains("Chapter")
|
|
||||||
// || Name.Contains("Podcast"));
|
|
||||||
|
|
||||||
[StringLength(1024)]
|
[StringLength(1024)]
|
||||||
public string? Notes { get; set; }
|
public string? Notes { get; set; }
|
||||||
@@ -79,15 +64,12 @@ public class EventDefinition
|
|||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public int? LevelOfEffort { get; set; }
|
public int? LevelOfEffort { get; set; }
|
||||||
|
|
||||||
public ICollection<Career> RelatedCareers { get; set; } = new List<Career>();
|
public ICollection<Career> RelatedCareers { get; set; } = [];
|
||||||
|
|
||||||
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
|
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
|
||||||
public string? RelatedCareersText { get; set; }
|
public string? RelatedCareersText { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString() => Name;
|
||||||
{
|
|
||||||
return Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly EventDefinition GeneralSchedule = new(){Name = "General Schedule"};
|
public static readonly EventDefinition GeneralSchedule = new(){Name = "General Schedule"};
|
||||||
public static readonly EventDefinition MeetTheCandidates = new(){Name = "Meet the Candidates"};
|
public static readonly EventDefinition MeetTheCandidates = new(){Name = "Meet the Candidates"};
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ public static class EventOccurrenceGrammar
|
|||||||
/// Array of all month names in order (January through December).
|
/// Array of all month names in order (January through December).
|
||||||
/// This is the single source of truth for month names used throughout the parser.
|
/// This is the single source of truth for month names used throughout the parser.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string[] MonthNames = new[]
|
public static readonly string[] MonthNames =
|
||||||
{
|
[
|
||||||
"January", "February", "March", "April", "May", "June",
|
"January", "February", "March", "April", "May", "June",
|
||||||
"July", "August", "September", "October", "November", "December"
|
"July", "August", "September", "October", "November", "December"
|
||||||
};
|
];
|
||||||
|
|
||||||
// Build month parsers dynamically from MonthNames array
|
// Build month parsers dynamically from MonthNames array
|
||||||
private static readonly Parser<string>[] MonthParsers = MonthNames
|
private static readonly Parser<string>[] MonthParsers = MonthNames
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class StudentEventRankingParser : CsvParserBase
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
var competitiveEvents = new List<EventDefinition>(6);
|
var competitiveEvents = new List<EventDefinition>();
|
||||||
|
|
||||||
for (var i = 1; i <= 6; i++)
|
for (var i = 1; i <= 6; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public class StudentParser : CsvParserBase
|
|||||||
|
|
||||||
public Student[] Parse()
|
public Student[] Parse()
|
||||||
{
|
{
|
||||||
var s = new List<Student>();
|
var students = new List<Student>();
|
||||||
|
|
||||||
CsvReader.Read();
|
CsvReader.Read();
|
||||||
CsvReader.ReadHeader();
|
CsvReader.ReadHeader();
|
||||||
@@ -44,9 +44,9 @@ public class StudentParser : CsvParserBase
|
|||||||
RegionalId = regionalId,
|
RegionalId = regionalId,
|
||||||
NationalId = nationalId
|
NationalId = nationalId
|
||||||
};
|
};
|
||||||
s.Add(student);
|
students.Add(student);
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.ToArray();
|
return students.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ public static class CareerFieldDefinitions
|
|||||||
public static IReadOnlyList<CareerField> GetRelatedCareerFields(IEnumerable<Career> careers)
|
public static IReadOnlyList<CareerField> GetRelatedCareerFields(IEnumerable<Career> careers)
|
||||||
{
|
{
|
||||||
if (careers == null)
|
if (careers == null)
|
||||||
return Array.Empty<CareerField>();
|
return [];
|
||||||
|
|
||||||
var careerNames = careers
|
var careerNames = careers
|
||||||
.Where(c => !string.IsNullOrWhiteSpace(c.Name))
|
.Where(c => !string.IsNullOrWhiteSpace(c.Name))
|
||||||
@@ -31,7 +31,7 @@ public static class CareerFieldDefinitions
|
|||||||
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
if (!careerNames.Any())
|
if (!careerNames.Any())
|
||||||
return Array.Empty<CareerField>();
|
return [];
|
||||||
|
|
||||||
var matchingFields = new HashSet<CareerField>();
|
var matchingFields = new HashSet<CareerField>();
|
||||||
var allFields = GetAllCareerFields();
|
var allFields = GetAllCareerFields();
|
||||||
@@ -74,15 +74,15 @@ public static class CareerFieldDefinitions
|
|||||||
|
|
||||||
private static IReadOnlyList<CareerField> CreateAllCareerFields()
|
private static IReadOnlyList<CareerField> CreateAllCareerFields()
|
||||||
{
|
{
|
||||||
return new List<CareerField>
|
return
|
||||||
{
|
[
|
||||||
// 1. Aerospace & Automotive Engineering
|
// 1. Aerospace & Automotive Engineering
|
||||||
new CareerField(
|
new CareerField(
|
||||||
1,
|
1,
|
||||||
"Aerospace & Automotive Engineering",
|
"Aerospace & Automotive Engineering",
|
||||||
"Careers focused on designing and engineering aircraft, spacecraft, and vehicles for transportation.",
|
"Careers focused on designing and engineering aircraft, spacecraft, and vehicles for transportation.",
|
||||||
new[] { "Aeronautical engineer", "Aircraft systems engineer", "Automobile designer", "Automotive designer", "Automotive modeler", "Race car engineer" },
|
[ "Aeronautical engineer", "Aircraft systems engineer", "Automobile designer", "Automotive designer", "Automotive modeler", "Race car engineer" ],
|
||||||
new[] { "aeronautical", "aircraft", "automobile", "automotive", "race car" }
|
[ "aeronautical", "aircraft", "automobile", "automotive", "race car" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 2. Mechanical & Robotics Engineering
|
// 2. Mechanical & Robotics Engineering
|
||||||
@@ -90,8 +90,8 @@ public static class CareerFieldDefinitions
|
|||||||
2,
|
2,
|
||||||
"Mechanical & Robotics Engineering",
|
"Mechanical & Robotics Engineering",
|
||||||
"Engineering disciplines involving mechanical systems, machinery design, and automated robotic systems.",
|
"Engineering disciplines involving mechanical systems, machinery design, and automated robotic systems.",
|
||||||
new[] { "Machine designer", "Mechanical drafter", "Mechanical engineer", "Robotics engineer" },
|
[ "Machine designer", "Mechanical drafter", "Mechanical engineer", "Robotics engineer" ],
|
||||||
new[] { "mechanical", "robotics", "machine" }
|
[ "mechanical", "robotics", "machine" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 3. Electrical & Electronics Engineering
|
// 3. Electrical & Electronics Engineering
|
||||||
@@ -99,8 +99,8 @@ public static class CareerFieldDefinitions
|
|||||||
3,
|
3,
|
||||||
"Electrical & Electronics Engineering",
|
"Electrical & Electronics Engineering",
|
||||||
"Careers involving electrical systems, circuits, and electronic device design and maintenance.",
|
"Careers involving electrical systems, circuits, and electronic device design and maintenance.",
|
||||||
new[] { "Electrical engineer", "Electrical technician", "Electrician", "Electromechanical engineer", "Electronic analyst", "Electronic designer" },
|
[ "Electrical engineer", "Electrical technician", "Electrician", "Electromechanical engineer", "Electronic analyst", "Electronic designer" ],
|
||||||
new[] { "electrical", "electronic", "electrician" }
|
[ "electrical", "electronic", "electrician" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 4. Civil & Structural Engineering
|
// 4. Civil & Structural Engineering
|
||||||
@@ -108,8 +108,8 @@ public static class CareerFieldDefinitions
|
|||||||
4,
|
4,
|
||||||
"Civil & Structural Engineering",
|
"Civil & Structural Engineering",
|
||||||
"Engineering fields focused on infrastructure, buildings, bridges, and construction project management.",
|
"Engineering fields focused on infrastructure, buildings, bridges, and construction project management.",
|
||||||
new[] { "Civil engineer", "Construction analyst", "Construction manager", "General contractor", "Structural engineer", "Structural iron and steel work technician" },
|
[ "Civil engineer", "Construction analyst", "Construction manager", "General contractor", "Structural engineer", "Structural iron and steel work technician" ],
|
||||||
new[] { "civil", "construction", "structural", "contractor" }
|
[ "civil", "construction", "structural", "contractor" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 5. Environmental & Energy Engineering
|
// 5. Environmental & Energy Engineering
|
||||||
@@ -117,8 +117,8 @@ public static class CareerFieldDefinitions
|
|||||||
5,
|
5,
|
||||||
"Environmental & Energy Engineering",
|
"Environmental & Energy Engineering",
|
||||||
"Engineering careers focused on sustainable energy solutions, environmental protection, and chemical processes.",
|
"Engineering careers focused on sustainable energy solutions, environmental protection, and chemical processes.",
|
||||||
new[] { "Chemical engineer", "Energy efficiency technician", "Environmental engineer", "Solar engineer", "Solar panel installer", "Solar sales consultant" },
|
[ "Chemical engineer", "Energy efficiency technician", "Environmental engineer", "Solar engineer", "Solar panel installer", "Solar sales consultant" ],
|
||||||
new[] { "chemical", "energy", "environmental", "solar" }
|
[ "chemical", "energy", "environmental", "solar" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 6. General Engineering & Quality
|
// 6. General Engineering & Quality
|
||||||
@@ -126,8 +126,8 @@ public static class CareerFieldDefinitions
|
|||||||
6,
|
6,
|
||||||
"General Engineering & Quality",
|
"General Engineering & Quality",
|
||||||
"Broad engineering roles including management, quality assurance, and standards compliance across various industries.",
|
"Broad engineering roles including management, quality assurance, and standards compliance across various industries.",
|
||||||
new[] { "Engineer", "Engineering manager", "Engineering technician", "Quality assurance engineer", "Quality engineer", "Standards engineer" },
|
[ "Engineer", "Engineering manager", "Engineering technician", "Quality assurance engineer", "Quality engineer", "Standards engineer" ],
|
||||||
new[] { "engineer", "quality", "standards" }
|
[ "engineer", "quality", "standards" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 7. Architecture & Urban Planning
|
// 7. Architecture & Urban Planning
|
||||||
@@ -135,8 +135,8 @@ public static class CareerFieldDefinitions
|
|||||||
7,
|
7,
|
||||||
"Architecture & Urban Planning",
|
"Architecture & Urban Planning",
|
||||||
"Design and planning careers focused on buildings, spaces, and community development.",
|
"Design and planning careers focused on buildings, spaces, and community development.",
|
||||||
new[] { "Architect", "Community planner", "Interior designer", "Urban and regional planner" },
|
[ "Architect", "Community planner", "Interior designer", "Urban and regional planner" ],
|
||||||
new[] { "architect", "planner", "interior design", "urban" }
|
[ "architect", "planner", "interior design", "urban" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 8. Software Development
|
// 8. Software Development
|
||||||
@@ -144,8 +144,8 @@ public static class CareerFieldDefinitions
|
|||||||
8,
|
8,
|
||||||
"Software Development",
|
"Software Development",
|
||||||
"Careers in creating, designing, and developing computer software applications and systems.",
|
"Careers in creating, designing, and developing computer software applications and systems.",
|
||||||
new[] { "Computer programmer", "Computer software engineer", "Programming & software development", "Software designer", "Software engineer" },
|
[ "Computer programmer", "Computer software engineer", "Programming & software development", "Software designer", "Software engineer" ],
|
||||||
new[] { "programming", "programmer", "software", "developer" }
|
[ "programming", "programmer", "software", "developer" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 9. IT & Networking
|
// 9. IT & Networking
|
||||||
@@ -153,8 +153,8 @@ public static class CareerFieldDefinitions
|
|||||||
9,
|
9,
|
||||||
"IT & Networking",
|
"IT & Networking",
|
||||||
"Information technology careers involving computer systems, networks, technical support, and telecommunications.",
|
"Information technology careers involving computer systems, networks, technical support, and telecommunications.",
|
||||||
new[] { "Computer engineer", "Computer network specialist", "Computer technician", "Information support & services", "Network systems", "Technical support specialist", "Telecommunications manager" },
|
[ "Computer engineer", "Computer network specialist", "Computer technician", "Information support & services", "Network systems", "Technical support specialist", "Telecommunications manager" ],
|
||||||
new[] { "network", "computer", "technical support", "telecommunications", "IT" }
|
[ "network", "computer", "technical support", "telecommunications", "IT" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 10. Cybersecurity & Digital Forensics
|
// 10. Cybersecurity & Digital Forensics
|
||||||
@@ -162,8 +162,8 @@ public static class CareerFieldDefinitions
|
|||||||
10,
|
10,
|
||||||
"Cybersecurity & Digital Forensics",
|
"Cybersecurity & Digital Forensics",
|
||||||
"Security-focused careers protecting digital systems, investigating cybercrimes, and ensuring information security.",
|
"Security-focused careers protecting digital systems, investigating cybercrimes, and ensuring information security.",
|
||||||
new[] { "Cryptographer", "Cyber Crime Investigator", "Cyber defense incident responder", "Cyber forensics expert", "Cyber legal advisor", "Cyber operator", "Cybersecurity engineer", "Vulnerability assessor" },
|
[ "Cryptographer", "Cyber Crime Investigator", "Cyber defense incident responder", "Cyber forensics expert", "Cyber legal advisor", "Cyber operator", "Cybersecurity engineer", "Vulnerability assessor" ],
|
||||||
new[] { "cyber", "security", "forensics", "cryptography", "vulnerability" }
|
[ "cyber", "security", "forensics", "cryptography", "vulnerability" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 11. Data Science & Analytics
|
// 11. Data Science & Analytics
|
||||||
@@ -171,8 +171,8 @@ public static class CareerFieldDefinitions
|
|||||||
11,
|
11,
|
||||||
"Data Science & Analytics",
|
"Data Science & Analytics",
|
||||||
"Careers analyzing data, applying mathematical and statistical methods to solve problems and make decisions.",
|
"Careers analyzing data, applying mathematical and statistical methods to solve problems and make decisions.",
|
||||||
new[] { "Actuary", "Data analyst", "Data scientist", "Economist", "Mathematician", "Operations research analyst" },
|
[ "Actuary", "Data analyst", "Data scientist", "Economist", "Mathematician", "Operations research analyst" ],
|
||||||
new[] { "data", "analyst", "actuary", "economist", "mathematician", "research" }
|
[ "data", "analyst", "actuary", "economist", "mathematician", "research" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 12. CAD, CNC & Manufacturing
|
// 12. CAD, CNC & Manufacturing
|
||||||
@@ -180,8 +180,8 @@ public static class CareerFieldDefinitions
|
|||||||
12,
|
12,
|
||||||
"CAD, CNC & Manufacturing",
|
"CAD, CNC & Manufacturing",
|
||||||
"Careers in computer-aided design, manufacturing processes, and production planning.",
|
"Careers in computer-aided design, manufacturing processes, and production planning.",
|
||||||
new[] { "CAD professional", "CNC programmer", "Manufacturing", "Production planner" },
|
[ "CAD professional", "CNC programmer", "Manufacturing", "Production planner" ],
|
||||||
new[] { "CAD", "CNC", "manufacturing", "production" }
|
[ "CAD", "CNC", "manufacturing", "production" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 13. Industrial & Product Design
|
// 13. Industrial & Product Design
|
||||||
@@ -189,8 +189,8 @@ public static class CareerFieldDefinitions
|
|||||||
13,
|
13,
|
||||||
"Industrial & Product Design",
|
"Industrial & Product Design",
|
||||||
"Design careers creating products, commercial goods, and industrial solutions with focus on form and function.",
|
"Design careers creating products, commercial goods, and industrial solutions with focus on form and function.",
|
||||||
new[] { "Appraiser", "Commercial and industrial design", "Designer", "Industrial designer", "Product designer" },
|
[ "Appraiser", "Commercial and industrial design", "Designer", "Industrial designer", "Product designer" ],
|
||||||
new[] { "designer", "design", "industrial", "product", "appraiser" }
|
[ "designer", "design", "industrial", "product", "appraiser" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 14. Visual Arts & Animation
|
// 14. Visual Arts & Animation
|
||||||
@@ -198,8 +198,8 @@ public static class CareerFieldDefinitions
|
|||||||
14,
|
14,
|
||||||
"Visual Arts & Animation",
|
"Visual Arts & Animation",
|
||||||
"Creative careers in visual design, illustration, animation, and digital art creation.",
|
"Creative careers in visual design, illustration, animation, and digital art creation.",
|
||||||
new[] { "Animator", "Artist", "Computer animator", "Graphic artist", "Illustrator", "Multimedia designer" },
|
[ "Animator", "Artist", "Computer animator", "Graphic artist", "Illustrator", "Multimedia designer" ],
|
||||||
new[] { "animator", "artist", "graphic", "illustrator", "multimedia" }
|
[ "animator", "artist", "graphic", "illustrator", "multimedia" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 15. Game Design & Interactive Media
|
// 15. Game Design & Interactive Media
|
||||||
@@ -207,8 +207,8 @@ public static class CareerFieldDefinitions
|
|||||||
15,
|
15,
|
||||||
"Game Design & Interactive Media",
|
"Game Design & Interactive Media",
|
||||||
"Careers in video game design, development, testing, and professional gaming.",
|
"Careers in video game design, development, testing, and professional gaming.",
|
||||||
new[] { "Game designer", "Game Play Tester", "Professional Gamer" },
|
[ "Game designer", "Game Play Tester", "Professional Gamer" ],
|
||||||
new[] { "game", "gamer", "gaming" }
|
[ "game", "gamer", "gaming" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 16. Audio & Music Production
|
// 16. Audio & Music Production
|
||||||
@@ -216,8 +216,8 @@ public static class CareerFieldDefinitions
|
|||||||
16,
|
16,
|
||||||
"Audio & Music Production",
|
"Audio & Music Production",
|
||||||
"Careers in audio engineering, music composition, sound design, and broadcast technology.",
|
"Careers in audio engineering, music composition, sound design, and broadcast technology.",
|
||||||
new[] { "Audio designer or engineer", "Audio Engineer", "Audio operator or technician", "Broadcast technician", "Music composer" },
|
[ "Audio designer or engineer", "Audio Engineer", "Audio operator or technician", "Broadcast technician", "Music composer" ],
|
||||||
new[] { "audio", "music", "broadcast", "sound" }
|
[ "audio", "music", "broadcast", "sound" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 17. Video & Film Production
|
// 17. Video & Film Production
|
||||||
@@ -225,8 +225,8 @@ public static class CareerFieldDefinitions
|
|||||||
17,
|
17,
|
||||||
"Video & Film Production",
|
"Video & Film Production",
|
||||||
"Careers in video production, filmmaking, directing, and television broadcasting.",
|
"Careers in video production, filmmaking, directing, and television broadcasting.",
|
||||||
new[] { "Audiovisual technician", "Director", "Entertainment/television broadcaster", "Videographer" },
|
[ "Audiovisual technician", "Director", "Entertainment/television broadcaster", "Videographer" ],
|
||||||
new[] { "video", "film", "director", "television", "broadcast", "videographer" }
|
[ "video", "film", "director", "television", "broadcast", "videographer" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 18. Web & Digital Communications
|
// 18. Web & Digital Communications
|
||||||
@@ -234,8 +234,8 @@ public static class CareerFieldDefinitions
|
|||||||
18,
|
18,
|
||||||
"Web & Digital Communications",
|
"Web & Digital Communications",
|
||||||
"Careers in web design, digital communication, and instructional technology.",
|
"Careers in web design, digital communication, and instructional technology.",
|
||||||
new[] { "Instructional technologist", "Web & digital communications", "Webmaster", "Website designer" },
|
[ "Instructional technologist", "Web & digital communications", "Webmaster", "Website designer" ],
|
||||||
new[] { "web", "website", "digital", "communications", "webmaster" }
|
[ "web", "website", "digital", "communications", "webmaster" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 19. Writing & Publishing
|
// 19. Writing & Publishing
|
||||||
@@ -243,8 +243,8 @@ public static class CareerFieldDefinitions
|
|||||||
19,
|
19,
|
||||||
"Writing & Publishing",
|
"Writing & Publishing",
|
||||||
"Careers in writing, editing, publishing, and content creation across various media formats.",
|
"Careers in writing, editing, publishing, and content creation across various media formats.",
|
||||||
new[] { "Ad copy writer", "Editor", "Publisher", "Screenplay writer", "Speech writer", "Technical writer", "Writer" },
|
[ "Ad copy writer", "Editor", "Publisher", "Screenplay writer", "Speech writer", "Technical writer", "Writer" ],
|
||||||
new[] { "writing", "writer", "editor", "publisher", "copy" }
|
[ "writing", "writer", "editor", "publisher", "copy" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 20. Journalism & Public Relations
|
// 20. Journalism & Public Relations
|
||||||
@@ -252,8 +252,8 @@ public static class CareerFieldDefinitions
|
|||||||
20,
|
20,
|
||||||
"Journalism & Public Relations",
|
"Journalism & Public Relations",
|
||||||
"Careers in news reporting, photojournalism, public relations, and communications management.",
|
"Careers in news reporting, photojournalism, public relations, and communications management.",
|
||||||
new[] { "Internal communications manager", "Motivational speaker", "Photojournalist", "Reporter" },
|
[ "Internal communications manager", "Motivational speaker", "Photojournalist", "Reporter" ],
|
||||||
new[] { "journalism", "reporter", "photojournalist", "communications", "speaker" }
|
[ "journalism", "reporter", "photojournalist", "communications", "speaker" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 21. Forensics & Criminal Investigation
|
// 21. Forensics & Criminal Investigation
|
||||||
@@ -261,8 +261,8 @@ public static class CareerFieldDefinitions
|
|||||||
21,
|
21,
|
||||||
"Forensics & Criminal Investigation",
|
"Forensics & Criminal Investigation",
|
||||||
"Careers in criminal investigation, forensic science, and analyzing evidence for legal proceedings.",
|
"Careers in criminal investigation, forensic science, and analyzing evidence for legal proceedings.",
|
||||||
new[] { "Crime scene investigator", "Detective", "Forensic accountant", "Forensic anthropologist", "Forensic engineering scientist", "Forensic pathologist" },
|
[ "Crime scene investigator", "Detective", "Forensic accountant", "Forensic anthropologist", "Forensic engineering scientist", "Forensic pathologist" ],
|
||||||
new[] { "forensic", "detective", "investigator", "crime" }
|
[ "forensic", "detective", "investigator", "crime" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 22. Healthcare & Medical Technology
|
// 22. Healthcare & Medical Technology
|
||||||
@@ -270,8 +270,8 @@ public static class CareerFieldDefinitions
|
|||||||
22,
|
22,
|
||||||
"Healthcare & Medical Technology",
|
"Healthcare & Medical Technology",
|
||||||
"Medical and healthcare careers providing patient care, medical technology, and health services.",
|
"Medical and healthcare careers providing patient care, medical technology, and health services.",
|
||||||
new[] { "Dietitian", "Doctor", "Epidemiologist", "Medical technologist", "Nurse", "Pharmacist", "Prosthetics practitioner" },
|
[ "Dietitian", "Doctor", "Epidemiologist", "Medical technologist", "Nurse", "Pharmacist", "Prosthetics practitioner" ],
|
||||||
new[] { "medical", "health", "doctor", "nurse", "pharmacist", "dietitian", "epidemiology" }
|
[ "medical", "health", "doctor", "nurse", "pharmacist", "dietitian", "epidemiology" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 23. Science & Research
|
// 23. Science & Research
|
||||||
@@ -279,8 +279,8 @@ public static class CareerFieldDefinitions
|
|||||||
23,
|
23,
|
||||||
"Science & Research",
|
"Science & Research",
|
||||||
"Scientific research careers across biology, physics, meteorology, and other scientific disciplines.",
|
"Scientific research careers across biology, physics, meteorology, and other scientific disciplines.",
|
||||||
new[] { "Botanist", "Food scientist", "Meteorologist", "Molecular biologist", "Physics instructor", "Plant geneticist", "Research and development scientist", "Research assistant", "Researcher" },
|
[ "Botanist", "Food scientist", "Meteorologist", "Molecular biologist", "Physics instructor", "Plant geneticist", "Research and development scientist", "Research assistant", "Researcher" ],
|
||||||
new[] { "scientist", "research", "biology", "physics", "botanist", "meteorologist", "geneticist" }
|
[ "scientist", "research", "biology", "physics", "botanist", "meteorologist", "geneticist" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 24. Education & Training
|
// 24. Education & Training
|
||||||
@@ -288,8 +288,8 @@ public static class CareerFieldDefinitions
|
|||||||
24,
|
24,
|
||||||
"Education & Training",
|
"Education & Training",
|
||||||
"Careers in teaching, training, and educational instruction across various subjects and technologies.",
|
"Careers in teaching, training, and educational instruction across various subjects and technologies.",
|
||||||
new[] { "Educator", "Teacher/trainer", "Technology education instructor" },
|
[ "Educator", "Teacher/trainer", "Technology education instructor" ],
|
||||||
new[] { "educator", "teacher", "trainer", "education", "instructor" }
|
[ "educator", "teacher", "trainer", "education", "instructor" ]
|
||||||
),
|
),
|
||||||
|
|
||||||
// 25. Business, Legal & Government
|
// 25. Business, Legal & Government
|
||||||
@@ -297,10 +297,10 @@ public static class CareerFieldDefinitions
|
|||||||
25,
|
25,
|
||||||
"Business, Legal & Government",
|
"Business, Legal & Government",
|
||||||
"Careers in business management, legal services, government, politics, and public policy.",
|
"Careers in business management, legal services, government, politics, and public policy.",
|
||||||
new[] { "Creative consultant", "Entrepreneur", "Government Official", "Lawyer", "Legal Aide", "Lobbyist", "Management executive", "Market researcher", "Marketing strategist", "Parliamentarian", "Politician", "Project manager", "Public affairs specialist", "Public policy specialist", "Recording Clerk", "Small business owner", "Volunteer manager" },
|
[ "Creative consultant", "Entrepreneur", "Government Official", "Lawyer", "Legal Aide", "Lobbyist", "Management executive", "Market researcher", "Marketing strategist", "Parliamentarian", "Politician", "Project manager", "Public affairs specialist", "Public policy specialist", "Recording Clerk", "Small business owner", "Volunteer manager" ],
|
||||||
new[] { "business", "legal", "lawyer", "government", "politician", "manager", "marketing", "consultant", "entrepreneur" }
|
[ "business", "legal", "lawyer", "government", "politician", "manager", "marketing", "consultant", "entrepreneur" ]
|
||||||
)
|
)
|
||||||
};
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
// Load teams for all event definitions
|
// Load teams for all event definitions
|
||||||
var teamsByEventId = await EventOccurrenceService.GetTeamsByEventDefinitionIdsAsync(eventDefinitionIds);
|
var teamsByEventId = await EventOccurrenceService.GetTeamsByEventDefinitionIdsAsync(eventDefinitionIds);
|
||||||
|
|
||||||
var items = new List<CalendarEventItem>();
|
List<CalendarEventItem> items = [];
|
||||||
foreach (var occ in eventOccurrences)
|
foreach (var occ in eventOccurrences)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
// Get student first names for this event definition
|
// Get student first names for this event definition
|
||||||
var studentFirstNames = occ.EventDefinition != null
|
var studentFirstNames = occ.EventDefinition != null
|
||||||
? StudentFirstNames(occ.EventDefinition, teamsByEventId)
|
? StudentFirstNames(occ.EventDefinition, teamsByEventId)
|
||||||
: new List<string>();
|
: [];
|
||||||
|
|
||||||
var calendarItem = new CalendarEventItem(occ, studentFirstNames);
|
var calendarItem = new CalendarEventItem(occ, studentFirstNames);
|
||||||
items.Add(calendarItem);
|
items.Add(calendarItem);
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, "Error loading calendar events");
|
Logger.LogError(ex, "Error loading calendar events");
|
||||||
_calendarItems = new List<CalendarEventItem>();
|
_calendarItems = [];
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
|
|
||||||
private static List<string> StudentFirstNames(EventDefinition ed, Dictionary<int, List<Team>> teamsByEventId)
|
private static List<string> StudentFirstNames(EventDefinition ed, Dictionary<int, List<Team>> teamsByEventId)
|
||||||
{
|
{
|
||||||
var studentFirstNames = new List<string>();
|
List<string> studentFirstNames = [];
|
||||||
if (ed?.Id == null || !teamsByEventId.TryGetValue(ed.Id, out var teams)) return studentFirstNames;
|
if (ed?.Id == null || !teamsByEventId.TryGetValue(ed.Id, out var teams)) return studentFirstNames;
|
||||||
|
|
||||||
// Get all unique student first names from all teams for this event
|
// Get all unique student first names from all teams for this event
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
|
|
||||||
private string GetEventTooltip(CalendarEventItem item)
|
private string GetEventTooltip(CalendarEventItem item)
|
||||||
{
|
{
|
||||||
var parts = new List<string>();
|
List<string> parts = [];
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(item.EventDefinition?.Name))
|
if (!string.IsNullOrEmpty(item.EventDefinition?.Name))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ else
|
|||||||
{
|
{
|
||||||
if (!_fieldIdToCareers.ContainsKey(field.Id))
|
if (!_fieldIdToCareers.ContainsKey(field.Id))
|
||||||
{
|
{
|
||||||
_fieldIdToCareers[field.Id] = new List<string>();
|
_fieldIdToCareers[field.Id] = [];
|
||||||
}
|
}
|
||||||
// Add unique career names for this field
|
// Add unique career names for this field
|
||||||
foreach (var career in evt.RelatedCareers)
|
foreach (var career in evt.RelatedCareers)
|
||||||
@@ -153,8 +153,8 @@ else
|
|||||||
|
|
||||||
private NetworkData GenerateNetworkData(List<EventDefinition> events)
|
private NetworkData GenerateNetworkData(List<EventDefinition> events)
|
||||||
{
|
{
|
||||||
var nodes = new List<Node>();
|
List<Node> nodes = [];
|
||||||
var edges = new List<Edge>();
|
List<Edge> edges = [];
|
||||||
|
|
||||||
// Dictionary to track node IDs (to avoid duplicates)
|
// Dictionary to track node IDs (to avoid duplicates)
|
||||||
var eventNodeIds = new Dictionary<int, string>();
|
var eventNodeIds = new Dictionary<int, string>();
|
||||||
@@ -284,7 +284,7 @@ else
|
|||||||
Title = field.Name,
|
Title = field.Name,
|
||||||
Description = field.Description,
|
Description = field.Description,
|
||||||
IsCareerField = true,
|
IsCareerField = true,
|
||||||
Careers = careers?.ToList() ?? new List<string>()
|
Careers = careers?.ToList() ?? []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
@page "/events"
|
@page "/events"
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
|
@implements IAsyncDisposable
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using WebApp.Models
|
@using WebApp.Models
|
||||||
@using WebApp.Components.Shared.Components
|
@using WebApp.Components.Shared.Components
|
||||||
@@ -74,16 +75,32 @@
|
|||||||
@code {
|
@code {
|
||||||
MudDataGrid<EventDefinition> _dataGrid = null!;
|
MudDataGrid<EventDefinition> _dataGrid = null!;
|
||||||
private bool _isLoading = true;
|
private bool _isLoading = true;
|
||||||
|
private CancellationTokenSource? _cancellationTokenSource;
|
||||||
|
private bool _isDisposed = false;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
_cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<GridData<EventDefinition>> ServerReload(GridState<EventDefinition> state)
|
private async Task<GridData<EventDefinition>> ServerReload(GridState<EventDefinition> state)
|
||||||
{
|
{
|
||||||
|
if (_isDisposed)
|
||||||
|
{
|
||||||
|
return new GridData<EventDefinition> { TotalItems = 0, Items = [] };
|
||||||
|
}
|
||||||
|
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var query = Context.Events.OrderBy(e => e.Name).Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||||
|
|
||||||
var totalItems = await query.CountAsync();
|
var query = Context.Events
|
||||||
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync();
|
.AsNoTracking()
|
||||||
|
.OrderBy(e => e.Name).Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
||||||
|
|
||||||
|
var totalItems = await query.CountAsync(cancellationToken);
|
||||||
|
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
return new GridData<EventDefinition>
|
return new GridData<EventDefinition>
|
||||||
{
|
{
|
||||||
@@ -91,15 +108,30 @@
|
|||||||
Items = pagedData
|
Items = pagedData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
return new GridData<EventDefinition> { TotalItems = 0, Items = [] };
|
||||||
|
}
|
||||||
|
catch (JSDisconnectedException)
|
||||||
|
{
|
||||||
|
return new GridData<EventDefinition> { TotalItems = 0, Items = [] };
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
{
|
{
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task DeleteEventDefinition(EventDefinition evt)
|
private async Task DeleteEventDefinition(EventDefinition evt)
|
||||||
{
|
{
|
||||||
//_isRowBlocked = true;
|
if (_isDisposed) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||||
|
|
||||||
var result = await DialogService
|
var result = await DialogService
|
||||||
.ShowMessageBox("Delete Event",
|
.ShowMessageBox("Delete Event",
|
||||||
@@ -107,15 +139,51 @@
|
|||||||
yesText:"Yes",
|
yesText:"Yes",
|
||||||
noText:"Cancel");
|
noText:"Cancel");
|
||||||
|
|
||||||
|
if (_isDisposed) return;
|
||||||
|
|
||||||
if (result == true)
|
if (result == true)
|
||||||
{
|
{
|
||||||
Context.Events.Remove(evt!);
|
Context.Events.Remove(evt!);
|
||||||
await Context.SaveChangesAsync();
|
await Context.SaveChangesAsync(cancellationToken);
|
||||||
Snackbar.Add($"Delete event: Delete of Event {evt.Name}", Severity.Info);
|
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Event {evt.Name} deleted", Severity.Info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//_isRowBlocked = false;
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
await _dataGrid.ReloadServerData();
|
await _dataGrid.ReloadServerData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
// Component was disposed, ignore
|
||||||
|
}
|
||||||
|
catch (JSDisconnectedException)
|
||||||
|
{
|
||||||
|
// JS connection lost, ignore
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error deleting event: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
_isDisposed = true;
|
||||||
|
_cancellationTokenSource?.Cancel();
|
||||||
|
_cancellationTokenSource?.Dispose();
|
||||||
|
_cancellationTokenSource = null;
|
||||||
|
}
|
||||||
|
await ValueTask.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -178,7 +178,7 @@
|
|||||||
_scheduledTeams = _scheduledTeams.Where(t => t != unassignedTeam);
|
_scheduledTeams = _scheduledTeams.Where(t => t != unassignedTeam);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_scheduledTeams = _scheduledTeams.Concat(new[] { unassignedTeam });
|
_scheduledTeams = _scheduledTeams.Concat([unassignedTeam]);
|
||||||
}
|
}
|
||||||
await SaveScheduledTeams();
|
await SaveScheduledTeams();
|
||||||
}
|
}
|
||||||
@@ -216,6 +216,7 @@
|
|||||||
|
|
||||||
_teams
|
_teams
|
||||||
= await Context.Teams
|
= await Context.Teams
|
||||||
|
.AsNoTracking()
|
||||||
.Include(e => e.Event)
|
.Include(e => e.Event)
|
||||||
.Include(e => e.Students)
|
.Include(e => e.Students)
|
||||||
.OrderBy(e => e.Event.Name)
|
.OrderBy(e => e.Event.Name)
|
||||||
@@ -224,6 +225,7 @@
|
|||||||
|
|
||||||
_students =
|
_students =
|
||||||
await Context.Students
|
await Context.Students
|
||||||
|
.AsNoTracking()
|
||||||
.Include(e => e.Teams)
|
.Include(e => e.Teams)
|
||||||
.ThenInclude(e => e.Captain)
|
.ThenInclude(e => e.Captain)
|
||||||
.Include(e => e.EventRankings)
|
.Include(e => e.EventRankings)
|
||||||
@@ -311,13 +313,13 @@
|
|||||||
|
|
||||||
// Try recommendation strategies in priority order
|
// Try recommendation strategies in priority order
|
||||||
var scheduler = new UnassignedStudentScheduler(_teams, _solution.TimeSlots);
|
var scheduler = new UnassignedStudentScheduler(_teams, _solution.TimeSlots);
|
||||||
var strategies = new[]
|
UnassignedScheduleStrategy[] strategies =
|
||||||
{
|
[
|
||||||
UnassignedScheduleStrategy.LevelOfEffort,
|
UnassignedScheduleStrategy.LevelOfEffort,
|
||||||
UnassignedScheduleStrategy.BiggestGroup,
|
UnassignedScheduleStrategy.BiggestGroup,
|
||||||
UnassignedScheduleStrategy.AnyNotMeetingAlready,
|
UnassignedScheduleStrategy.AnyNotMeetingAlready,
|
||||||
UnassignedScheduleStrategy.IndividualEvents
|
UnassignedScheduleStrategy.IndividualEvents
|
||||||
};
|
];
|
||||||
|
|
||||||
_possibleAdditions = strategies
|
_possibleAdditions = strategies
|
||||||
.Select(strategy => scheduler.ScheduleStrategy(strategy))
|
.Select(strategy => scheduler.ScheduleStrategy(strategy))
|
||||||
|
|||||||
@@ -140,11 +140,13 @@ else
|
|||||||
.OrderBy(e => e.Event.Name)
|
.OrderBy(e => e.Event.Name)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var events = await Context.Events.ToArrayAsync();
|
var events = await Context.Events
|
||||||
|
.AsNoTracking()
|
||||||
|
.ToArrayAsync();
|
||||||
var remainingEvents =
|
var remainingEvents =
|
||||||
events
|
events
|
||||||
.Where(e => _eventStudentRankings.All(est => est.Event.Id != e.Id))
|
.Where(e => _eventStudentRankings.All(est => est.Event.Id != e.Id))
|
||||||
.Select(e => new EventStudentRankings { Event = e, StudentRanking = Array.Empty<Tuple<Student, int>>() })
|
.Select(e => new EventStudentRankings { Event = e, StudentRanking = [] })
|
||||||
.OrderBy(e => e.Event.Name)
|
.OrderBy(e => e.Event.Name)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
@page "/students"
|
@page "/students"
|
||||||
@attribute [Authorize]
|
@attribute [Authorize]
|
||||||
|
@implements IAsyncDisposable
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using WebApp.Models
|
@using WebApp.Models
|
||||||
@using WebApp.Components.Shared.Components
|
@using WebApp.Components.Shared.Components
|
||||||
@@ -68,18 +69,34 @@
|
|||||||
@code {
|
@code {
|
||||||
MudDataGrid<Student> _dataGrid = null!;
|
MudDataGrid<Student> _dataGrid = null!;
|
||||||
private bool _isLoading = true;
|
private bool _isLoading = true;
|
||||||
|
private CancellationTokenSource? _cancellationTokenSource;
|
||||||
|
private bool _isDisposed = false;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
_cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<GridData<Student>> ServerReload(GridState<Student> state)
|
private async Task<GridData<Student>> ServerReload(GridState<Student> state)
|
||||||
{
|
{
|
||||||
|
if (_isDisposed)
|
||||||
|
{
|
||||||
|
return new GridData<Student> { TotalItems = 0, Items = [] };
|
||||||
|
}
|
||||||
|
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||||
|
|
||||||
var query =
|
var query =
|
||||||
Context.Students.OrderBy(e => e.LastName)
|
Context.Students
|
||||||
|
.AsNoTracking()
|
||||||
|
.OrderBy(e => e.LastName)
|
||||||
.Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
.Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
||||||
|
|
||||||
var totalItems = await query.CountAsync();
|
var totalItems = await query.CountAsync(cancellationToken);
|
||||||
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync();
|
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
return new GridData<Student>
|
return new GridData<Student>
|
||||||
{
|
{
|
||||||
@@ -87,15 +104,30 @@
|
|||||||
Items = pagedData
|
Items = pagedData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
return new GridData<Student> { TotalItems = 0, Items = [] };
|
||||||
|
}
|
||||||
|
catch (JSDisconnectedException)
|
||||||
|
{
|
||||||
|
return new GridData<Student> { TotalItems = 0, Items = [] };
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
{
|
{
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task DeleteStudent(Student student)
|
private async Task DeleteStudent(Student student)
|
||||||
{
|
{
|
||||||
//_isRowBlocked = true;
|
if (_isDisposed) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||||
|
|
||||||
var result = await DialogService
|
var result = await DialogService
|
||||||
.ShowMessageBox("Delete student",
|
.ShowMessageBox("Delete student",
|
||||||
@@ -103,15 +135,51 @@
|
|||||||
yesText:"Yes",
|
yesText:"Yes",
|
||||||
noText:"Cancel");
|
noText:"Cancel");
|
||||||
|
|
||||||
|
if (_isDisposed) return;
|
||||||
|
|
||||||
if (result == true)
|
if (result == true)
|
||||||
{
|
{
|
||||||
Context.Students.Remove(student!);
|
Context.Students.Remove(student!);
|
||||||
await Context.SaveChangesAsync();
|
await Context.SaveChangesAsync(cancellationToken);
|
||||||
Snackbar.Add($"Delete event: Delete of Student {student.Name}", Severity.Info);
|
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Student {student.Name} deleted", Severity.Info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//_isRowBlocked = false;
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
await _dataGrid.ReloadServerData();
|
await _dataGrid.ReloadServerData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
// Component was disposed, ignore
|
||||||
|
}
|
||||||
|
catch (JSDisconnectedException)
|
||||||
|
{
|
||||||
|
// JS connection lost, ignore
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"Error deleting student: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (!_isDisposed)
|
||||||
|
{
|
||||||
|
_isDisposed = true;
|
||||||
|
_cancellationTokenSource?.Cancel();
|
||||||
|
_cancellationTokenSource?.Dispose();
|
||||||
|
_cancellationTokenSource = null;
|
||||||
|
}
|
||||||
|
await ValueTask.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -174,6 +174,7 @@
|
|||||||
{
|
{
|
||||||
// Load all students with their teams
|
// Load all students with their teams
|
||||||
var students = await Context.Students
|
var students = await Context.Students
|
||||||
|
.AsNoTracking()
|
||||||
.Include(s => s.Teams)
|
.Include(s => s.Teams)
|
||||||
.ThenInclude(t => t.Event)
|
.ThenInclude(t => t.Event)
|
||||||
.Include(s => s.Teams)
|
.Include(s => s.Teams)
|
||||||
@@ -270,7 +271,7 @@
|
|||||||
Student = student,
|
Student = student,
|
||||||
Events = student.Teams?.Where(t => t?.Event != null)
|
Events = student.Teams?.Where(t => t?.Event != null)
|
||||||
.Select(t => t.Event)
|
.Select(t => t.Event)
|
||||||
.ToList() ?? new List<EventDefinition>()
|
.ToList() ?? []
|
||||||
};
|
};
|
||||||
|
|
||||||
return ValidationService.ValidateStudentStatistics(stats, ValidationContext.StudentRegistration);
|
return ValidationService.ValidateStudentStatistics(stats, ValidationContext.StudentRegistration);
|
||||||
|
|||||||
@@ -71,7 +71,9 @@
|
|||||||
.Include(e => e.Event)
|
.Include(e => e.Event)
|
||||||
.Include(e => e.Students)
|
.Include(e => e.Students)
|
||||||
.FirstOrDefaultAsync(m => m.Id == Id);
|
.FirstOrDefaultAsync(m => m.Id == Id);
|
||||||
_students = await Context.Students.ToListAsync();
|
_students = await Context.Students
|
||||||
|
.AsNoTracking()
|
||||||
|
.ToListAsync();
|
||||||
_selectedStudents = Team?.Students.ToList();
|
_selectedStudents = Team?.Students.ToList();
|
||||||
|
|
||||||
if (Team is null)
|
if (Team is null)
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ else
|
|||||||
{
|
{
|
||||||
_teams
|
_teams
|
||||||
= await Context.Teams
|
= await Context.Teams
|
||||||
|
.AsNoTracking()
|
||||||
.Include(e => e.Event)
|
.Include(e => e.Event)
|
||||||
.Include(e => e.Students)
|
.Include(e => e.Students)
|
||||||
.OrderByEventFormatFirst()
|
.OrderByEventFormatFirst()
|
||||||
@@ -228,6 +229,7 @@ else
|
|||||||
_maxTeamSize = _teams.Max(t => t.Students.Count);
|
_maxTeamSize = _teams.Max(t => t.Students.Count);
|
||||||
_students =
|
_students =
|
||||||
await Context.Students
|
await Context.Students
|
||||||
|
.AsNoTracking()
|
||||||
.Include(e => e.Teams)
|
.Include(e => e.Teams)
|
||||||
.ThenInclude(e => e.Captain)
|
.ThenInclude(e => e.Captain)
|
||||||
.Include(e => e.EventRankings)
|
.Include(e => e.EventRankings)
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ namespace WebApp;
|
|||||||
public sealed class LocalStorageService
|
public sealed class LocalStorageService
|
||||||
{
|
{
|
||||||
private readonly IJSRuntime _jsRuntime;
|
private readonly IJSRuntime _jsRuntime;
|
||||||
|
private readonly ILogger<LocalStorageService> _logger;
|
||||||
|
|
||||||
public LocalStorageService(IJSRuntime jsRuntime)
|
public LocalStorageService(IJSRuntime jsRuntime, ILogger<LocalStorageService> logger)
|
||||||
{
|
{
|
||||||
_jsRuntime = jsRuntime;
|
_jsRuntime = jsRuntime;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -47,7 +49,7 @@ public sealed class LocalStorageService
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to save boolean to localStorage [{key}]: {ex.Message}");
|
_logger.LogWarning(ex, "Failed to save boolean to localStorage [{Key}]", key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +85,7 @@ public sealed class LocalStorageService
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to save integer to localStorage [{key}]: {ex.Message}");
|
_logger.LogWarning(ex, "Failed to save integer to localStorage [{Key}]", key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,14 +102,14 @@ public sealed class LocalStorageService
|
|||||||
if (!string.IsNullOrEmpty(json))
|
if (!string.IsNullOrEmpty(json))
|
||||||
{
|
{
|
||||||
var array = JsonSerializer.Deserialize<int[]>(json);
|
var array = JsonSerializer.Deserialize<int[]>(json);
|
||||||
return array ?? Array.Empty<int>();
|
return array ?? [];
|
||||||
}
|
}
|
||||||
return Array.Empty<int>();
|
return [];
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to load integer array from localStorage [{key}]: {ex.Message}");
|
_logger.LogWarning(ex, "Failed to load integer array from localStorage [{Key}]", key);
|
||||||
return Array.Empty<int>();
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +127,7 @@ public sealed class LocalStorageService
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to save integer array to localStorage [{key}]: {ex.Message}");
|
_logger.LogWarning(ex, "Failed to save integer array to localStorage [{Key}]", key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +143,7 @@ public sealed class LocalStorageService
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to remove from localStorage [{key}]: {ex.Message}");
|
_logger.LogWarning(ex, "Failed to remove from localStorage [{Key}]", key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +158,7 @@ public sealed class LocalStorageService
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to clear localStorage: {ex.Message}");
|
_logger.LogWarning(ex, "Failed to clear localStorage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,15 +33,14 @@ namespace WebApp.Logging
|
|||||||
LogEventLevel.Information,
|
LogEventLevel.Information,
|
||||||
null, // No exception at Info level
|
null, // No exception at Info level
|
||||||
messageTemplate,
|
messageTemplate,
|
||||||
new[]
|
[
|
||||||
{
|
|
||||||
new LogEventProperty("OriginalMessage",
|
new LogEventProperty("OriginalMessage",
|
||||||
new ScalarValue(logEvent.MessageTemplate.Render(logEvent.Properties))),
|
new ScalarValue(logEvent.MessageTemplate.Render(logEvent.Properties))),
|
||||||
new LogEventProperty("SourceContext",
|
new LogEventProperty("SourceContext",
|
||||||
logEvent.Properties.GetValueOrDefault("SourceContext") ?? new ScalarValue("Unknown")),
|
logEvent.Properties.GetValueOrDefault("SourceContext") ?? new ScalarValue("Unknown")),
|
||||||
new LogEventProperty("RequestPath",
|
new LogEventProperty("RequestPath",
|
||||||
logEvent.Properties.GetValueOrDefault("RequestPath") ?? new ScalarValue("Unknown"))
|
logEvent.Properties.GetValueOrDefault("RequestPath") ?? new ScalarValue("Unknown"))
|
||||||
});
|
]);
|
||||||
|
|
||||||
_wrappedSink.Emit(rewrittenEvent);
|
_wrappedSink.Emit(rewrittenEvent);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public class EventDefinitionService
|
|||||||
|
|
||||||
// Get all existing careers from database (case-insensitive lookup)
|
// Get all existing careers from database (case-insensitive lookup)
|
||||||
var existingCareers = await _context.Careers
|
var existingCareers = await _context.Careers
|
||||||
|
.AsNoTracking()
|
||||||
.Where(c => !string.IsNullOrWhiteSpace(c.Name))
|
.Where(c => !string.IsNullOrWhiteSpace(c.Name))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user