Add Xbox to front page; Bulk add

refactor-intermediate-models
Thomas Hounsell 2017-01-22 22:50:19 +00:00
parent c3cdb064de
commit 813aa09205
15 changed files with 442 additions and 306 deletions

View File

@ -123,6 +123,15 @@ namespace BuildFeed.Local {
}
}
/// <summary>
/// Looks up a localized string similar to Add bulk.
/// </summary>
public static string Common_AddBulk {
get {
return ResourceManager.GetString("Common_AddBulk", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Admin.
/// </summary>
@ -339,6 +348,15 @@ namespace BuildFeed.Local {
}
}
/// <summary>
/// Looks up a localized string similar to Current Xbox.
/// </summary>
public static string Front_CurrentXbox {
get {
return ResourceManager.GetString("Front_CurrentXbox", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Delete.
/// </summary>

View File

@ -138,6 +138,9 @@
<data name="Common_AddBuild" xml:space="preserve">
<value>Add build</value>
</data>
<data name="Common_AddBulk" xml:space="preserve">
<value>Add bulk</value>
</data>
<data name="Common_Admin" xml:space="preserve">
<value>Admin</value>
</data>
@ -210,6 +213,9 @@
<data name="Front_CurrentRelease" xml:space="preserve">
<value>Current Release</value>
</data>
<data name="Front_CurrentXbox" xml:space="preserve">
<value>Current Xbox</value>
</data>
<data name="Front_Delete" xml:space="preserve">
<value>Delete</value>
</data>
@ -447,5 +453,4 @@
<data name="Support_Week" xml:space="preserve">
<value>Week</value>
</data>
</root>

View File

@ -105,6 +105,7 @@
<Compile Include="ProjectFamily.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TypeOfSource.cs" />
<Compile Include="View\AddBulk.cs" />
<Compile Include="View\ChangePassword.cs" />
<Compile Include="View\FrontBuildGroup.cs" />
<Compile Include="View\FrontPage.cs" />

View File

@ -10,293 +10,305 @@ using MongoDB.Driver;
namespace BuildFeed.Model
{
public partial class BuildRepository
{
private const string BUILD_COLLECTION_NAME = "builds";
private static readonly BsonDocument sortByAddedDate = new BsonDocument(nameof(Build.Added), -1);
private static readonly BsonDocument sortByCompileDate = new BsonDocument(nameof(Build.BuildTime), -1);
private static readonly BsonDocument sortByLeakedDate = new BsonDocument(nameof(Build.LeakDate), -1);
public partial class BuildRepository
{
private const string BUILD_COLLECTION_NAME = "builds";
private static readonly BsonDocument sortByAddedDate = new BsonDocument(nameof(Build.Added), -1);
private static readonly BsonDocument sortByCompileDate = new BsonDocument(nameof(Build.BuildTime), -1);
private static readonly BsonDocument sortByLeakedDate = new BsonDocument(nameof(Build.LeakDate), -1);
private static readonly BsonDocument sortByOrder = new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), -1),
new BsonElement(nameof(Build.MinorVersion), -1),
new BsonElement(nameof(Build.Number), -1),
new BsonElement(nameof(Build.Revision), -1),
new BsonElement(nameof(Build.BuildTime), -1)
};
private static readonly BsonDocument sortByOrder = new BsonDocument
{
new BsonElement(nameof(Build.MajorVersion), -1),
new BsonElement(nameof(Build.MinorVersion), -1),
new BsonElement(nameof(Build.Number), -1),
new BsonElement(nameof(Build.Revision), -1),
new BsonElement(nameof(Build.BuildTime), -1)
};
private readonly IMongoCollection<Build> _buildCollection;
private readonly IMongoCollection<Build> _buildCollection;
public BuildRepository()
{
MongoClientSettings settings = new MongoClientSettings
{
Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port)
};
if (!string.IsNullOrEmpty(MongoConfig.Username) && !string.IsNullOrEmpty(MongoConfig.Password))
{
settings.Credentials = new List<MongoCredential>
public BuildRepository()
{
MongoClientSettings settings = new MongoClientSettings
{
MongoCredential.CreateCredential(MongoConfig.Database, MongoConfig.Username, MongoConfig.Password)
Server = new MongoServerAddress(MongoConfig.Host, MongoConfig.Port)
};
}
MongoClient dbClient = new MongoClient(settings);
IMongoDatabase buildDatabase = dbClient.GetDatabase(MongoConfig.Database);
_buildCollection = buildDatabase.GetCollection<Build>(BUILD_COLLECTION_NAME);
}
public async Task SetupIndexes()
{
List<BsonDocument> indexes = await (await _buildCollection.Indexes.ListAsync()).ToListAsync();
if (indexes.All(i => i["name"] != "_idx_group"))
{
await
_buildCollection.Indexes.CreateOneAsync(
Builders<Build>.IndexKeys.Combine(Builders<Build>.IndexKeys.Descending(b => b.MajorVersion),
Builders<Build>.IndexKeys.Descending(b => b.MinorVersion),
Builders<Build>.IndexKeys.Descending(b => b.Number),
Builders<Build>.IndexKeys.Descending(b => b.Revision)),
new CreateIndexOptions
{
Name = "_idx_group"
});
}
if (indexes.All(i => i["name"] != "_idx_legacy"))
{
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Ascending(b => b.LegacyId),
new CreateIndexOptions
{
Name = "_idx_legacy"
});
}
if (indexes.All(i => i["name"] != "_idx_lab"))
{
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Ascending(b => b.Lab),
new CreateIndexOptions
{
Name = "_idx_lab"
});
}
if (indexes.All(i => i["name"] != "_idx_date"))
{
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Descending(b => b.BuildTime),
new CreateIndexOptions
{
Name = "_idx_date"
});
}
if (indexes.All(i => i["name"] != "_idx_bstr"))
{
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Ascending(b => b.FullBuildString),
new CreateIndexOptions
{
Name = "_idx_bstr"
});
}
if (indexes.All(i => i["name"] != "_idx_alt_bstr"))
{
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Ascending(b => b.AlternateBuildString),
new CreateIndexOptions
{
Name = "_idx_alt_bstr"
});
}
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<Build>> Select() => await _buildCollection.Find(new BsonDocument()).ToListAsync();
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<Build> SelectById(Guid id) => await _buildCollection.Find(Builders<Build>.Filter.Eq(b => b.Id, id)).SingleOrDefaultAsync();
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<Build> SelectByLegacyId(long id) => await _buildCollection.Find(Builders<Build>.Filter.Eq(b => b.LegacyId, id)).SingleOrDefaultAsync();
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByOrder(int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument()).Sort(sortByOrder).Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<FrontPage> SelectFrontPage()
{
FrontPage fp = new FrontPage();
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument
{
if (!string.IsNullOrEmpty(MongoConfig.Username) && !string.IsNullOrEmpty(MongoConfig.Password))
{
nameof(Build.LabUrl), new BsonDocument
{
{"$in", new BsonArray(ConfigurationManager.AppSettings["site:OSGLab"].Split(';'))}
}
settings.Credentials = new List<MongoCredential>
{
MongoCredential.CreateCredential(MongoConfig.Database, MongoConfig.Username, MongoConfig.Password)
};
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentCanary = await query.FirstOrDefaultAsync();
query = _buildCollection.Find(new BsonDocument
{
MongoClient dbClient = new MongoClient(settings);
IMongoDatabase buildDatabase = dbClient.GetDatabase(MongoConfig.Database);
_buildCollection = buildDatabase.GetCollection<Build>(BUILD_COLLECTION_NAME);
}
public async Task SetupIndexes()
{
List<BsonDocument> indexes = await (await _buildCollection.Indexes.ListAsync()).ToListAsync();
if (indexes.All(i => i["name"] != "_idx_group"))
{
nameof(Build.LabUrl), new BsonDocument
{
{"$in", new BsonArray(ConfigurationManager.AppSettings["site:InsiderLab"].Split(';'))}
}
},
{
nameof(Build.SourceType), new BsonDocument
{
{
"$in", new BsonArray
{
TypeOfSource.PublicRelease,
TypeOfSource.UpdateGDR
}
}
}
await
_buildCollection.Indexes.CreateOneAsync(
Builders<Build>.IndexKeys.Combine(Builders<Build>.IndexKeys.Descending(b => b.MajorVersion),
Builders<Build>.IndexKeys.Descending(b => b.MinorVersion),
Builders<Build>.IndexKeys.Descending(b => b.Number),
Builders<Build>.IndexKeys.Descending(b => b.Revision)),
new CreateIndexOptions
{
Name = "_idx_group"
});
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentInsider = await query.FirstOrDefaultAsync();
query = _buildCollection.Find(new BsonDocument
{
if (indexes.All(i => i["name"] != "_idx_legacy"))
{
nameof(Build.LabUrl), new BsonDocument
{
{"$in", new BsonArray(ConfigurationManager.AppSettings["site:ReleaseLab"].Split(';'))}
}
},
{
nameof(Build.SourceType), new BsonDocument
{
{
"$in", new BsonArray
{
TypeOfSource.PublicRelease,
TypeOfSource.UpdateGDR
}
}
}
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Ascending(b => b.LegacyId),
new CreateIndexOptions
{
Name = "_idx_legacy"
});
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentRelease = await query.FirstOrDefaultAsync();
return fp;
}
if (indexes.All(i => i["name"] != "_idx_lab"))
{
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Ascending(b => b.Lab),
new CreateIndexOptions
{
Name = "_idx_lab"
});
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByStringSearch(string term, int limit = -1)
{
IAggregateFluent<Build> query = _buildCollection.Aggregate().Match(b => b.FullBuildString != null).Match(b => b.FullBuildString != "").Match(b => b.FullBuildString.ToLower().Contains(term.ToLower()));
if (indexes.All(i => i["name"] != "_idx_date"))
{
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Descending(b => b.BuildTime),
new CreateIndexOptions
{
Name = "_idx_date"
});
}
if (limit > 0)
{
query = query.Limit(limit);
}
if (indexes.All(i => i["name"] != "_idx_bstr"))
{
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Ascending(b => b.FullBuildString),
new CreateIndexOptions
{
Name = "_idx_bstr"
});
}
return await query.ToListAsync();
}
if (indexes.All(i => i["name"] != "_idx_alt_bstr"))
{
await _buildCollection.Indexes.CreateOneAsync(Builders<Build>.IndexKeys.Ascending(b => b.AlternateBuildString),
new CreateIndexOptions
{
Name = "_idx_alt_bstr"
});
}
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByCompileDate(int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument()).Sort(sortByCompileDate).Skip(skip);
[DataObjectMethod(DataObjectMethodType.Select, true)]
public async Task<List<Build>> Select() => await _buildCollection.Find(new BsonDocument()).ToListAsync();
if (limit > 0)
{
query = query.Limit(limit);
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<Build> SelectById(Guid id) => await _buildCollection.Find(Builders<Build>.Filter.Eq(b => b.Id, id)).SingleOrDefaultAsync();
return await query.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<Build> SelectByLegacyId(long id) => await _buildCollection.Find(Builders<Build>.Filter.Eq(b => b.LegacyId, id)).SingleOrDefaultAsync();
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByAddedDate(int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument()).Sort(sortByAddedDate).Skip(skip);
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByOrder(int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument()).Sort(sortByOrder).Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
return await query.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByLeakedDate(int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument()).Sort(sortByLeakedDate).Skip(skip);
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<FrontPage> SelectFrontPage()
{
FrontPage fp = new FrontPage();
if (limit > 0)
{
query = query.Limit(limit);
}
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument
{
{
nameof(Build.LabUrl), new BsonDocument
{
{"$in", new BsonArray(ConfigurationManager.AppSettings["site:OSGLab"].Split(';'))}
}
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentCanary = await query.FirstOrDefaultAsync();
return await query.ToListAsync();
}
query = _buildCollection.Find(new BsonDocument
{
{
nameof(Build.LabUrl), new BsonDocument
{
{"$in", new BsonArray(ConfigurationManager.AppSettings["site:InsiderLab"].Split(';'))}
}
},
{
nameof(Build.SourceType), new BsonDocument
{
{
"$in", new BsonArray
{
TypeOfSource.PublicRelease,
TypeOfSource.UpdateGDR
}
}
}
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentInsider = await query.FirstOrDefaultAsync();
[DataObjectMethod(DataObjectMethodType.Insert, true)]
public async Task Insert(Build item)
{
item.Id = Guid.NewGuid();
item.LabUrl = item.GenerateLabUrl();
item.FullBuildString = item.GenerateFullBuildString();
item.AlternateBuildString = item.GenerateAlternateBuildString();
query = _buildCollection.Find(new BsonDocument
{
{
nameof(Build.LabUrl), new BsonDocument
{
{"$in", new BsonArray(ConfigurationManager.AppSettings["site:ReleaseLab"].Split(';'))}
}
},
{
nameof(Build.SourceType), new BsonDocument
{
{
"$in", new BsonArray
{
TypeOfSource.PublicRelease,
TypeOfSource.UpdateGDR
}
}
}
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentRelease = await query.FirstOrDefaultAsync();
await _buildCollection.InsertOneAsync(item);
}
[DataObjectMethod(DataObjectMethodType.Insert, false)]
public async Task InsertAll(IEnumerable<Build> items)
{
var generatedItems = new List<Build>();
foreach (Build item in items)
{
query = _buildCollection.Find(new BsonDocument
{
{
nameof(Build.LabUrl), new BsonDocument
{
{"$in", new BsonArray(ConfigurationManager.AppSettings["site:XboxLab"].Split(';'))}
}
}
}).Sort(sortByCompileDate).Limit(1);
fp.CurrentXbox = await query.FirstOrDefaultAsync();
return fp;
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByStringSearch(string term, int limit = -1)
{
IAggregateFluent<Build> query = _buildCollection.Aggregate().Match(b => b.FullBuildString != null).Match(b => b.FullBuildString != "").Match(b => b.FullBuildString.ToLower().Contains(term.ToLower()));
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByCompileDate(int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument()).Sort(sortByCompileDate).Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByAddedDate(int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument()).Sort(sortByAddedDate).Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Select, false)]
public async Task<List<Build>> SelectBuildsByLeakedDate(int limit = -1, int skip = 0)
{
IFindFluent<Build, Build> query = _buildCollection.Find(new BsonDocument()).Sort(sortByLeakedDate).Skip(skip);
if (limit > 0)
{
query = query.Limit(limit);
}
return await query.ToListAsync();
}
[DataObjectMethod(DataObjectMethodType.Insert, true)]
public async Task Insert(Build item)
{
item.Id = Guid.NewGuid();
item.LabUrl = item.GenerateLabUrl();
item.FullBuildString = item.GenerateFullBuildString();
item.AlternateBuildString = item.GenerateAlternateBuildString();
generatedItems.Add(item);
}
await _buildCollection.InsertOneAsync(item);
}
await _buildCollection.InsertManyAsync(generatedItems);
}
[DataObjectMethod(DataObjectMethodType.Insert, false)]
public async Task InsertAll(IEnumerable<Build> items)
{
var generatedItems = new List<Build>();
foreach (Build item in items)
{
item.Id = Guid.NewGuid();
item.LabUrl = item.GenerateLabUrl();
item.FullBuildString = item.GenerateFullBuildString();
item.AlternateBuildString = item.GenerateAlternateBuildString();
[DataObjectMethod(DataObjectMethodType.Update, true)]
public async Task Update(Build item)
{
Build old = await SelectById(item.Id);
item.Added = old.Added;
item.Modified = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc);
item.LabUrl = item.GenerateLabUrl();
item.FullBuildString = item.GenerateFullBuildString();
item.AlternateBuildString = item.GenerateAlternateBuildString();
generatedItems.Add(item);
}
await _buildCollection.ReplaceOneAsync(Builders<Build>.Filter.Eq(b => b.Id, item.Id), item);
}
await _buildCollection.InsertManyAsync(generatedItems);
}
[DataObjectMethod(DataObjectMethodType.Delete, true)]
public async Task DeleteById(Guid id)
{
await _buildCollection.DeleteOneAsync(Builders<Build>.Filter.Eq(b => b.Id, id));
}
}
[DataObjectMethod(DataObjectMethodType.Update, true)]
public async Task Update(Build item)
{
Build old = await SelectById(item.Id);
item.Added = old.Added;
item.Modified = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc);
item.LabUrl = item.GenerateLabUrl();
item.FullBuildString = item.GenerateFullBuildString();
item.AlternateBuildString = item.GenerateAlternateBuildString();
await _buildCollection.ReplaceOneAsync(Builders<Build>.Filter.Eq(b => b.Id, item.Id), item);
}
[DataObjectMethod(DataObjectMethodType.Delete, true)]
public async Task DeleteById(Guid id)
{
await _buildCollection.DeleteOneAsync(Builders<Build>.Filter.Eq(b => b.Id, id));
}
}
}

View File

@ -0,0 +1,9 @@
namespace BuildFeed.Model.View
{
public class AddBulk
{
public string Builds { get; set; }
public bool SendNotifications { get; set; }
}
}

View File

@ -1,9 +1,10 @@
namespace BuildFeed.Model.View
{
public class FrontPage
{
public Build CurrentCanary { get; set; }
public Build CurrentInsider { get; set; }
public Build CurrentRelease { get; set; }
}
public class FrontPage
{
public Build CurrentCanary { get; set; }
public Build CurrentInsider { get; set; }
public Build CurrentRelease { get; set; }
public Build CurrentXbox { get; set; }
}
}

View File

@ -412,6 +412,7 @@
</Content>
<Content Include="Scripts\trumbowyg\plugins\colors\ui\sass\trumbowyg.colors.scss" />
<Content Include="Scripts\trumbowyg\ui\sass\trumbowyg.scss" />
<Content Include="Views\front\AddBulk.cshtml" />
</ItemGroup>
<ItemGroup />
<ItemGroup>

View File

@ -448,6 +448,21 @@ namespace BuildFeed.Controllers
return View("EditBuild", build);
}
[Route("bulk/")]
[Authorize]
public ActionResult AddBulk()
{
return View();
}
[Route("bulk/")]
[Authorize]
[HttpPost]
public async Task<ActionResult> AddBulk(AddBulk builds)
{
return View(builds);
}
[Route("edit/{id}/")]
[Authorize]
public async Task<ActionResult> EditBuild(Guid id)

View File

@ -0,0 +1,40 @@
@model BuildFeed.Model.View.AddBulk
@{
ViewBag.Title = $"{VariantTerms.Common_AddBulk} | {InvariantTerms.SiteName}";
}
<h1>Add builds in bulk</h1>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<div class="form-group">
<label for="@Html.IdFor(m => m.Builds)">Builds</label>
<div>
@Html.TextAreaFor(m => m.Builds, new
{
rows = 10
})
</div>
</div>
<div class="form-group">
<label></label>
<div>
<label>
@Html.CheckBoxFor(m => m.SendNotifications)
Send notifications
</label>
</div>
</div>
<div class="form-group">
<label></label>
<div>
<input type="submit" value="Add builds" class="button" />
</div>
</div>
}

View File

@ -1,64 +1,78 @@
@model BuildFeed.Model.View.FrontPage
@{
ViewBag.Title = $"{InvariantTerms.SiteName} | Windows 10 Build Tracker";
ViewBag.Title = $"{InvariantTerms.SiteName} | Windows 10 Build Tracker";
}
@section Head
{
<meta name="description" content="Learn what Dona Sarkar won&apos;t tell you. Keep up to date with the latest Microsoft Windows developments with BuildFeed, the comprehensive build tracker." />
<meta name="description" content="Learn what Dona Sarkar won&apos;t tell you. Keep up to date with the latest Microsoft Windows developments with BuildFeed, the comprehensive build tracker." />
}
<h1>@string.Format(VariantTerms.Front_HomeH1, InvariantTerms.SiteName)</h1>
<h3>@VariantTerms.Front_LatestBuilds</h3>
<div class="latest-flex">
@if (Model.CurrentCanary != null)
{
<a href="@Url.Action("ViewBuild", new
{
Model.CurrentCanary.Id
})" class="latest-flex-item latest-flex-red">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentCanary</h3>
<div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentCanary.MajorVersion).@(Model.CurrentCanary.MinorVersion).@(Model.CurrentCanary.Number).@(Model.CurrentCanary.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentCanary.Lab</p>
<p class="latest-flex-time">@(Model.CurrentCanary.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div>
</a>
}
@if (Model.CurrentInsider != null)
{
<a href="@Url.Action("ViewBuild", new
{
Model.CurrentInsider.Id
})" class="latest-flex-item latest-flex-yellow">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentInsider</h3>
<div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentInsider.MajorVersion).@(Model.CurrentInsider.MinorVersion).@(Model.CurrentInsider.Number).@(Model.CurrentInsider.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentInsider.Lab</p>
<p class="latest-flex-time">@(Model.CurrentInsider.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div>
</a>
}
@if (Model.CurrentRelease != null)
{
<a href="@Url.Action("ViewBuild", new
{
Model.CurrentRelease.Id
})" class="latest-flex-item latest-flex-green">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentRelease</h3>
<div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentRelease.MajorVersion).@(Model.CurrentRelease.MinorVersion).@(Model.CurrentRelease.Number).@(Model.CurrentRelease.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentRelease.Lab</p>
<p class="latest-flex-time">@(Model.CurrentRelease.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div>
</a>
}
@if (Model.CurrentCanary != null)
{
<a href="@Url.Action("ViewBuild", new
{
Model.CurrentCanary.Id
})" class="latest-flex-item latest-flex-red">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentCanary</h3>
<div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentCanary.MajorVersion).@(Model.CurrentCanary.MinorVersion).@(Model.CurrentCanary.Number).@(Model.CurrentCanary.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentCanary.Lab</p>
<p class="latest-flex-time">@(Model.CurrentCanary.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div>
</a>
}
@if (Model.CurrentInsider != null)
{
<a href="@Url.Action("ViewBuild", new
{
Model.CurrentInsider.Id
})" class="latest-flex-item latest-flex-yellow">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentInsider</h3>
<div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentInsider.MajorVersion).@(Model.CurrentInsider.MinorVersion).@(Model.CurrentInsider.Number).@(Model.CurrentInsider.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentInsider.Lab</p>
<p class="latest-flex-time">@(Model.CurrentInsider.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div>
</a>
}
@if (Model.CurrentRelease != null)
{
<a href="@Url.Action("ViewBuild", new
{
Model.CurrentRelease.Id
})" class="latest-flex-item latest-flex-blue">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentRelease</h3>
<div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentRelease.MajorVersion).@(Model.CurrentRelease.MinorVersion).@(Model.CurrentRelease.Number).@(Model.CurrentRelease.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentRelease.Lab</p>
<p class="latest-flex-time">@(Model.CurrentRelease.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div>
</a>
}
@if (Model.CurrentXbox != null)
{
<a href="@Url.Action("ViewBuild", new
{
Model.CurrentXbox.Id
})" class="latest-flex-item latest-flex-green">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentXbox</h3>
<div class="latest-flex-detail">
<p class="latest-flex-build">@(Model.CurrentXbox.MajorVersion).@(Model.CurrentXbox.MinorVersion).@(Model.CurrentXbox.Number).@(Model.CurrentXbox.Revision)</p>
<p class="latest-flex-lab">@Model.CurrentXbox.Lab</p>
<p class="latest-flex-time">@(Model.CurrentXbox.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div>
</a>
}
</div>
<a href="@Url.Action("IndexPage", new
{
Page = 1
Page = 1
})" class="latest-full">
@VariantTerms.Front_FullBuildListing
@VariantTerms.Front_FullBuildListing
</a>
<h3>@VariantTerms.Front_Share</h3>
<div class="addthis_sharing_toolbox"></div>

View File

@ -135,6 +135,15 @@
<i class="fa fa-fw fa-plus-square"></i> @VariantTerms.Common_AddBuild
</a>
</li>
<li>
<a href="@Url.Action(nameof(FrontController.AddBulk), new
{
controller = "Front",
area = ""
})" title="@VariantTerms.Common_AddBulk">
<i class="fa fa-fw fa-database"></i> @VariantTerms.Common_AddBulk
</a>
</li>
<li>
<a href="@Url.Action(nameof(SupportController.Logout), new
{

View File

@ -11,6 +11,7 @@
<add key="site:OSGLab" value="rs_prerelease" />
<add key="site:InsiderLab" value="rs_prerelease" />
<add key="site:ReleaseLab" value="rs1_release;rs1_release_inmarket;rs1_release_sec;rs1_release_inmarket_rim" />
<add key="site:XboxLab" value="rs1_xbox_rel_1610" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.6.2">

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -341,7 +341,7 @@ article
.build-group-empty
{
width: 255px;
width: 270px;
flex-grow: 1;
margin: 0 0.75em;
box-sizing: border-box;
@ -404,6 +404,16 @@ article
}
}
&.latest-flex-blue
{
border: #{(1em / 4)} solid #0A81CC;
h3.latest-flex-title
{
background: #0A81CC;
}
}
&.latest-flex-green
{
border: #{(1em / 4)} solid #12B23F;