diff options
-rw-r--r-- | src/SMAPI.Web/Framework/LogParsing/LogParser.cs | 18 | ||||
-rw-r--r-- | src/SMAPI.Web/Framework/LogParsing/Models/LogMessage.cs | 6 | ||||
-rw-r--r-- | src/SMAPI.Web/Framework/LogParsing/Models/LogSection.cs | 15 | ||||
-rw-r--r-- | src/SMAPI.Web/Views/LogParser/Index.cshtml | 25 | ||||
-rw-r--r-- | src/SMAPI.Web/wwwroot/Content/css/log-parser.css | 13 | ||||
-rw-r--r-- | src/SMAPI.Web/wwwroot/Content/js/log-parser.js | 11 |
6 files changed, 84 insertions, 4 deletions
diff --git a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs index fdc19404..3f33c0c1 100644 --- a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs +++ b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs @@ -119,7 +119,11 @@ namespace StardewModdingAPI.Web.Framework.LogParsing // mod list if (!inModList && message.Level == LogLevel.Info && this.ModListStartPattern.IsMatch(message.Text)) + { inModList = true; + message.IsStartOfSection = true; + message.Section = LogSection.ModsList; + } else if (inModList) { Match match = this.ModListEntryPattern.Match(message.Text); @@ -128,11 +132,17 @@ namespace StardewModdingAPI.Web.Framework.LogParsing string author = match.Groups["author"].Value; string description = match.Groups["description"].Value; mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, Loaded = true }; + + message.Section = LogSection.ModsList; } // content pack list else if (!inContentPackList && message.Level == LogLevel.Info && this.ContentPackListStartPattern.IsMatch(message.Text)) + { inContentPackList = true; + message.IsStartOfSection = true; + message.Section = LogSection.ContentPackList; + } else if (inContentPackList) { Match match = this.ContentPackListEntryPattern.Match(message.Text); @@ -142,11 +152,17 @@ namespace StardewModdingAPI.Web.Framework.LogParsing string description = match.Groups["description"].Value; string forMod = match.Groups["for"].Value; mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, ContentPackFor = forMod, Loaded = true }; + + message.Section = LogSection.ContentPackList; } // mod update list else if (!inModUpdateList && message.Level == LogLevel.Alert && this.ModUpdateListStartPattern.IsMatch(message.Text)) + { inModUpdateList = true; + message.IsStartOfSection = true; + message.Section = LogSection.ModUpdateList; + } else if (inModUpdateList) { Match match = this.ModUpdateListEntryPattern.Match(message.Text); @@ -162,6 +178,8 @@ namespace StardewModdingAPI.Web.Framework.LogParsing { mods[name] = new LogModInfo { Name = name, UpdateVersion = version, UpdateLink = link, Loaded = false }; } + + message.Section = LogSection.ModUpdateList; } else if (message.Level == LogLevel.Alert && this.SMAPIUpdatePattern.IsMatch(message.Text)) diff --git a/src/SMAPI.Web/Framework/LogParsing/Models/LogMessage.cs b/src/SMAPI.Web/Framework/LogParsing/Models/LogMessage.cs index baeac83c..ecca0b5b 100644 --- a/src/SMAPI.Web/Framework/LogParsing/Models/LogMessage.cs +++ b/src/SMAPI.Web/Framework/LogParsing/Models/LogMessage.cs @@ -20,5 +20,11 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models /// <summary>The number of times this message was repeated consecutively.</summary> public int Repeated { get; set; } + + /// <summary>The section that this log message belongs too.</summary> + public LogSection? Section { get; set; } + + /// <summary>Whether this message is the first one of it's section.</summary> + public bool IsStartOfSection { get; set; } } } diff --git a/src/SMAPI.Web/Framework/LogParsing/Models/LogSection.cs b/src/SMAPI.Web/Framework/LogParsing/Models/LogSection.cs new file mode 100644 index 00000000..218d546c --- /dev/null +++ b/src/SMAPI.Web/Framework/LogParsing/Models/LogSection.cs @@ -0,0 +1,15 @@ +namespace StardewModdingAPI.Web.Framework.LogParsing.Models +{ + /// <summary>The different sections of a log.</summary> + public enum LogSection + { + /// <summary>The list of mods the user has.</summary> + ModsList, + + /// <summary>The list of content packs the user has.</summary> + ContentPackList, + + /// <summary>The list of mod updates SMAPI has found.</summary> + ModUpdateList + } +} diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index 21adf35b..aa37fef2 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -27,6 +27,7 @@ logStarted: new Date(@Json.Serialize(Model.ParsedLog?.Timestamp)), showPopup: @Json.Serialize(Model.ParsedLog == null), showMods: @Json.Serialize(Model.ParsedLog?.Mods?.Select(p => Model.GetSlug(p.Name)).Distinct().ToDictionary(slug => slug, slug => true), noFormatting), + showSections: @Json.Serialize(Enum.GetNames(typeof(LogSection)).ToDictionary(section => section, section => false), noFormatting), showLevels: @Json.Serialize(defaultFilters, noFormatting), enableFilters: @Json.Serialize(!Model.ShowRaw) }, '@Model.SectionUrl'); @@ -261,16 +262,34 @@ else if (Model.ParsedLog?.IsValid == true) @foreach (var message in Model.ParsedLog.Messages) { string levelStr = message.Level.ToString().ToLower(); + string sectionStartClass = message.IsStartOfSection ? "section-start" : null; - <tr class="@levelStr mod" v-show="filtersAllow('@Model.GetSlug(message.Mod)', '@levelStr')"> + // filter the message by section if it has one + string sectionFilter = message.Section != null ? $"&& sectionsAllow('{message.Section}')" : null; + // always show the first message in the section regardless of section filters + string sectionsAllow = message.IsStartOfSection ? null : sectionFilter; + + <tr class="@levelStr mod @sectionStartClass" + @if (message.IsStartOfSection) + { + <text>v-on:click="toggleSection('@message.Section')"</text> + } + v-show="filtersAllow('@Model.GetSlug(message.Mod)', '@levelStr') @sectionsAllow"> <td v-pre>@message.Time</td> <td v-pre>@message.Level.ToString().ToUpper()</td> <td v-pre data-title="@message.Mod">@message.Mod</td> - <td v-pre>@message.Text</td> + <td> + <span v-pre class="log-message-text">@message.Text</span> + @if (message.IsStartOfSection) + { + <span class="section-toggle-message" v-show="!sectionsAllow('@message.Section')">This section is hidden. Click here to show it.</span> + <span class="section-toggle-message" v-show="sectionsAllow('@message.Section')">This section is shown. Click here to hide it.</span> + } + </td> </tr> if (message.Repeated > 0) { - <tr class="@levelStr mod mod-repeat" v-show="filtersAllow('@Model.GetSlug(message.Mod)', '@levelStr')"> + <tr class="@levelStr mod mod-repeat" v-show="filtersAllow('@Model.GetSlug(message.Mod)', '@levelStr') @sectionsAllow"> <td colspan="3"></td> <td v-pre><i>repeats [@message.Repeated] times.</i></td> </tr> diff --git a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css index ea28cd7d..7610f12c 100644 --- a/src/SMAPI.Web/wwwroot/Content/css/log-parser.css +++ b/src/SMAPI.Web/wwwroot/Content/css/log-parser.css @@ -219,6 +219,18 @@ table caption { font-weight: bold; } +#log .section-start { + cursor: pointer; +} + +#log .section-toggle-message { + color: blue; +} + +#log .log-message-text { + white-space: pre-wrap; +} + #log { border-spacing: 0; } @@ -233,7 +245,6 @@ table caption { border-bottom: 1px dotted #ccc; border-top: 2px solid #fff; vertical-align: top; - white-space: pre-wrap; } #log td:not(:last-child) { diff --git a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js index 0c654205..e87a1a5c 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/log-parser.js +++ b/src/SMAPI.Web/wwwroot/Content/js/log-parser.js @@ -69,6 +69,13 @@ smapi.logParser = function (data, sectionUrl) { updateModFilters(); }, + toggleSection: function (name) { + if (!data.enableFilters) + return; + + this.showSections[name] = !this.showSections[name]; + }, + showAllMods: function () { if (!data.enableFilters) return; @@ -95,6 +102,10 @@ smapi.logParser = function (data, sectionUrl) { filtersAllow: function(modId, level) { return this.showMods[modId] !== false && this.showLevels[level] !== false; + }, + + sectionsAllow: function (section) { + return this.showSections[section] !== false; } } }); |