Enhance event occurrence parsing with school level filtering
This commit introduces a new SchoolLevel enum and updates the EventOccurrenceParser to filter event occurrences based on the specified school level (Middle School or High School). The EventOccurrenceParseResult and EventOccurrenceParserResult classes have been updated to track skipped section headers and counts for both school levels. Additionally, the EventOccurrenceParserService has been modified to read the school level from configuration, and the UI has been updated to allow users to select the school level for event imports. This enhancement improves the accuracy of event parsing and provides better user feedback on skipped occurrences.
This commit is contained in:
@@ -32,10 +32,26 @@ public class EventOccurrenceParseResult
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of high school (HS) section headers that were encountered but skipped
|
/// List of high school (HS) section headers that were encountered but skipped
|
||||||
/// because they don't match any event definition in the system.
|
/// because they don't match the chapter's school level setting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string> SkippedHSSectionHeaders { get; set; } = new();
|
public List<string> SkippedHSSectionHeaders { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of middle school (MS) section headers that were encountered but skipped
|
||||||
|
/// because they don't match the chapter's school level setting.
|
||||||
|
/// </summary>
|
||||||
|
public List<string> SkippedMSSectionHeaders { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of Middle School (MS) event occurrences that were skipped due to school level filtering.
|
||||||
|
/// </summary>
|
||||||
|
public int SkippedMSEventCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of High School (HS) event occurrences that were skipped due to school level filtering.
|
||||||
|
/// </summary>
|
||||||
|
public int SkippedHSEventCount { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total number of event occurrences successfully parsed.
|
/// Total number of event occurrences successfully parsed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
namespace Core.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// School level for filtering event occurrences.
|
||||||
|
/// </summary>
|
||||||
|
public enum SchoolLevel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Middle School level
|
||||||
|
/// </summary>
|
||||||
|
MiddleSchool,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// High School level
|
||||||
|
/// </summary>
|
||||||
|
HighSchool
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ using Core.Entities;
|
|||||||
using Core.Models;
|
using Core.Models;
|
||||||
using EventOccurrenceParsers = Core.Parsers.EventOccurrence;
|
using EventOccurrenceParsers = Core.Parsers.EventOccurrence;
|
||||||
using Core.Utility;
|
using Core.Utility;
|
||||||
|
using SchoolLevel = Core.Models.SchoolLevel;
|
||||||
|
|
||||||
namespace Core.Parsers;
|
namespace Core.Parsers;
|
||||||
|
|
||||||
@@ -14,17 +15,22 @@ public class EventOccurrenceParserResult
|
|||||||
public IDictionary<EventDefinition, List<Entities.EventOccurrence>> Occurrences { get; set; } = new Dictionary<EventDefinition, List<Entities.EventOccurrence>>();
|
public IDictionary<EventDefinition, List<Entities.EventOccurrence>> Occurrences { get; set; } = new Dictionary<EventDefinition, List<Entities.EventOccurrence>>();
|
||||||
public List<ParsingIssue> Issues { get; set; } = new();
|
public List<ParsingIssue> Issues { get; set; } = new();
|
||||||
public List<string> SkippedHSSectionHeaders { get; set; } = new();
|
public List<string> SkippedHSSectionHeaders { get; set; } = new();
|
||||||
|
public List<string> SkippedMSSectionHeaders { get; set; } = new();
|
||||||
|
public int SkippedMSEventCount { get; set; }
|
||||||
|
public int SkippedHSEventCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EventOccurrenceParser
|
public class EventOccurrenceParser
|
||||||
{
|
{
|
||||||
private FileSystemInfo _txtFile;
|
private FileSystemInfo _txtFile;
|
||||||
private ICollection<EventDefinition> _events;
|
private ICollection<EventDefinition> _events;
|
||||||
|
private SchoolLevel? _schoolLevel;
|
||||||
|
|
||||||
public EventOccurrenceParser(FileSystemInfo txtFile, ICollection<EventDefinition> events)
|
public EventOccurrenceParser(FileSystemInfo txtFile, ICollection<EventDefinition> events, SchoolLevel? schoolLevel = null)
|
||||||
{
|
{
|
||||||
_events = events;
|
_events = events;
|
||||||
_txtFile = txtFile;
|
_txtFile = txtFile;
|
||||||
|
_schoolLevel = schoolLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventOccurrenceParserResult Parse()
|
public EventOccurrenceParserResult Parse()
|
||||||
@@ -35,6 +41,7 @@ public class EventOccurrenceParser
|
|||||||
EventDefinition? currentEventDefinition = null;
|
EventDefinition? currentEventDefinition = null;
|
||||||
bool inContinuationMode = false;
|
bool inContinuationMode = false;
|
||||||
bool inHSSection = false;
|
bool inHSSection = false;
|
||||||
|
bool inMSSection = false;
|
||||||
|
|
||||||
var lines = File.ReadLines(_txtFile.FullName);
|
var lines = File.ReadLines(_txtFile.FullName);
|
||||||
foreach (var (line, index) in lines.Select((line, index) => (line, index + 1)))
|
foreach (var (line, index) in lines.Select((line, index) => (line, index + 1)))
|
||||||
@@ -73,22 +80,71 @@ public class EventOccurrenceParser
|
|||||||
// Section headers break continuation mode
|
// Section headers break continuation mode
|
||||||
inContinuationMode = false;
|
inContinuationMode = false;
|
||||||
|
|
||||||
// Check if this is an HS event - if so, skip gracefully regardless of whether it matches
|
// Determine if we should skip this event based on chapter's school level setting
|
||||||
// This prevents HS events from being incorrectly associated with MS events (e.g.,
|
bool shouldSkip = false;
|
||||||
// "Biotechnology Design – HS" matching "Biotechnology" MS event)
|
if (!string.IsNullOrWhiteSpace(schoolLevel))
|
||||||
if (schoolLevel.Equals("HS", StringComparison.OrdinalIgnoreCase))
|
{
|
||||||
|
if (_schoolLevel.HasValue)
|
||||||
|
{
|
||||||
|
// School level is set - filter based on it
|
||||||
|
if (_schoolLevel.Value == SchoolLevel.MiddleSchool &&
|
||||||
|
schoolLevel.Equals("HS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
shouldSkip = true;
|
||||||
|
result.SkippedHSSectionHeaders.Add(normalizedLine);
|
||||||
|
inHSSection = true;
|
||||||
|
inMSSection = false;
|
||||||
|
}
|
||||||
|
else if (_schoolLevel.Value == SchoolLevel.HighSchool &&
|
||||||
|
schoolLevel.Equals("MS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
shouldSkip = true;
|
||||||
|
result.SkippedMSSectionHeaders.Add(normalizedLine);
|
||||||
|
inMSSection = true;
|
||||||
|
inHSSection = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No school level set - backward compatibility: skip HS events
|
||||||
|
if (schoolLevel.Equals("HS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
shouldSkip = true;
|
||||||
|
result.SkippedHSSectionHeaders.Add(normalizedLine);
|
||||||
|
inHSSection = true;
|
||||||
|
inMSSection = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSkip)
|
||||||
{
|
{
|
||||||
result.SkippedHSSectionHeaders.Add(normalizedLine);
|
|
||||||
currentEventDefinition = null; // Skip subsequent occurrences
|
currentEventDefinition = null; // Skip subsequent occurrences
|
||||||
inHSSection = true; // Mark that we're in an HS section
|
|
||||||
continue; // No issue created
|
continue; // No issue created
|
||||||
}
|
}
|
||||||
|
|
||||||
// For MS events, use fuzzy matching to find the best matching event definition
|
// Reset section flags for events we're processing
|
||||||
|
if (schoolLevel.Equals("MS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
inMSSection = true;
|
||||||
|
inHSSection = false;
|
||||||
|
}
|
||||||
|
else if (schoolLevel.Equals("HS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
inHSSection = true;
|
||||||
|
inMSSection = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inHSSection = false;
|
||||||
|
inMSSection = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use fuzzy matching to find the best matching event definition
|
||||||
var evt = EventOccurrenceParsers.SectionHeaderMatcher.MatchEventDefinition(eventNamePart, _events);
|
var evt = EventOccurrenceParsers.SectionHeaderMatcher.MatchEventDefinition(eventNamePart, _events);
|
||||||
if (evt == null)
|
if (evt == null)
|
||||||
{
|
{
|
||||||
// For unmatched MS headers, create issue
|
// For unmatched headers, create issue
|
||||||
var bestRatio = EventOccurrenceParsers.SectionHeaderMatcher.GetBestMatchRatio(eventNamePart, _events);
|
var bestRatio = EventOccurrenceParsers.SectionHeaderMatcher.GetBestMatchRatio(eventNamePart, _events);
|
||||||
issues.Add(new ParsingIssue
|
issues.Add(new ParsingIssue
|
||||||
{
|
{
|
||||||
@@ -100,7 +156,6 @@ public class EventOccurrenceParser
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
currentEventDefinition = evt;
|
currentEventDefinition = evt;
|
||||||
inHSSection = false; // Reset HS section flag for MS events
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +164,8 @@ public class EventOccurrenceParser
|
|||||||
{
|
{
|
||||||
// General schedule breaks continuation mode
|
// General schedule breaks continuation mode
|
||||||
inContinuationMode = false;
|
inContinuationMode = false;
|
||||||
inHSSection = false; // Reset HS section flag
|
inHSSection = false; // Reset section flags
|
||||||
|
inMSSection = false;
|
||||||
currentEventDefinition = EventDefinition.GeneralSchedule;
|
currentEventDefinition = EventDefinition.GeneralSchedule;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -120,21 +176,68 @@ public class EventOccurrenceParser
|
|||||||
// Section headers break continuation mode
|
// Section headers break continuation mode
|
||||||
inContinuationMode = false;
|
inContinuationMode = false;
|
||||||
|
|
||||||
// Check if this is an HS event - if so, skip gracefully regardless of whether it matches
|
// Determine if we should skip this event based on chapter's school level setting
|
||||||
// This prevents HS events from being incorrectly associated with MS events
|
bool shouldSkip = false;
|
||||||
if (normalizedLine.Contains("HS", StringComparison.OrdinalIgnoreCase))
|
if (_schoolLevel.HasValue)
|
||||||
|
{
|
||||||
|
// School level is set - filter based on it
|
||||||
|
if (_schoolLevel.Value == SchoolLevel.MiddleSchool &&
|
||||||
|
normalizedLine.Contains("HS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
shouldSkip = true;
|
||||||
|
result.SkippedHSSectionHeaders.Add(normalizedLine);
|
||||||
|
inHSSection = true;
|
||||||
|
inMSSection = false;
|
||||||
|
}
|
||||||
|
else if (_schoolLevel.Value == SchoolLevel.HighSchool &&
|
||||||
|
normalizedLine.Contains("MS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
shouldSkip = true;
|
||||||
|
result.SkippedMSSectionHeaders.Add(normalizedLine);
|
||||||
|
inMSSection = true;
|
||||||
|
inHSSection = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No school level set - backward compatibility: skip HS events
|
||||||
|
if (normalizedLine.Contains("HS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
shouldSkip = true;
|
||||||
|
result.SkippedHSSectionHeaders.Add(normalizedLine);
|
||||||
|
inHSSection = true;
|
||||||
|
inMSSection = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSkip)
|
||||||
{
|
{
|
||||||
result.SkippedHSSectionHeaders.Add(normalizedLine);
|
|
||||||
currentEventDefinition = null; // Skip subsequent occurrences
|
currentEventDefinition = null; // Skip subsequent occurrences
|
||||||
inHSSection = true; // Mark that we're in an HS section
|
|
||||||
continue; // No issue created
|
continue; // No issue created
|
||||||
}
|
}
|
||||||
|
|
||||||
// For MS events, use fuzzy matching to find the best matching event definition
|
// Reset section flags for events we're processing
|
||||||
|
if (normalizedLine.Contains("MS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
inMSSection = true;
|
||||||
|
inHSSection = false;
|
||||||
|
}
|
||||||
|
else if (normalizedLine.Contains("HS", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
inHSSection = true;
|
||||||
|
inMSSection = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inHSSection = false;
|
||||||
|
inMSSection = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use fuzzy matching to find the best matching event definition
|
||||||
var evt = EventOccurrenceParsers.SectionHeaderMatcher.MatchEventDefinition(normalizedLine, _events);
|
var evt = EventOccurrenceParsers.SectionHeaderMatcher.MatchEventDefinition(normalizedLine, _events);
|
||||||
if (evt == null)
|
if (evt == null)
|
||||||
{
|
{
|
||||||
// For unmatched MS headers, create issue
|
// For unmatched headers, create issue
|
||||||
var bestRatio = EventOccurrenceParsers.SectionHeaderMatcher.GetBestMatchRatio(normalizedLine, _events);
|
var bestRatio = EventOccurrenceParsers.SectionHeaderMatcher.GetBestMatchRatio(normalizedLine, _events);
|
||||||
issues.Add(new ParsingIssue
|
issues.Add(new ParsingIssue
|
||||||
{
|
{
|
||||||
@@ -146,7 +249,6 @@ public class EventOccurrenceParser
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
currentEventDefinition = evt;
|
currentEventDefinition = evt;
|
||||||
inHSSection = false; // Reset HS section flag for MS events
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,10 +282,28 @@ public class EventOccurrenceParser
|
|||||||
// Occurrence lines break continuation mode
|
// Occurrence lines break continuation mode
|
||||||
inContinuationMode = false;
|
inContinuationMode = false;
|
||||||
|
|
||||||
// Skip occurrences under HS sections (they won't match any event definition)
|
// Skip occurrences under sections that don't match the school level setting
|
||||||
if (inHSSection)
|
if (_schoolLevel.HasValue)
|
||||||
{
|
{
|
||||||
continue;
|
if (_schoolLevel.Value == SchoolLevel.MiddleSchool && inHSSection)
|
||||||
|
{
|
||||||
|
result.SkippedHSEventCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (_schoolLevel.Value == SchoolLevel.HighSchool && inMSSection)
|
||||||
|
{
|
||||||
|
result.SkippedMSEventCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If no school level is set, skip HS sections (backward compatibility)
|
||||||
|
if (inHSSection)
|
||||||
|
{
|
||||||
|
result.SkippedHSEventCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (occurrenceName, month, dayOfMonthStr, timeAndLocation) = occurrenceLine.Value;
|
var (occurrenceName, month, dayOfMonthStr, timeAndLocation) = occurrenceLine.Value;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Core.Entities;
|
|||||||
using Core.Models;
|
using Core.Models;
|
||||||
using Core.Parsers;
|
using Core.Parsers;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using SchoolLevel = Core.Models.SchoolLevel;
|
||||||
|
|
||||||
namespace Core.Services;
|
namespace Core.Services;
|
||||||
|
|
||||||
@@ -13,9 +14,11 @@ namespace Core.Services;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class EventOccurrenceParserService : IEventOccurrenceParserService
|
public class EventOccurrenceParserService : IEventOccurrenceParserService
|
||||||
{
|
{
|
||||||
|
private readonly IConfiguration? _configuration;
|
||||||
|
|
||||||
public EventOccurrenceParserService(IConfiguration? configuration = null)
|
public EventOccurrenceParserService(IConfiguration? configuration = null)
|
||||||
{
|
{
|
||||||
// Configuration parameter kept for backward compatibility but not used
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -38,8 +41,22 @@ public class EventOccurrenceParserService : IEventOccurrenceParserService
|
|||||||
File.WriteAllText(tempFile, text, Encoding.UTF8);
|
File.WriteAllText(tempFile, text, Encoding.UTF8);
|
||||||
var fileInfo = new FileInfo(tempFile);
|
var fileInfo = new FileInfo(tempFile);
|
||||||
|
|
||||||
// Use the existing EventOccurrenceParser
|
// Read SchoolLevel from configuration
|
||||||
var parser = new EventOccurrenceParser(fileInfo, events);
|
SchoolLevel? schoolLevel = null;
|
||||||
|
if (_configuration != null)
|
||||||
|
{
|
||||||
|
var schoolLevelStr = _configuration.GetSection("ChapterSettings:SchoolLevel").Get<string>();
|
||||||
|
if (!string.IsNullOrWhiteSpace(schoolLevelStr))
|
||||||
|
{
|
||||||
|
if (Enum.TryParse<SchoolLevel>(schoolLevelStr, ignoreCase: true, out var parsed))
|
||||||
|
{
|
||||||
|
schoolLevel = parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the existing EventOccurrenceParser with school level
|
||||||
|
var parser = new EventOccurrenceParser(fileInfo, events, schoolLevel);
|
||||||
var parserResult = parser.Parse();
|
var parserResult = parser.Parse();
|
||||||
|
|
||||||
// Copy occurrences from parser result
|
// Copy occurrences from parser result
|
||||||
@@ -92,8 +109,21 @@ public class EventOccurrenceParserService : IEventOccurrenceParserService
|
|||||||
// Copy parsing issues from parser result
|
// Copy parsing issues from parser result
|
||||||
result.Issues.AddRange(parserResult.Issues);
|
result.Issues.AddRange(parserResult.Issues);
|
||||||
|
|
||||||
// Copy skipped HS section headers from parser result
|
// Copy skipped section headers from parser result
|
||||||
result.SkippedHSSectionHeaders.AddRange(parserResult.SkippedHSSectionHeaders);
|
result.SkippedHSSectionHeaders.AddRange(parserResult.SkippedHSSectionHeaders);
|
||||||
|
result.SkippedMSSectionHeaders.AddRange(parserResult.SkippedMSSectionHeaders);
|
||||||
|
result.SkippedMSEventCount = parserResult.SkippedMSEventCount;
|
||||||
|
result.SkippedHSEventCount = parserResult.SkippedHSEventCount;
|
||||||
|
|
||||||
|
// Add informational messages about skipped events
|
||||||
|
if (parserResult.SkippedMSEventCount > 0)
|
||||||
|
{
|
||||||
|
result.Warnings.Add($"Skipped {parserResult.SkippedMSEventCount} Middle School (MS) event occurrence(s) based on school level setting");
|
||||||
|
}
|
||||||
|
if (parserResult.SkippedHSEventCount > 0)
|
||||||
|
{
|
||||||
|
result.Warnings.Add($"Skipped {parserResult.SkippedHSEventCount} High School (HS) event occurrence(s) based on school level setting");
|
||||||
|
}
|
||||||
|
|
||||||
// Validate locations and add warnings for problematic ones
|
// Validate locations and add warnings for problematic ones
|
||||||
ValidateLocations(result);
|
ValidateLocations(result);
|
||||||
|
|||||||
@@ -125,9 +125,50 @@
|
|||||||
{
|
{
|
||||||
<MudAlert Severity="Severity.Success" Dense="true">
|
<MudAlert Severity="Severity.Success" Dense="true">
|
||||||
Successfully parsed @_parseResult.TotalParsed occurrence(s) from @_parseResult.Occurrences.Count event definition(s)
|
Successfully parsed @_parseResult.TotalParsed occurrence(s) from @_parseResult.Occurrences.Count event definition(s)
|
||||||
|
@if (_parseResult.SkippedMSEventCount > 0 || _parseResult.SkippedHSEventCount > 0)
|
||||||
|
{
|
||||||
|
<text> (Skipped @(_parseResult.SkippedMSEventCount + _parseResult.SkippedHSEventCount) event occurrence(s) from other school level)</text>
|
||||||
|
}
|
||||||
</MudAlert>
|
</MudAlert>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@* Skipped Section Headers *@
|
||||||
|
@if ((_parseResult.SkippedMSSectionHeaders.Any() || _parseResult.SkippedHSSectionHeaders.Any()) && _parseResult.IsSuccess)
|
||||||
|
{
|
||||||
|
<MudExpansionPanels Elevation="0" Class="mt-2">
|
||||||
|
@if (_parseResult.SkippedMSSectionHeaders.Any())
|
||||||
|
{
|
||||||
|
<MudExpansionPanel Text="@($"Skipped MS Section Headers ({_parseResult.SkippedMSSectionHeaders.Count})")"
|
||||||
|
Icon="@Icons.Material.Filled.Info"
|
||||||
|
iconcolor="Color.Info">
|
||||||
|
<MudList T="string">
|
||||||
|
@foreach (var header in _parseResult.SkippedMSSectionHeaders)
|
||||||
|
{
|
||||||
|
<MudListItem T="string">
|
||||||
|
<MudText>@header</MudText>
|
||||||
|
</MudListItem>
|
||||||
|
}
|
||||||
|
</MudList>
|
||||||
|
</MudExpansionPanel>
|
||||||
|
}
|
||||||
|
@if (_parseResult.SkippedHSSectionHeaders.Any())
|
||||||
|
{
|
||||||
|
<MudExpansionPanel Text="@($"Skipped HS Section Headers ({_parseResult.SkippedHSSectionHeaders.Count})")"
|
||||||
|
Icon="@Icons.Material.Filled.Info"
|
||||||
|
iconcolor="Color.Info">
|
||||||
|
<MudList T="string">
|
||||||
|
@foreach (var header in _parseResult.SkippedHSSectionHeaders)
|
||||||
|
{
|
||||||
|
<MudListItem T="string">
|
||||||
|
<MudText>@header</MudText>
|
||||||
|
</MudListItem>
|
||||||
|
}
|
||||||
|
</MudList>
|
||||||
|
</MudExpansionPanel>
|
||||||
|
}
|
||||||
|
</MudExpansionPanels>
|
||||||
|
}
|
||||||
|
|
||||||
@* Locations Summary *@
|
@* Locations Summary *@
|
||||||
@if (_parseResult.IsSuccess && _parseResult.Occurrences.Any())
|
@if (_parseResult.IsSuccess && _parseResult.Occurrences.Any())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
@using WebApp.Models
|
@using WebApp.Models
|
||||||
@using WebApp.Components.Shared.Components
|
@using WebApp.Components.Shared.Components
|
||||||
@using System.Text.Json
|
@using System.Text.Json
|
||||||
|
@using Core.Models
|
||||||
@inject IWebHostEnvironment Environment
|
@inject IWebHostEnvironment Environment
|
||||||
@inject IConfiguration Configuration
|
@inject IConfiguration Configuration
|
||||||
|
|
||||||
@@ -43,6 +44,16 @@
|
|||||||
MaxLength="4"
|
MaxLength="4"
|
||||||
Required="true" />
|
Required="true" />
|
||||||
</MudItem>
|
</MudItem>
|
||||||
|
<MudItem xs="12" md="6">
|
||||||
|
<MudSelect T="SchoolLevel?" @bind-Value="_settings.SchoolLevel"
|
||||||
|
Label="School Level"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
HelperText="Filter event occurrences by school level (leave empty to import both MS and HS)">
|
||||||
|
<MudSelectItem T="SchoolLevel?" Value="null">Both (MS and HS)</MudSelectItem>
|
||||||
|
<MudSelectItem T="SchoolLevel?" Value="@SchoolLevel.MiddleSchool">Middle School (MS)</MudSelectItem>
|
||||||
|
<MudSelectItem T="SchoolLevel?" Value="@SchoolLevel.HighSchool">High School (HS)</MudSelectItem>
|
||||||
|
</MudSelect>
|
||||||
|
</MudItem>
|
||||||
</MudGrid>
|
</MudGrid>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using Core.Models;
|
||||||
|
|
||||||
namespace WebApp.Models;
|
namespace WebApp.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -34,4 +36,9 @@ public class ChapterSettings
|
|||||||
/// Competition year (e.g., "2026")
|
/// Competition year (e.g., "2026")
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string CompetitionYear { get; set; } = "2026";
|
public string CompetitionYear { get; set; } = "2026";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// School level for the chapter (null = import both MS and HS events)
|
||||||
|
/// </summary>
|
||||||
|
public SchoolLevel? SchoolLevel { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user