add update info in suggested fixes section

This commit is contained in:
danvolchek 2019-02-17 20:39:36 -06:00 committed by Jesse Plamondon-Willard
parent 4baad0ec8d
commit a23261106e
No known key found for this signature in database
GPG Key ID: 7D7C8097B62033CE
4 changed files with 138 additions and 17 deletions

View File

@ -39,6 +39,15 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
/// <summary>A regex pattern matching an entry in SMAPI's content pack list.</summary>
private readonly Regex ContentPackListEntryPattern = new Regex(@"^ (?<name>.+) (?<version>.+) by (?<author>.+) \| for (?<for>.+?)(?: \| (?<description>.+))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>A regex pattern matching the start of SMAPI's mod update list.</summary>
private readonly Regex ModUpdateListStartPattern = new Regex(@"^You can update \d+ mods?:$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>A regex pattern matching an entry in SMAPI's mod update list.</summary>
private readonly Regex ModUpdateListEntryPattern = new Regex(@"^ (?<name>.+?) (?<version>" + SemanticVersion.UnboundedVersionPattern + @"): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>A regex pattern matching SMAPI's update line.</summary>
private readonly Regex SMAPIUpdatePattern = new Regex(@"^You can update SMAPI to (?<version>" + SemanticVersion.UnboundedVersionPattern + @"): (?<link>.+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/*********
** Public methods
@ -69,11 +78,12 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
};
// parse log messages
LogModInfo smapiMod = new LogModInfo { Name = "SMAPI", Author = "Pathoschild", Description = "" };
LogModInfo gameMod = new LogModInfo { Name = "game", Author = "", Description = "" };
LogModInfo smapiMod = new LogModInfo { Name = "SMAPI", Author = "Pathoschild", Description = "", Loaded = true};
LogModInfo gameMod = new LogModInfo { Name = "game", Author = "", Description = "", Loaded = true };
IDictionary<string, LogModInfo> mods = new Dictionary<string, LogModInfo>();
bool inModList = false;
bool inContentPackList = false;
bool inModUpdateList = false;
foreach (LogMessage message in log.Messages)
{
// collect stats
@ -106,6 +116,8 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
inModList = false;
if (inContentPackList && !this.ContentPackListEntryPattern.IsMatch(message.Text))
inContentPackList = false;
if (inModUpdateList && !this.ModUpdateListEntryPattern.IsMatch(message.Text))
inModUpdateList = false;
// mod list
if (!inModList && message.Level == LogLevel.Info && this.ModListStartPattern.IsMatch(message.Text))
@ -117,7 +129,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
string version = match.Groups["version"].Value;
string author = match.Groups["author"].Value;
string description = match.Groups["description"].Value;
mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description };
mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, Loaded = true };
}
// content pack list
@ -131,7 +143,36 @@ namespace StardewModdingAPI.Web.Framework.LogParsing
string author = match.Groups["author"].Value;
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 };
mods[name] = new LogModInfo { Name = name, Author = author, Version = version, Description = description, ContentPackFor = forMod, Loaded = true };
}
// mod update list
else if (!inModUpdateList && message.Level == LogLevel.Alert && this.ModUpdateListStartPattern.IsMatch(message.Text))
inModUpdateList = true;
else if (inModUpdateList)
{
Match match = this.ModUpdateListEntryPattern.Match(message.Text);
string name = match.Groups["name"].Value;
string version = match.Groups["version"].Value;
string link = match.Groups["link"].Value;
if (mods.ContainsKey(name))
{
mods[name].UpdateLink = link;
mods[name].UpdateVersion = version;
}
else
{
mods[name] = new LogModInfo {Name = name, UpdateVersion = version, UpdateLink = link, Loaded = false};
}
}
else if(message.Level == LogLevel.Alert && this.SMAPIUpdatePattern.IsMatch(message.Text))
{
Match match = this.SMAPIUpdatePattern.Match(message.Text);
string version = match.Groups["version"].Value;
string link = match.Groups["link"].Value;
smapiMod.UpdateVersion = version;
smapiMod.UpdateLink = link;
}
// platform info line

View File

@ -12,6 +12,12 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
/// <summary>The mod author.</summary>
public string Author { get; set; }
/// <summary>The update version.</summary>
public string UpdateVersion { get; set; }
/// <summary>The update link.</summary>
public string UpdateLink { get; set; }
/// <summary>The mod version.</summary>
public string Version { get; set; }
@ -23,5 +29,11 @@ namespace StardewModdingAPI.Web.Framework.LogParsing.Models
/// <summary>The number of errors logged by this mod.</summary>
public int Errors { get; set; }
/// <summary>Whether the mod was loaded into the game.</summary>
public bool Loaded { get; set; }
/// <summary>Whether the mod has an update available.</summary>
public bool HasUpdate => this.UpdateVersion != null && this.Version != this.UpdateVersion;
}
}

View File

@ -117,9 +117,60 @@ else if (Model.ParsedLog?.IsValid == true)
@* parsed log *@
@if (Model.ParsedLog?.IsValid == true)
{
<h2>Log info</h2>
<div id="output">
<table id="metadata">
@if (Model.ParsedLog.Mods.Any(mod => mod.HasUpdate))
{
<h2>Suggested fixes</h2>
<p>You have some mods that aren't fully up to date. Updating them can fix problems.</p>
<table id="updates" class="table">
<caption>
Updates Available:
</caption>
@foreach (LogModInfo mod in Model.ParsedLog.Mods.Where(mod => (mod.HasUpdate && mod.ContentPackFor == null) || (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList) && contentPackList.Any(pack => pack.HasUpdate))))
{
<tr class="mod-entry">
<td>
<strong class=@(!mod.HasUpdate ? "hidden": "")>@mod.Name</strong>
@if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList))
{
<div class="content-packs">
@foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
{
<text>+ @contentPack.Name</text><br />
}
</div>
}
</td>
<td>
@if (mod.HasUpdate)
{
<a href="@mod.UpdateLink" target="_blank">
@(mod.Version == null ? @mod.UpdateVersion : $"{mod.Version} → {mod.UpdateVersion}")
</a>
}
else
{
<span class="invisible">Okay</span>
}
@if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out contentPackList))
{
<div>
@foreach (LogModInfo contentPack in contentPackList.Where(pack => pack.HasUpdate))
{
<a href="@contentPack.UpdateLink" target="_blank">@contentPack.Version → @contentPack.UpdateVersion</a><br />
}
</div>
}
</td>
</tr>
}
</table>
}
<h2>Log info</h2>
<table id="metadata" class="table">
<caption>Game info:</caption>
<tr>
<th>Stardew Valley:</th>
@ -138,8 +189,8 @@ else if (Model.ParsedLog?.IsValid == true)
<td>@Model.ParsedLog.Timestamp.UtcDateTime.ToString("yyyy-MM-dd HH:mm") UTC ({{localTimeStarted}} your time)</td>
</tr>
</table>
<br />
<table id="mods" class="@(Model.ShowRaw ? "filters-disabled" : null)">
<br/>
<table id="mods" class="@(Model.ShowRaw ? "filters-disabled" : null) table">
<caption>
Installed mods:
@if (!Model.ShowRaw)
@ -149,7 +200,7 @@ else if (Model.ParsedLog?.IsValid == true)
<span class="notice btn txt" v-on:click="hideAllMods" v-bind:class="{ invisible: !anyModsShown || !anyModsHidden }">hide all</span>
}
</caption>
@foreach (var mod in Model.ParsedLog.Mods.Where(p => p.ContentPackFor == null))
@foreach (var mod in Model.ParsedLog.Mods.Where(p => p.Loaded && p.ContentPackFor == null))
{
<tr v-on:click="toggleMod('@Model.GetSlug(mod.Name)')" class="mod-entry" v-bind:class="{ hidden: !showMods['@Model.GetSlug(mod.Name)'] }">
<td><input type="checkbox" v-bind:checked="showMods['@Model.GetSlug(mod.Name)']" v-bind:class="{ invisible: !anyModsHidden }" /></td>

View File

@ -13,6 +13,13 @@ caption {
#output {
padding: 10px;
overflow: auto;
}
#output h2 {
margin: -10px 0 10px -10px;
}
#output table {
font-family: monospace;
}
@ -43,7 +50,7 @@ table caption {
/*********
** Log metadata & filters
*********/
#metadata, #mods, #filters {
.table, #filters {
border-bottom: 1px dashed #888888;
margin-bottom: 5px;
}
@ -53,7 +60,7 @@ table caption {
padding-right: 0.7em;
}
table#metadata, table#mods {
.table {
border: 1px solid #000000;
background: #ffffff;
border-radius: 5px;
@ -63,6 +70,18 @@ table#metadata, table#mods {
box-shadow: 1px 1px 1px 1px #dddddd;
}
.mod-entry {
height: 1.8em;
}
.table > caption {
min-height: 1.3em;
}
#updates {
min-width: 10em;
}
.invisible {
visibility: hidden;
}
@ -87,8 +106,7 @@ table#metadata, table#mods {
cursor: default;
}
#metadata tr,
#mods tr {
.table tr {
background: #eee
}
@ -114,11 +132,11 @@ table#metadata, table#mods {
display: inline-block;
}
#mods .mod-entry.hidden {
.table .hidden {
opacity: 0.5;
}
#mods .content-packs {
.table .content-packs {
margin-left: 1em;
font-size: 0.9em;
font-style: italic;
@ -128,8 +146,7 @@ table#metadata, table#mods {
padding-right: 5px;
}
#metadata tr:nth-child(even),
#mods tr:nth-child(even) {
.table tr:nth-child(even) {
background: #fff
}