Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
String list and search implemented:
Browse files Browse the repository at this point in the history
- Filters and initial string list are properly initialized on first page load
  based on the supplied query string

- Modifying the filters loads the new data via Ajax and pushes the newly
  generated query string in browser history, same for the quick filter links

- Reviewers see "Ignore" buttons in the list, but the buttons do nothing yet

- A spinner is displayed in the center of the screen while loading Ajax data

Ohter improvements:

- Html.DropDownListFor is now used for rendering the dropdown filters

- Bundling+minification of css and js configured for production environment

- ASP.NET client validation disabled on startup (no more validation attributes
  in the generated HTML)
  • Loading branch information
Konamiman committed Apr 10, 2019
1 parent ee568bb commit 68e5212
Show file tree
Hide file tree
Showing 19 changed files with 592 additions and 108 deletions.
27 changes: 26 additions & 1 deletion Traducir.Api/ViewModels/Strings/QueryViewModel.cs
@@ -1,25 +1,35 @@
using System.ComponentModel.DataAnnotations;

namespace Traducir.Api.ViewModels.Strings
{
#pragma warning disable CA1717
public enum SuggestionApprovalStatus
{
AnyStatus = 0, // will default to this one
[Display(Name = "Any string", Order = 0)]
AnyStatus = 0,

[Display(Name = "Strings without suggestions", Order = 1)]
DoesNotHaveSuggestions = 1,

[Display(Name = "Strings with suggestions awaiting review", Order = 3)]
HasSuggestionsNeedingReview = 2,

[Display(Name = "Strings with suggestions awaiting approval", Order = 2)]
HasSuggestionsNeedingApproval = 3,

[Display(Name = "Strings with approved suggestions awaiting review", Order = 4)]
HasSuggestionsNeedingReviewApprovedByTrustedUser = 4
}

public enum TranslationStatus
{
[Display(Name = "Any string", Order = 0)]
AnyStatus = 0,

[Display(Name = "Only strings with translation", Order = 2)]
WithTranslation = 1,

[Display(Name = "Only strings without translation", Order = 1)]
WithoutTranslation = 2
}

Expand All @@ -34,10 +44,13 @@ public enum PushStatus

public enum UrgencyStatus
{
[Display(Name = "Any string", Order = 0)]
AnyStatus = 0,

[Display(Name = "Is urgent", Order = 1)]
IsUrgent = 1,

[Display(Name = "Is not urgent", Order = 2)]
IsNotUrgent = 2
}

Expand All @@ -53,6 +66,18 @@ public enum IgnoredStatus

public class QueryViewModel
{
public static QueryViewModel Empty => new QueryViewModel();

public bool IsEmpty =>
string.IsNullOrEmpty(SourceRegex) &&
string.IsNullOrEmpty(TranslationRegex) &&
string.IsNullOrEmpty(Key) &&
TranslationStatus == TranslationStatus.AnyStatus &&
SuggestionsStatus == SuggestionApprovalStatus.AnyStatus &&
PushStatus == PushStatus.AnyStatus &&
UrgencyStatus == UrgencyStatus.AnyStatus &&
IgnoredStatus == IgnoredStatus.AvoidIgnored;

public string SourceRegex { get; set; }

public string TranslationRegex { get; set; }
Expand Down
1 change: 1 addition & 0 deletions Traducir.Web.Net/.gitignore
@@ -0,0 +1 @@
site.min.*
60 changes: 55 additions & 5 deletions Traducir.Web.Net/Controllers/HomeController.cs
Expand Up @@ -3,9 +3,14 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Traducir.Api.Services;
using Traducir.Core.Services;
using Traducir.Core.Helpers;
using Traducir.Web.Net.Models;
using Traducir.Web.Net.ViewModels.Home;
using Traducir.Api.ViewModels.Strings;
using Traducir.Core.Models.Enums;
using System;
using Traducir.Core.Models;
using System.Collections.Generic;

namespace Traducir.Web.Net.Controllers
{
Expand All @@ -18,22 +23,67 @@ public HomeController(IStringsService stringsService)
this.stringsService = stringsService;
}

public async Task<IActionResult> Index()
public Task<IActionResult> Index()
{
return await Filters();
return Filters(null);
}

[Route("/filters")]
public async Task<IActionResult> Filters()
public async Task<IActionResult> Filters(QueryViewModel query)
{
FilterResultsViewModel filterResults = null;

if(query == null)
{
query = new QueryViewModel();
}
else if(query.IsEmpty)
{
//let's redirect to root if we get just '/filters'
return RedirectToAction(nameof(Index));
}
else
{
filterResults = new FilterResultsViewModel
{
UserType = User.GetClaim<UserType>(ClaimType.UserType),
Strings = await stringsService.Query(query)
};
}

var viewModel = new IndexViewModel
{
StringCounts = await stringsService.GetStringCounts()
StringCounts = await stringsService.GetStringCounts(),
StringsQuery = query,
FilterResults = filterResults
};

return View("~/Views/Home/Index.cshtml", viewModel);
}

[Route("/strings_list")]
public async Task<IActionResult> StringsList(QueryViewModel query)
{
IEnumerable<SOString> strings;

try
{
strings = await stringsService.Query(query);
}
catch (InvalidOperationException ex)
{
return BadRequest(ex.Message);
}

var filterResults = new FilterResultsViewModel
{
UserType = User.GetClaim<UserType>(ClaimType.UserType),
Strings = strings
};

return PartialView("FilterResults", filterResults);
}

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
Expand Down
6 changes: 5 additions & 1 deletion Traducir.Web.Net/Startup.cs
Expand Up @@ -42,7 +42,11 @@ public void ConfigureServices(IServiceCollection services)
options.MinimumSameSitePolicy = SameSiteMode.None;
});

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services
.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddViewOptions(options => options.HtmlHelperOptions.ClientValidationEnabled = false);

services.AddHttpContextAccessor();
}

Expand Down
8 changes: 8 additions & 0 deletions Traducir.Web.Net/Traducir.Web.Net.csproj
Expand Up @@ -10,6 +10,12 @@
<WarningsAsErrors />
</PropertyGroup>

<ItemGroup>
<Content Remove="Views\Shared\_ValidationScriptsPartial.cshtml" />
<Content Remove="wwwroot\css\site.min.css" />
<Content Remove="wwwroot\js\site.min.js" />
</ItemGroup>

<ItemGroup>
<None Remove="Properties\launchSettings.jsonx" />
</ItemGroup>
Expand Down Expand Up @@ -45,9 +51,11 @@


<ItemGroup>
<PackageReference Include="BuildBundlerMinifier" Version="2.9.406" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.2.3" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
<PackageReference Include="Simple.Migrations" Version="0.9.19" />
<PackageReference Include="StackExchange.Exceptional.AspNetCore" Version="2.0.0" />
</ItemGroup>
Expand Down
22 changes: 22 additions & 0 deletions Traducir.Web.Net/ViewModels/Home/FilterResultsViewModel.cs
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using System.Linq;
using Traducir.Core.Models;
using Traducir.Core.Models.Enums;

namespace Traducir.Web.Net.ViewModels.Home
{
public class FilterResultsViewModel
{
public UserType UserType { get; set; }

public IEnumerable<SOString> Strings { get; set; }

public int Count => Strings.Count();

public int ApprovedSuggestionsCountFor(SOString str) => str.Suggestions?.Count(s => s.State == StringSuggestionState.ApprovedByTrustedUser) ?? 0;

public int PendingSuggestionsCountFor(SOString str) => str.Suggestions?.Count(s => s.State == StringSuggestionState.Created) ?? 0;

public bool UserCanManageIgnoring => UserType >= UserType.TrustedUser;
}
}
2 changes: 2 additions & 0 deletions Traducir.Web.Net/ViewModels/Home/IndexViewModel.cs
Expand Up @@ -5,5 +5,7 @@ namespace Traducir.Web.Net.ViewModels.Home
public class IndexViewModel
{
public StringCountsViewModel StringCounts { get; set; }
public QueryViewModel StringsQuery { get; set; }
public FilterResultsViewModel FilterResults { get; set; }
}
}
67 changes: 67 additions & 0 deletions Traducir.Web.Net/Views/Home/FilterResults.cshtml
@@ -0,0 +1,67 @@
@model Traducir.Web.Net.ViewModels.Home.FilterResultsViewModel

<div class="m-2 text-center">
<h2>
Results @(Model.Count > 0 ? $"({Model.Count})" : null)
</h2>
</div>
<table class="table">
<thead class="thead-light">
<tr>
<th>String</th>
<th>Translation</th>
<th>Suggestions</th>
</tr>
</thead>
<tbody>
@if(Model.Count == 0)
{
<tr>
<td colSpan="3" class="text-center">No results (sad trombone)</td>
</tr>
}
else
{
foreach (var str in Model.Strings)
{
var approvedCount = Model.ApprovedSuggestionsCountFor(str);
var pendingCount = Model.PendingSuggestionsCountFor(str);

<tr>
<td>@str.OriginalString</td>
<td>
@if(str.Translation != null)
{
<text>@str.Translation</text>
}
else if(Model.UserCanManageIgnoring)
{
if (str.IsIgnored)
{
<button type="button" class="btn btn-warning btn-sm">Stop ignoring</button>
}
else
{
<button type="button" class="btn btn-warning btn-sm">Ignore!</button>
}
}
</td>
<td>
@if (approvedCount > 0)
{
<span class="text-success">@approvedCount</span>
}
@if (approvedCount > 0 && pendingCount > 0)
{
<span> - </span>
}
@if(pendingCount > 0)
{
<span class="text-danger">@pendingCount</span>
}
</td>
</tr>
}
}
</tbody>
</table>

0 comments on commit 68e5212

Please sign in to comment.