summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/LogParser.cs18
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/Models/LogMessage.cs6
-rw-r--r--src/SMAPI.Web/Framework/LogParsing/Models/LogSection.cs15
-rw-r--r--src/SMAPI.Web/Views/LogParser/Index.cshtml25
-rw-r--r--src/SMAPI.Web/wwwroot/Content/css/log-parser.css13
-rw-r--r--src/SMAPI.Web/wwwroot/Content/js/log-parser.js11
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;
}
}
});