Add Xbox to front page; Bulk add

This commit is contained in:
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 @@ public static string Common_AddBuild {
} }
} }
/// <summary>
/// Looks up a localized string similar to Add bulk.
/// </summary>
public static string Common_AddBulk {
get {
return ResourceManager.GetString("Common_AddBulk", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Admin. /// Looks up a localized string similar to Admin.
/// </summary> /// </summary>
@ -339,6 +348,15 @@ public static string Front_CurrentRelease {
} }
} }
/// <summary>
/// Looks up a localized string similar to Current Xbox.
/// </summary>
public static string Front_CurrentXbox {
get {
return ResourceManager.GetString("Front_CurrentXbox", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Delete. /// Looks up a localized string similar to Delete.
/// </summary> /// </summary>

View File

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

View File

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

View File

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

View File

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

View File

@ -448,6 +448,21 @@ public async Task<ActionResult> AddBuild(Build build)
return View("EditBuild", build); 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}/")] [Route("edit/{id}/")]
[Authorize] [Authorize]
public async Task<ActionResult> EditBuild(Guid id) 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 @model BuildFeed.Model.View.FrontPage
@{ @{
ViewBag.Title = $"{InvariantTerms.SiteName} | Windows 10 Build Tracker"; ViewBag.Title = $"{InvariantTerms.SiteName} | Windows 10 Build Tracker";
} }
@section Head @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> <h1>@string.Format(VariantTerms.Front_HomeH1, InvariantTerms.SiteName)</h1>
<h3>@VariantTerms.Front_LatestBuilds</h3> <h3>@VariantTerms.Front_LatestBuilds</h3>
<div class="latest-flex"> <div class="latest-flex">
@if (Model.CurrentCanary != null) @if (Model.CurrentCanary != null)
{ {
<a href="@Url.Action("ViewBuild", new <a href="@Url.Action("ViewBuild", new
{ {
Model.CurrentCanary.Id Model.CurrentCanary.Id
})" class="latest-flex-item latest-flex-red"> })" class="latest-flex-item latest-flex-red">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentCanary</h3> <h3 class="latest-flex-title">@VariantTerms.Front_CurrentCanary</h3>
<div class="latest-flex-detail"> <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-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-lab">@Model.CurrentCanary.Lab</p>
<p class="latest-flex-time">@(Model.CurrentCanary.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p> <p class="latest-flex-time">@(Model.CurrentCanary.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div> </div>
</a> </a>
} }
@if (Model.CurrentInsider != null) @if (Model.CurrentInsider != null)
{ {
<a href="@Url.Action("ViewBuild", new <a href="@Url.Action("ViewBuild", new
{ {
Model.CurrentInsider.Id Model.CurrentInsider.Id
})" class="latest-flex-item latest-flex-yellow"> })" class="latest-flex-item latest-flex-yellow">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentInsider</h3> <h3 class="latest-flex-title">@VariantTerms.Front_CurrentInsider</h3>
<div class="latest-flex-detail"> <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-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-lab">@Model.CurrentInsider.Lab</p>
<p class="latest-flex-time">@(Model.CurrentInsider.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p> <p class="latest-flex-time">@(Model.CurrentInsider.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div> </div>
</a> </a>
} }
@if (Model.CurrentRelease != null) @if (Model.CurrentRelease != null)
{ {
<a href="@Url.Action("ViewBuild", new <a href="@Url.Action("ViewBuild", new
{ {
Model.CurrentRelease.Id Model.CurrentRelease.Id
})" class="latest-flex-item latest-flex-green"> })" class="latest-flex-item latest-flex-blue">
<h3 class="latest-flex-title">@VariantTerms.Front_CurrentRelease</h3> <h3 class="latest-flex-title">@VariantTerms.Front_CurrentRelease</h3>
<div class="latest-flex-detail"> <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-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-lab">@Model.CurrentRelease.Lab</p>
<p class="latest-flex-time">@(Model.CurrentRelease.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p> <p class="latest-flex-time">@(Model.CurrentRelease.BuildTime?.ToString("HH:mm, dddd dd MMMM yyyy"))</p>
</div> </div>
</a> </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> </div>
<a href="@Url.Action("IndexPage", new <a href="@Url.Action("IndexPage", new
{ {
Page = 1 Page = 1
})" class="latest-full"> })" class="latest-full">
@VariantTerms.Front_FullBuildListing @VariantTerms.Front_FullBuildListing
</a> </a>
<h3>@VariantTerms.Front_Share</h3> <h3>@VariantTerms.Front_Share</h3>
<div class="addthis_sharing_toolbox"></div> <div class="addthis_sharing_toolbox"></div>

View File

@ -135,6 +135,15 @@
<i class="fa fa-fw fa-plus-square"></i> @VariantTerms.Common_AddBuild <i class="fa fa-fw fa-plus-square"></i> @VariantTerms.Common_AddBuild
</a> </a>
</li> </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> <li>
<a href="@Url.Action(nameof(SupportController.Logout), new <a href="@Url.Action(nameof(SupportController.Logout), new
{ {

View File

@ -11,6 +11,7 @@
<add key="site:OSGLab" value="rs_prerelease" /> <add key="site:OSGLab" value="rs_prerelease" />
<add key="site:InsiderLab" 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:ReleaseLab" value="rs1_release;rs1_release_inmarket;rs1_release_sec;rs1_release_inmarket_rim" />
<add key="site:XboxLab" value="rs1_xbox_rel_1610" />
</appSettings> </appSettings>
<system.web> <system.web>
<compilation debug="true" targetFramework="4.6.2"> <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 .build-group-empty
{ {
width: 255px; width: 270px;
flex-grow: 1; flex-grow: 1;
margin: 0 0.75em; margin: 0 0.75em;
box-sizing: border-box; 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 &.latest-flex-green
{ {
border: #{(1em / 4)} solid #12B23F; border: #{(1em / 4)} solid #12B23F;