Add Option for Hiding Left Navigation (#3686)
* Add option for hiding left navigation * Improve reviews page command bar * Persist page settings as user preferences * Smart update cache * Add auto mapper for mapping between models
This commit is contained in:
Родитель
13a0b3bf6f
Коммит
8e661c62b1
|
@ -22,6 +22,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
|
||||||
<PackageReference Include="Azure.Storage.Blobs" Version="12.13.0" />
|
<PackageReference Include="Azure.Storage.Blobs" Version="12.13.0" />
|
||||||
<PackageReference Include="CsvHelper" Version="27.2.1" />
|
<PackageReference Include="CsvHelper" Version="27.2.1" />
|
||||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.12.0-beta4" />
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.12.0-beta4" />
|
||||||
|
|
|
@ -571,6 +571,7 @@ code {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 1%;
|
width: 1%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line-details table {
|
.line-details table {
|
||||||
|
|
|
@ -1,33 +1 @@
|
||||||
import Split from "split.js";
|
|
||||||
|
|
||||||
addEventListener("load", () => {
|
|
||||||
$(".nav-list-toggle").click(function () {
|
|
||||||
$(this).parents(".nav-list-group").first().toggleClass("nav-list-collapsed");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(() => {
|
|
||||||
/* 992px matches bootstrap col-lg min-width */
|
|
||||||
($('.namespace-view') as any).stickySidebar({ minWidth: 992 });
|
|
||||||
|
|
||||||
/* Split left and right review panes using split.js */
|
|
||||||
const rl = $('#review-left');
|
|
||||||
const rr = $('#review-right');
|
|
||||||
|
|
||||||
if (rl.length && rr.length) {
|
|
||||||
Split(['#review-left', '#review-right'], {
|
|
||||||
direction: 'horizontal',
|
|
||||||
sizes: [17, 83],
|
|
||||||
elementStyle: (dimension, size, gutterSize) => {
|
|
||||||
return {
|
|
||||||
'flex-basis': `calc(${size}% - ${gutterSize}px`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
gutterStyle: (dimension, gutterSize) => {
|
|
||||||
return {
|
|
||||||
'flex-basis': `${gutterSize}px`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,4 +1,6 @@
|
||||||
$(() => {
|
import Split from "split.js";
|
||||||
|
|
||||||
|
$(() => {
|
||||||
const SEL_DOC_CLASS = ".documentation";
|
const SEL_DOC_CLASS = ".documentation";
|
||||||
const SHOW_DOC_CHECK_COMPONENT = "#show-documentation-component";
|
const SHOW_DOC_CHECK_COMPONENT = "#show-documentation-component";
|
||||||
const SHOW_DOC_CHECKBOX = ".show-doc-checkbox";
|
const SHOW_DOC_CHECKBOX = ".show-doc-checkbox";
|
||||||
|
@ -6,15 +8,73 @@
|
||||||
const SHOW_DIFFONLY_CHECKBOX = ".show-diffonly-checkbox";
|
const SHOW_DIFFONLY_CHECKBOX = ".show-diffonly-checkbox";
|
||||||
const SHOW_DIFFONLY_HREF = ".show-diffonly";
|
const SHOW_DIFFONLY_HREF = ".show-diffonly";
|
||||||
const HIDE_LINE_NUMBERS = "#hide-line-numbers";
|
const HIDE_LINE_NUMBERS = "#hide-line-numbers";
|
||||||
|
const HIDE_LEFT_NAVIGATION = "#hide-left-navigation";
|
||||||
|
|
||||||
hideCheckboxIfNoDocs();
|
hideCheckboxIfNoDocs();
|
||||||
|
|
||||||
|
/* FUNCTIONS
|
||||||
|
--------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
function hideCheckboxIfNoDocs() {
|
function hideCheckboxIfNoDocs() {
|
||||||
if ($(SEL_DOC_CLASS).length == 0) {
|
if ($(SEL_DOC_CLASS).length == 0) {
|
||||||
$(SHOW_DOC_CHECK_COMPONENT).hide();
|
$(SHOW_DOC_CHECK_COMPONENT).hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function splitReviewPageContent() {
|
||||||
|
/* Split left and right review panes using split.js */
|
||||||
|
const rl = $('#review-left');
|
||||||
|
const rr = $('#review-right');
|
||||||
|
|
||||||
|
if (rl.length && rr.length) {
|
||||||
|
Split(['#review-left', '#review-right'], {
|
||||||
|
direction: 'horizontal',
|
||||||
|
sizes: [17, 83],
|
||||||
|
elementStyle: (dimension, size, gutterSize) => {
|
||||||
|
return {
|
||||||
|
'flex-basis': `calc(${size}% - ${gutterSize}px`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
gutterStyle: (dimension, gutterSize) => {
|
||||||
|
return {
|
||||||
|
'flex-basis': `${gutterSize}px`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updated Page Setting by Updating UserPreference
|
||||||
|
function updatePageSettings(callBack) {
|
||||||
|
var hideLineNumbers = $(HIDE_LINE_NUMBERS).prop("checked");
|
||||||
|
var hideLeftNavigation = $(HIDE_LEFT_NAVIGATION).prop("checked");
|
||||||
|
var uri = `?handler=updatepagesettings&hideLineNumbers=${hideLineNumbers}&hideLeftNavigation=${hideLeftNavigation}`;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "GET",
|
||||||
|
url: uri
|
||||||
|
}).done(callBack());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ADD EVENT LISTENER FOR TOGGLING LEFT NAVIGATION
|
||||||
|
--------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
|
addEventListener("load", () => {
|
||||||
|
$(".nav-list-toggle").click(function () {
|
||||||
|
$(this).parents(".nav-list-group").first().toggleClass("nav-list-collapsed");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* SPLIT REVIEW PAGE CONTENT
|
||||||
|
--------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
|
/* 992px matches bootstrap col-lg min-width */
|
||||||
|
($('.namespace-view') as any).stickySidebar({ minWidth: 992 });
|
||||||
|
if (!$("#review-left").hasClass("d-none"))
|
||||||
|
{
|
||||||
|
// Only Add Split gutter if left navigation is not hidden
|
||||||
|
splitReviewPageContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOGGLE PAGE OPTIONS
|
||||||
|
--------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
$(SHOW_DOC_CHECKBOX).on("click", e => {
|
$(SHOW_DOC_CHECKBOX).on("click", e => {
|
||||||
$(SHOW_DOC_HREF)[0].click();
|
$(SHOW_DOC_HREF)[0].click();
|
||||||
});
|
});
|
||||||
|
@ -24,17 +84,32 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
$(HIDE_LINE_NUMBERS).on("click", e => {
|
$(HIDE_LINE_NUMBERS).on("click", e => {
|
||||||
$(".line-number").toggleClass("d-none");
|
updatePageSettings(function(){
|
||||||
});
|
$(".line-number").toggleClass("d-none");
|
||||||
|
|
||||||
/* DIFF BUTTON (UPDATES REVIEW PAGE ON CLICK)
|
|
||||||
--------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
|
||||||
$('.diff-button').each(function(index, value){
|
|
||||||
$(this).on('click', function () {
|
|
||||||
window.location.href = $(this).val() as string;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(HIDE_LEFT_NAVIGATION).on("click", e => {
|
||||||
|
updatePageSettings(function(){
|
||||||
|
var leftContainer = $("#review-left");
|
||||||
|
var rightContainer = $("#review-right");
|
||||||
|
var gutter = $(".gutter-horizontal");
|
||||||
|
|
||||||
|
if (leftContainer.hasClass("d-none")) {
|
||||||
|
leftContainer.removeClass("d-none");
|
||||||
|
rightContainer.removeClass("col-12");
|
||||||
|
rightContainer.addClass("col-10");
|
||||||
|
splitReviewPageContent();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
leftContainer.addClass("d-none");
|
||||||
|
rightContainer.css("flex-basis", "100%");
|
||||||
|
gutter.remove();
|
||||||
|
rightContainer.removeClass("col-10");
|
||||||
|
rightContainer.addClass("col-12");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
/* DROPDOWN FILTER FOR REVIEW, REVISIONS AND DIFF (UPDATES REVIEW PAGE ON CHANGE)
|
/* DROPDOWN FILTER FOR REVIEW, REVISIONS AND DIFF (UPDATES REVIEW PAGE ON CHANGE)
|
||||||
--------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
--------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
|
@ -59,7 +134,6 @@
|
||||||
var caretDirection = caretClasses ? caretClasses.split(' ').filter(c => c.startsWith('fa-angle-'))[0] : "";
|
var caretDirection = caretClasses ? caretClasses.split(' ').filter(c => c.startsWith('fa-angle-'))[0] : "";
|
||||||
var foldableClassPrefix = headingRowClasses ? headingRowClasses.split(' ').filter(c => c.endsWith('-heading'))[0].replace("-heading", "") : "";
|
var foldableClassPrefix = headingRowClasses ? headingRowClasses.split(' ').filter(c => c.endsWith('-heading'))[0].replace("-heading", "") : "";
|
||||||
|
|
||||||
|
|
||||||
if (triggeringClass == "row-fold-caret" && caretDirection == "fa-angle-down") {
|
if (triggeringClass == "row-fold-caret" && caretDirection == "fa-angle-down") {
|
||||||
var classesOfRowsToHide = [`${foldableClassPrefix}-content`];
|
var classesOfRowsToHide = [`${foldableClassPrefix}-content`];
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
$(() => {
|
$(() => {
|
||||||
// Search
|
|
||||||
const defaultPageSize = 50;
|
const defaultPageSize = 50;
|
||||||
const reviewsFilterPartial = $( '#reviews-filter-partial' );
|
const reviewsFilterPartial = $( '#reviews-filter-partial' );
|
||||||
const languageFilter = $( '#language-filter-bootstraps-select' );
|
const languageFilter = $( '#language-filter-bootstraps-select' );
|
||||||
|
@ -77,10 +76,9 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Triggers partial page update to retriev properties for poulating filter dropdowns
|
// Fetches data for populating dropdown options
|
||||||
function updateFilterDropDown(filter, query)
|
function updateFilterDropDown(filter, query)
|
||||||
{
|
{
|
||||||
// update tags dropdown select
|
|
||||||
var uri = `?handler=reviews${query}`;
|
var uri = `?handler=reviews${query}`;
|
||||||
var urlParams = new URLSearchParams(location.search);
|
var urlParams = new URLSearchParams(location.search);
|
||||||
if (urlParams.has(query))
|
if (urlParams.has(query))
|
||||||
|
@ -97,20 +95,20 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update content of dropdown on page load
|
// Fetch content of dropdown on page load
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
updateFilterDropDown(languageFilter, "languages");
|
updateFilterDropDown(languageFilter, "languages"); // Pulls languages data from DB
|
||||||
addPaginationEventHandlers();
|
addPaginationEventHandlers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update list of reviews when any dropdown is changed
|
||||||
// Update when any dropdown is changed
|
|
||||||
[languageFilter, stateFilter, statusFilter, typeFilter].forEach(function(value, index) {
|
[languageFilter, stateFilter, statusFilter, typeFilter].forEach(function(value, index) {
|
||||||
value.on('hidden.bs.select', function() {
|
value.on('hidden.bs.select', function() {
|
||||||
updateListedReviews();
|
updateListedReviews();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update list of reviews based on search input
|
||||||
searchBox.on('input', _.debounce(function(e) {
|
searchBox.on('input', _.debounce(function(e) {
|
||||||
updateListedReviews();
|
updateListedReviews();
|
||||||
}, 600));
|
}, 600));
|
||||||
|
@ -119,6 +117,7 @@
|
||||||
updateListedReviews();
|
updateListedReviews();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Reset list of reviews as well as filters
|
||||||
resetButton.on('click', function(e) {
|
resetButton.on('click', function(e) {
|
||||||
(<any>languageFilter).selectpicker('deselectAll');
|
(<any>languageFilter).selectpicker('deselectAll');
|
||||||
(<any>stateFilter).selectpicker('deselectAll').selectpicker('val', 'Open');
|
(<any>stateFilter).selectpicker('deselectAll').selectpicker('val', 'Open');
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
using APIViewWeb.Models;
|
||||||
|
using AutoMapper;
|
||||||
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
|
||||||
|
namespace APIViewWeb.Helpers
|
||||||
|
{
|
||||||
|
public class AutoMapperProfiles : Profile
|
||||||
|
{
|
||||||
|
public AutoMapperProfiles()
|
||||||
|
{
|
||||||
|
CreateMap<UserPreferenceModel, UserPreferenceModel>()
|
||||||
|
.ForMember(dest => dest.UserName, opt => opt.MapFrom((src, dest) => src.UserName != null ? src.UserName : dest.UserName))
|
||||||
|
.ForMember(dest => dest.Language, opt => opt.MapFrom((src, dest) => src.Language != null ? src.Language : dest.Language))
|
||||||
|
.ForMember(dest => dest.FilterType, opt => opt.MapFrom((src, dest) => src.FilterType != null ? src.FilterType : dest.FilterType))
|
||||||
|
.ForMember(dest => dest.State, opt => opt.MapFrom((src, dest) => src.State != null ? src.State : dest.State))
|
||||||
|
.ForMember(dest => dest.Status, opt => opt.MapFrom((src, dest) => src.Status != null ? src.Status : dest.Status))
|
||||||
|
.ForMember(dest => dest.HideLineNumbers, opt => opt.MapFrom((src, dest) => src.HideLineNumbers != null ? src.HideLineNumbers : dest.HideLineNumbers))
|
||||||
|
.ForMember(dest => dest.HideLeftNavigation, opt => opt.MapFrom((src, dest) => src.HideLeftNavigation != null ? src.HideLeftNavigation : dest.HideLeftNavigation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using CsvHelper.Configuration.Attributes;
|
using CsvHelper.Configuration.Attributes;
|
||||||
|
|
||||||
namespace APIViewWeb.Models
|
namespace APIViewWeb.Models
|
||||||
|
@ -12,5 +13,13 @@ namespace APIViewWeb.Models
|
||||||
public IEnumerable<string> Language { get; set; }
|
public IEnumerable<string> Language { get; set; }
|
||||||
[Name("FilterType")]
|
[Name("FilterType")]
|
||||||
public IEnumerable<ReviewType> FilterType { get; set; }
|
public IEnumerable<ReviewType> FilterType { get; set; }
|
||||||
|
[Name("State")]
|
||||||
|
public IEnumerable<string> State { get; set; }
|
||||||
|
[Name("Status")]
|
||||||
|
public IEnumerable<string> Status { get; set; }
|
||||||
|
[Name("HideLineNumbers")]
|
||||||
|
public bool? HideLineNumbers { get; set; }
|
||||||
|
[Name("HideLeftNavigation")]
|
||||||
|
public bool? HideLeftNavigation { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,20 @@ namespace APIViewWeb.Pages.Assemblies
|
||||||
List<string> search = null, List<string> languages=null, List<string> state =null,
|
List<string> search = null, List<string> languages=null, List<string> state =null,
|
||||||
List<string> status =null, List<string> type =null, int pageNo=1, int pageSize=_defaultPageSize, string sortField=_defaultSortField)
|
List<string> status =null, List<string> type =null, int pageNo=1, int pageSize=_defaultPageSize, string sortField=_defaultSortField)
|
||||||
{
|
{
|
||||||
|
if (search.Count == 0 && languages.Count == 0 && state.Count == 0 && status.Count == 0 && type.Count == 0)
|
||||||
|
{
|
||||||
|
UserPreferenceModel userPreference = _preferenceCache.GetUserPreferences(User.GetGitHubLogin());
|
||||||
|
if (userPreference != null)
|
||||||
|
{
|
||||||
|
languages = userPreference.Language.ToList();
|
||||||
|
state = userPreference.State.ToList();
|
||||||
|
status = userPreference.Status.ToList();
|
||||||
|
type = new List<string>();
|
||||||
|
if (userPreference.FilterType.Contains(ReviewType.Manual)) { type.Add("Manual"); }
|
||||||
|
if (userPreference.FilterType.Contains(ReviewType.Automatic)) { type.Add("Automatic"); }
|
||||||
|
if (userPreference.FilterType.Contains(ReviewType.PullRequest)) { type.Add("PullRequest"); }
|
||||||
|
}
|
||||||
|
}
|
||||||
await RunGetRequest(search, languages, state, status, type, pageNo, pageSize, sortField);
|
await RunGetRequest(search, languages, state, status, type, pageNo, pageSize, sortField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +65,14 @@ namespace APIViewWeb.Pages.Assemblies
|
||||||
|
|
||||||
public async Task<PartialViewResult> OnGetReviewsLanguagesAsync(List<string> selectedLanguages = null)
|
public async Task<PartialViewResult> OnGetReviewsLanguagesAsync(List<string> selectedLanguages = null)
|
||||||
{
|
{
|
||||||
|
if (selectedLanguages.Count == 0)
|
||||||
|
{
|
||||||
|
UserPreferenceModel userPreference = _preferenceCache.GetUserPreferences(User.GetGitHubLogin());
|
||||||
|
if (userPreference != null)
|
||||||
|
{
|
||||||
|
selectedLanguages = userPreference.Language.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
ReviewsProperties.Languages.All = await _manager.GetReviewPropertiesAsync("Revisions[0].Files[0].Language");
|
ReviewsProperties.Languages.All = await _manager.GetReviewPropertiesAsync("Revisions[0].Files[0].Language");
|
||||||
selectedLanguages = selectedLanguages.Select(x => HttpUtility.UrlDecode(x)).ToList();
|
selectedLanguages = selectedLanguages.Select(x => HttpUtility.UrlDecode(x)).ToList();
|
||||||
ReviewsProperties.Languages.Selected = selectedLanguages;
|
ReviewsProperties.Languages.Selected = selectedLanguages;
|
||||||
|
@ -128,11 +150,12 @@ namespace APIViewWeb.Pages.Assemblies
|
||||||
if (type.Contains("Automatic")) { filterTypes.Add((int)ReviewType.Automatic); }
|
if (type.Contains("Automatic")) { filterTypes.Add((int)ReviewType.Automatic); }
|
||||||
if (type.Contains("PullRequest")) { filterTypes.Add((int)ReviewType.PullRequest); }
|
if (type.Contains("PullRequest")) { filterTypes.Add((int)ReviewType.PullRequest); }
|
||||||
|
|
||||||
_preferenceCache.UpdateUserPreference(new UserPreferenceModel()
|
_preferenceCache.UpdateUserPreference(new UserPreferenceModel {
|
||||||
{
|
|
||||||
UserName = User.GetGitHubLogin(),
|
UserName = User.GetGitHubLogin(),
|
||||||
FilterType = filterTypes.Cast<ReviewType>().ToList(),
|
FilterType = filterTypes.Cast<ReviewType>().ToList(),
|
||||||
Language = languages
|
Language = languages,
|
||||||
|
State = state,
|
||||||
|
Status = status
|
||||||
});
|
});
|
||||||
|
|
||||||
bool? isApproved = null;
|
bool? isApproved = null;
|
||||||
|
|
|
@ -6,268 +6,94 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row mt-2 mb-0 pl-1">
|
<div class="row mx-1 px-0 py-2 border-bottom">
|
||||||
<div class="col">
|
<div class="col-lg-12 d-flex px-0">
|
||||||
<h3 class="mb-0">
|
@if (Model.Review.Language != null)
|
||||||
|
{
|
||||||
|
var imageSource = String.Empty;
|
||||||
|
@switch (Model.Review.Language.ToLower())
|
||||||
|
{
|
||||||
|
case "c#":
|
||||||
|
imageSource = "icons/csharp-original.svg";
|
||||||
|
break;
|
||||||
|
case "javascript":
|
||||||
|
imageSource = "icons/javascript-original.svg";
|
||||||
|
break;
|
||||||
|
case "python":
|
||||||
|
imageSource = "icons/python-original.svg";
|
||||||
|
break;
|
||||||
|
case "c":
|
||||||
|
imageSource = "icons/c-original.svg";
|
||||||
|
break;
|
||||||
|
case "c++":
|
||||||
|
imageSource = "icons/cplusplus-original.svg";
|
||||||
|
break;
|
||||||
|
case "go":
|
||||||
|
imageSource = "icons/go-original.svg";
|
||||||
|
break;
|
||||||
|
case "java":
|
||||||
|
imageSource = "icons/java-original.svg";
|
||||||
|
break;
|
||||||
|
case "swift":
|
||||||
|
imageSource = "icons/swift-original.svg";
|
||||||
|
break;
|
||||||
|
case "kotlin":
|
||||||
|
imageSource = "icons/kotlin-original.svg";
|
||||||
|
break;
|
||||||
|
case "json":
|
||||||
|
imageSource = "icons/json-original.svg";
|
||||||
|
break;
|
||||||
|
case "swagger":
|
||||||
|
imageSource = "icons/swagger-original.svg";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (String.IsNullOrEmpty(imageSource))
|
||||||
|
{
|
||||||
|
<span class="badge badge-info"><em>@Model.Review.Language</em></span>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span><img class="mr-2 mt-1 p-1 border rounded" src="~/@imageSource" width="34" alt="@Model.Review.Language" /></span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<p class="h6 mb-0 mr-auto">
|
||||||
@if (Model.Review.ServiceName != null)
|
@if (Model.Review.ServiceName != null)
|
||||||
{
|
{
|
||||||
@Model.Review.ServiceName
|
@Model.Review.ServiceName
|
||||||
<span> | </span>
|
|
||||||
}
|
}
|
||||||
|
<br>
|
||||||
<small class="text-muted">@Model.Review.PackageDisplayName</small>
|
<small class="text-muted">@Model.Review.PackageDisplayName</small>
|
||||||
@if (Model.Review.Language != null)
|
</p>
|
||||||
|
<div class="my-1">
|
||||||
|
@if (Model.Revision.Approvers.Count > 0)
|
||||||
{
|
{
|
||||||
@switch (Model.Review.Language.ToLower())
|
var approvers = String.Join(", ", Model.Revision.Approvers);
|
||||||
{
|
<button type="button" class="btn btn-sm shadow-sm btn-success" data-placement="bottom" data-trigger="focus" data-toggle="popover" data-title="Approvers" data-content="@approvers">
|
||||||
case "c#":
|
<i class="fas fa-check-circle"></i> APPROVED
|
||||||
<span><img class="mx-1" src="~/icons/csharp-original.svg" width="40" alt="@Model.Review.Language"></span>
|
<span class="badge badge-light">@Model.Revision.Approvers.Count</span>
|
||||||
break;
|
</button>
|
||||||
case "javascript":
|
}
|
||||||
<span><img class="mx-1" src="~/icons/javascript-original.svg" width="40" alt="@Model.Review.Language"></span>
|
else
|
||||||
break;
|
{
|
||||||
case "python":
|
<button type="button" class="btn btn-light btn-sm shadow-sm">
|
||||||
<span><img class="mx-1" src="~/icons/python-original.svg" width="40" alt="@Model.Review.Language"></span>
|
PENDING
|
||||||
break;
|
</button>
|
||||||
case "c":
|
|
||||||
<span><img class="mx-1" src="~/icons/c-original.svg" width="40" alt="@Model.Review.Language"></span>
|
|
||||||
break;
|
|
||||||
case "c++":
|
|
||||||
<span><img class="mx-1" src="~/icons/cplusplus-original.svg" width="40" alt="@Model.Review.Language"></span>
|
|
||||||
break;
|
|
||||||
case "go":
|
|
||||||
<span><img class="mx-1" src="~/icons/go-original.svg" width="40" alt="@Model.Review.Language"></span>
|
|
||||||
break;
|
|
||||||
case "java":
|
|
||||||
<span><img class="mx-1" src="~/icons/java-original.svg" width="40" alt="@Model.Review.Language"></span>
|
|
||||||
break;
|
|
||||||
case "swift":
|
|
||||||
<span><img class="mx-1" src="~/icons/swift-original.svg" width="40" alt="@Model.Review.Language"></span>
|
|
||||||
break;
|
|
||||||
case "kotlin":
|
|
||||||
<span><img class="mx-1" src="~/icons/kotlin-original.svg" width="40" alt="@Model.Review.Language"></span>
|
|
||||||
break;
|
|
||||||
case "json":
|
|
||||||
<span><img class="mx-1" src="~/icons/json-original.svg" width="40" alt="@Model.Review.Language"></span>
|
|
||||||
break;
|
|
||||||
case "swagger":
|
|
||||||
<span><img class="mx-1" src="~/icons/swagger-original.svg" width="40" alt="@Model.Review.Language"></span>
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
<span class="badge badge-info"><em>@Model.Review.Language</em></span>
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1">
|
|
||||||
<div class="col-lg-6 my-1">
|
|
||||||
<div class="row no-gutters">
|
|
||||||
<div class="col-md-4 mt-1 p-0 mr-md-1">
|
|
||||||
<div class="input-group input-group-sm m-0 p-0 shadow-sm" id="review-select-box">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<label class="input-group-text" for="review-bootstraps-select">Review</label>
|
|
||||||
</div>
|
|
||||||
<select class="selectpicker show-tick p-0" data-style="btn-light btn-sm border rounded-left-0 m-0" data-live-search="true" data-size="10" data-width="calc(100% - 60px)" data-container="body" id="review-bootstraps-select">
|
|
||||||
@foreach(var review in Model.ReviewsForPackage)
|
|
||||||
{
|
|
||||||
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
|
||||||
id = review.ReviewId
|
|
||||||
});
|
|
||||||
if (review.ReviewId == Model.Review.ReviewId)
|
|
||||||
{
|
|
||||||
<option selected value="@urlValue" data-subtext="Type: @review.FilterType | Language: @review.Language | Author: @review.Author">@review.DisplayName</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@urlValue" data-subtext="Type: @review.FilterType | Language: @review.Language | Author: @review.Author">@review.DisplayName</option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4 mt-1 p-0 mx-md-1">
|
|
||||||
<div class="input-group input-group-sm m-0 p-0 shadow-sm" id="revision-select-box">
|
|
||||||
<div class="input-group-prepend">
|
|
||||||
<label class="input-group-text" for="revisions-bootstraps-select">Revision</label>
|
|
||||||
</div>
|
|
||||||
<select class="selectpicker show-tick p-0" data-style="btn-light btn-sm border rounded-left-0 m-0" data-live-search="true" data-size="10" data-width="calc(100% - 68px)" data-container="body" id="revisions-bootstraps-select">
|
|
||||||
@foreach (var revision in Model.Review.Revisions.Reverse())
|
|
||||||
{
|
|
||||||
var approvedBadge = "<i class='fas fa-check-circle text-success ml-2'></i>";
|
|
||||||
var optionName = revision.IsApproved ? $"{@revision.DisplayName} {@approvedBadge}" : @revision.DisplayName;
|
|
||||||
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
|
||||||
id = @Model.Review.ReviewId,
|
|
||||||
revisionId = @revision.RevisionId,
|
|
||||||
doc = @Model.ShowDocumentation
|
|
||||||
});
|
|
||||||
if (@revision.DisplayName == @Model.Revision.DisplayName)
|
|
||||||
{
|
|
||||||
<option selected value="@urlValue" data-content="@optionName"></option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@urlValue" data-content="@optionName"></option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3 mt-1 p-0 ml-md-1">
|
|
||||||
@if (@Model.PreviousRevisions.Any())
|
|
||||||
{
|
|
||||||
<div class="input-group input-group-sm m-0 p-0 shadow-sm" id="diff-select-box">
|
|
||||||
<div class="input-group-prepend" for="diff-bootstraps-select">
|
|
||||||
@if (Model.DiffRevisionId != null)
|
|
||||||
{
|
|
||||||
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
|
||||||
id = @Model.Review.ReviewId,
|
|
||||||
revisionId = @Model.Revision.RevisionId,
|
|
||||||
diffRevisionId = @Model.DiffRevisionId,
|
|
||||||
doc = @Model.ShowDocumentation,
|
|
||||||
diffOnly = @Model.ShowDiffOnly
|
|
||||||
});
|
|
||||||
<button class="btn btn-outline-secondary diff-button" type="button" value="@urlValue" aria-label="Diff Button">Diff</button>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
|
||||||
id = @Model.Review.ReviewId,
|
|
||||||
revisionId = @Model.Revision.RevisionId,
|
|
||||||
diffRevisionId = @Model.PreviousRevisions.Last().RevisionId,
|
|
||||||
doc = @Model.ShowDocumentation,
|
|
||||||
diffOnly = @Model.ShowDiffOnly
|
|
||||||
});
|
|
||||||
<button class="btn btn-outline-secondary diff-button" type="button" value="@urlValue" aria-label="Diff Button">Diff</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<select class="selectpicker show-tick" data-style="btn-light btn-sm border border-left rounded-left-0" data-size="10" data-width="calc(100% - 39px)" data-live-search="true" data-container="body" aria-label="Diff Review" id="diff-bootstraps-select">
|
|
||||||
if (@Model.DiffRevisionId == null)
|
|
||||||
{
|
|
||||||
<option value="" selected></option>
|
|
||||||
}
|
|
||||||
@foreach (var revision in Model.PreviousRevisions.Reverse())
|
|
||||||
{
|
|
||||||
var approvedBadge = "<span class='badge badge-pill badge-success ml-1 p-1'><i class='fas fa-check-circle'></i> APPROVED</span>";
|
|
||||||
var optionName = revision.IsApproved ? $"{@revision.DisplayName} {@approvedBadge}" : @revision.DisplayName;
|
|
||||||
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
|
||||||
id = @Model.Review.ReviewId,
|
|
||||||
diffRevisionId = @revision.RevisionId,
|
|
||||||
doc = @Model.ShowDocumentation,
|
|
||||||
diffOnly = @Model.ShowDiffOnly,
|
|
||||||
revisionId = @Model.Revision.RevisionId
|
|
||||||
});
|
|
||||||
if (@Model.DiffRevisionId != null)
|
|
||||||
{
|
|
||||||
if (@Model.DiffRevisionId == @revision.RevisionId)
|
|
||||||
{
|
|
||||||
<option value="@urlValue" selected data-content="@optionName"></option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@urlValue" data-content="@optionName"></option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (@Model.DiffRevisionId != @revision.RevisionId)
|
|
||||||
{
|
|
||||||
<option value="@urlValue" data-content="@optionName"></option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="my-1 ml-2">
|
||||||
<div class="col-lg-6 my-1">
|
@{
|
||||||
@if (Model.Review.FilterType != ReviewType.Automatic)
|
var popOverContent = $"<b>{Model.ActiveConversations}</b> active revision threads.<br><b>{Model.TotalActiveConversations}</b> total active threads.<br>"
|
||||||
{
|
+ $"<b>Current Revision:</b> <em>{@Model.Revision.DisplayName}</em>";
|
||||||
<div class="float-right ml-2 my-1">
|
@if (Model.DiffRevisionId != null)
|
||||||
<form asp-resource="@Model.Review" class="form-inline" method="post" asp-page-handler="ToggleClosed">
|
|
||||||
@if (Model.Review.IsClosed)
|
|
||||||
{
|
|
||||||
<button type="submit" class="btn btn-sm border shadow-sm btn-light">
|
|
||||||
<i class="fa fa-sm fa-undo" aria-hidden="true"></i> Reopen
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<button type="submit" class="btn btn-sm border shadow-sm btn-light">
|
|
||||||
<i class="far fa-window-close" aria-hidden="true"></i> Close
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="float-right ml-2 my-1">
|
|
||||||
<form asp-resource="@Model.Review" class="form-inline" method="post" asp-page-handler="ToggleSubscribed">
|
|
||||||
@if (Model.Review.GetUserEmail(User) != null)
|
|
||||||
{
|
{
|
||||||
if (Model.Review.IsUserSubscribed(User))
|
popOverContent += $"<br><b>Current Diff:</b> <em>{@Model.DiffRevision?.DisplayName}</em>";
|
||||||
{
|
|
||||||
<button type="submit" class="btn border btn-sm shadow-sm btn-light">
|
|
||||||
<i class="far fa-minus-square" aria-hidden="true"></i> Unsubscribe
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<button type="submit" class="btn border btn-sm shadow-sm btn-light">
|
|
||||||
<i class="far fa-plus-square" aria-hidden="true"></i> Subscribe
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
<button type="button" class="btn btn-info btn-sm shadow-sm" data-placement="bottom" data-trigger="focus" data-toggle="popover" data-html="true" data-title="Page Info" data-content="@popOverContent">
|
||||||
{
|
<i class="far fa-comment-alt mr-2"></i><span class="badge badge-light">@Model.ActiveConversations / @Model.TotalActiveConversations</span>
|
||||||
<button type="submit" class="btn btn-sm shadow-sm btn-light" disabled data-placement="bottom" data-toggle="tooltip" title="Link a microsoft.com email to your Github account to subscribe">
|
</button>
|
||||||
<i class="fa fa-plus-square" aria-hidden="true"></i> Subscribe
|
}
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown d-inline-block float-right ml-2 my-1">
|
<div class="my-1">
|
||||||
<a class="btn btn-light btn-sm border shadow-sm dropdown-toggle" href="#" role="button" data-toggle="dropdown">
|
|
||||||
<i class="fas fa-sm fa-sliders-h"></i> Options
|
|
||||||
</a>
|
|
||||||
<div class="dropdown-menu dropdown-menu-right">
|
|
||||||
<span class="dropdown-item checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" checked="checked" id="show-comments-checkbox">
|
|
||||||
Show Comments
|
|
||||||
</label>
|
|
||||||
</span>
|
|
||||||
<span class="dropdown-item checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" checked="checked" id="show-system-comments-checkbox">
|
|
||||||
Show System Comments
|
|
||||||
</label>
|
|
||||||
</span>
|
|
||||||
<span class="dropdown-item" id="show-documentation-component">
|
|
||||||
<input asp-for="@Model.ShowDocumentation" class="show-doc-checkbox">
|
|
||||||
<a class="text-dark show-document" asp-all-route-data=@Model.GetRoutingData(diffRevisionId: Model.DiffRevisionId, showDocumentation: !Model.ShowDocumentation, showDiffOnly: Model.ShowDiffOnly, revisionId: Model.Revision.RevisionId)>
|
|
||||||
<label> Show Documentation</label>
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
<span class="dropdown-item checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="hide-line-numbers">
|
|
||||||
Hide Line Number
|
|
||||||
</label>
|
|
||||||
</span>
|
|
||||||
@if (!String.IsNullOrEmpty(Model.DiffRevisionId))
|
|
||||||
{
|
|
||||||
<span class="dropdown-item">
|
|
||||||
<input asp-for="@Model.ShowDiffOnly" class="show-diffonly-checkbox">
|
|
||||||
<a class="text-dark show-diffonly" asp-all-route-data=@Model.GetRoutingData(diffRevisionId: Model.DiffRevisionId, showDocumentation: Model.ShowDocumentation, showDiffOnly: !Model.ShowDiffOnly, revisionId: Model.Revision.RevisionId)>
|
|
||||||
<label> Show Only Diff</label>
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="float-right my-1">
|
|
||||||
<form asp-resource="@Model.Review" class="form-inline" asp-page-handler="ToggleApproval" method="post" asp-requirement="@ApproverRequirement.Instance">
|
<form asp-resource="@Model.Review" class="form-inline" asp-page-handler="ToggleApproval" method="post" asp-requirement="@ApproverRequirement.Instance">
|
||||||
<input type="hidden" name="revisionId" value="@Model.Revision.RevisionId" />
|
<input type="hidden" name="revisionId" value="@Model.Revision.RevisionId" />
|
||||||
@if (Model.DiffRevision == null || Model.DiffRevision.Approvers.Count > 0)
|
@if (Model.DiffRevision == null || Model.DiffRevision.Approvers.Count > 0)
|
||||||
|
@ -302,39 +128,237 @@
|
||||||
}
|
}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="float-right ml-2 my-1">
|
<div class="dropdown d-inline-block my-1 ml-2">
|
||||||
@{
|
<a class="btn btn-light btn-sm border shadow-sm dropdown-toggle" href="#" role="button" data-toggle="dropdown">
|
||||||
var popOverContent = $"<b>{Model.ActiveConversations}</b> active revision threads.<br><b>{Model.TotalActiveConversations}</b> total active threads.<br>"
|
<i class="fas fa-sm fa-sliders-h"></i> Options
|
||||||
+ $"<b>Current Revision:</b> <em>{@Model.Revision.DisplayName}</em>";
|
</a>
|
||||||
@if (Model.DiffRevisionId != null)
|
<div class="dropdown-menu dropdown-menu-right">
|
||||||
|
<span class="dropdown-item checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" checked="checked" id="show-comments-checkbox">
|
||||||
|
Show Comments
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<span class="dropdown-item checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" checked="checked" id="show-system-comments-checkbox">
|
||||||
|
Show System Comments
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<span class="dropdown-item" id="show-documentation-component">
|
||||||
|
<input asp-for="@Model.ShowDocumentation" class="show-doc-checkbox">
|
||||||
|
<a class="text-dark show-document" asp-all-route-data=@Model.GetRoutingData(diffRevisionId: Model.DiffRevisionId, showDocumentation: !Model.ShowDocumentation, showDiffOnly: Model.ShowDiffOnly, revisionId: Model.Revision.RevisionId)>
|
||||||
|
<label> Show Documentation</label>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<span class="dropdown-item checkbox">
|
||||||
|
<label>
|
||||||
|
@if (Model.GetUserPreference().HideLineNumbers == true)
|
||||||
|
{
|
||||||
|
<input type="checkbox" id="hide-line-numbers" checked>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input type="checkbox" id="hide-line-numbers" >
|
||||||
|
}
|
||||||
|
Hide Line Number
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<span class="dropdown-item checkbox">
|
||||||
|
<label>
|
||||||
|
@if (Model.GetUserPreference().HideLeftNavigation == true)
|
||||||
|
{
|
||||||
|
<input type="checkbox" id="hide-left-navigation" checked>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input type="checkbox" id="hide-left-navigation">
|
||||||
|
}
|
||||||
|
Hide Left Navigation
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
@if (!String.IsNullOrEmpty(Model.DiffRevisionId))
|
||||||
{
|
{
|
||||||
popOverContent += $"<br><b>Current Diff:</b> <em>{@Model.DiffRevision?.DisplayName}</em>";
|
<span class="dropdown-item">
|
||||||
|
<input asp-for="@Model.ShowDiffOnly" class="show-diffonly-checkbox">
|
||||||
|
<a class="text-dark show-diffonly" asp-all-route-data=@Model.GetRoutingData(diffRevisionId: Model.DiffRevisionId, showDocumentation: Model.ShowDocumentation, showDiffOnly: !Model.ShowDiffOnly, revisionId: Model.Revision.RevisionId)>
|
||||||
|
<label> Show Only Diff</label>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
<button type="button" class="btn btn-info btn-sm shadow-sm" data-placement="bottom" data-trigger="focus" data-toggle="popover" data-html="true" data-title="Page Info" data-content="@popOverContent">
|
</div>
|
||||||
<i class="far fa-comment-alt mr-2"></i><span class="badge badge-light">@Model.ActiveConversations / @Model.TotalActiveConversations</span>
|
</div>
|
||||||
|
<div class="my-1 ml-2">
|
||||||
|
<form asp-resource="@Model.Review" class="form-inline" method="post" asp-page-handler="ToggleSubscribed">
|
||||||
|
@if (Model.Review.GetUserEmail(User) != null)
|
||||||
|
{
|
||||||
|
if (Model.Review.IsUserSubscribed(User))
|
||||||
|
{
|
||||||
|
<button type="submit" class="btn border btn-sm shadow-sm btn-light">
|
||||||
|
<i class="far fa-minus-square" aria-hidden="true"></i> Unsubscribe
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="submit" class="btn border btn-sm shadow-sm btn-light">
|
||||||
|
<i class="far fa-plus-square" aria-hidden="true"></i> Subscribe
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="submit" class="btn btn-sm shadow-sm btn-light" disabled data-placement="bottom" data-toggle="tooltip" title="Link a microsoft.com email to your Github account to subscribe">
|
||||||
|
<i class="fa fa-plus-square" aria-hidden="true"></i> Subscribe
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</div>
|
</form>
|
||||||
<div class="float-right ml-2 my-1">
|
|
||||||
@if (Model.Revision.Approvers.Count > 0)
|
|
||||||
{
|
|
||||||
var approvers = String.Join(", ", Model.Revision.Approvers);
|
|
||||||
<button type="button" class="btn btn-sm shadow-sm btn-success" data-placement="bottom" data-trigger="focus" data-toggle="popover" data-title="Approvers" data-content="@approvers">
|
|
||||||
<i class="fas fa-check-circle"></i> APPROVED
|
|
||||||
<span class="badge badge-light">@Model.Revision.Approvers.Count</span>
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-light btn-sm shadow-sm">
|
|
||||||
PENDING
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
@if (Model.Review.FilterType != ReviewType.Automatic)
|
||||||
|
{
|
||||||
|
<div class="my-1 ml-2">
|
||||||
|
<form asp-resource="@Model.Review" class="form-inline" method="post" asp-page-handler="ToggleClosed">
|
||||||
|
@if (Model.Review.IsClosed)
|
||||||
|
{
|
||||||
|
<button type="submit" class="btn btn-sm border shadow-sm btn-light">
|
||||||
|
<i class="fa fa-sm fa-undo" aria-hidden="true"></i> Reopen
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="submit" class="btn btn-sm border shadow-sm btn-light">
|
||||||
|
<i class="far fa-window-close" aria-hidden="true"></i> Close
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mx-1 px-0 pt-0 pb-2">
|
||||||
|
<form>
|
||||||
|
<div class="form-row">
|
||||||
|
@* Hide until tags is implemented
|
||||||
|
<div class="form-group col-md-4 mb-0">
|
||||||
|
<label class="mb-0 ml-1"><small>REVIEW:</small></label>
|
||||||
|
<select class="selectpicker show-tick show-menu-arrow shadow-sm" data-style="btn-light btn-sm border" data-selected-text-format="value" data-live-search="true" data-size="10" data-width="100%" data-container="body" id="review-bootstraps-select" data-tick-icon="fa-solid fa-check">
|
||||||
|
@foreach(var review in Model.ReviewsForPackage)
|
||||||
|
{
|
||||||
|
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
||||||
|
id = review.ReviewId
|
||||||
|
});
|
||||||
|
if (review.ReviewId == Model.Review.ReviewId)
|
||||||
|
{
|
||||||
|
<option selected style="font-size: 0.8em;" value="@urlValue" data-subtext="Type: @review.FilterType | Language: @review.Language | Author: @review.Author">@review.DisplayName</option>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<option style="font-size: 0.8em;" value="@urlValue" data-subtext="Type: @review.FilterType | Language: @review.Language | Author: @review.Author">@review.DisplayName</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
*@
|
||||||
|
<div class="form-group col-md-6 mb-0">
|
||||||
|
<label class="mb-0 ml-1"><small>REVISION:</small></label>
|
||||||
|
<select class="selectpicker show-tick show-menu-arrow shadow-sm" data-style="btn-light btn-sm border" data-selected-text-format="value" data-live-search="true" data-size="10" data-width="100%" data-container="body" id="revisions-bootstraps-select" data-tick-icon="fa-solid fa-check">
|
||||||
|
@foreach (var revision in Model.Review.Revisions.Reverse())
|
||||||
|
{
|
||||||
|
var approvedBadge = "<i class='fas fa-check-circle text-success ml-2'></i>";
|
||||||
|
var optionName = revision.IsApproved ? $"{@revision.DisplayName} {@approvedBadge}" : @revision.DisplayName;
|
||||||
|
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
||||||
|
id = @Model.Review.ReviewId,
|
||||||
|
revisionId = @revision.RevisionId,
|
||||||
|
doc = @Model.ShowDocumentation
|
||||||
|
});
|
||||||
|
if (@revision.DisplayName == @Model.Revision.DisplayName)
|
||||||
|
{
|
||||||
|
<option selected style="font-size: 0.8em;" value="@urlValue" data-content="@optionName"></option>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<option style="font-size: 0.8em;" value="@urlValue" data-content="@optionName"></option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-6 mb-0">
|
||||||
|
@if (@Model.PreviousRevisions.Any())
|
||||||
|
{
|
||||||
|
@if (Model.DiffRevisionId != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
||||||
|
id = @Model.Review.ReviewId,
|
||||||
|
revisionId = @Model.Revision.RevisionId,
|
||||||
|
diffRevisionId = @Model.DiffRevisionId,
|
||||||
|
doc = @Model.ShowDocumentation,
|
||||||
|
diffOnly = @Model.ShowDiffOnly
|
||||||
|
});
|
||||||
|
<label class="mb-0 ml-1"><a href="@urlValue"><small>DIFF WITH:</small></a></label>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
||||||
|
id = @Model.Review.ReviewId,
|
||||||
|
revisionId = @Model.Revision.RevisionId,
|
||||||
|
diffRevisionId = @Model.PreviousRevisions.Last().RevisionId,
|
||||||
|
doc = @Model.ShowDocumentation,
|
||||||
|
diffOnly = @Model.ShowDiffOnly
|
||||||
|
});
|
||||||
|
<label class="mb-0 ml-1"><a href="@urlValue"><small>DIFF:</small></a></label>
|
||||||
|
}
|
||||||
|
<select class="selectpicker show-tick show-menu-arrow shadow-sm" data-style="btn-light btn-sm border border-left" data-size="10" data-width="100%" data-live-search="true" data-container="body" aria-label="Diff Review" id="diff-bootstraps-select" data-tick-icon="fa-solid fa-check">
|
||||||
|
if (@Model.DiffRevisionId == null)
|
||||||
|
{
|
||||||
|
<option style="font-size: 0.8em;" value="" selected></option>
|
||||||
|
}
|
||||||
|
@foreach (var revision in Model.PreviousRevisions.Reverse())
|
||||||
|
{
|
||||||
|
var approvedBadge = "<i class='fas fa-check-circle text-success ml-2'></i>";
|
||||||
|
var optionName = revision.IsApproved ? $"{@revision.DisplayName} {@approvedBadge}" : @revision.DisplayName;
|
||||||
|
var urlValue = @Url.ActionLink("Review", "Assemblies", new {
|
||||||
|
id = @Model.Review.ReviewId,
|
||||||
|
diffRevisionId = @revision.RevisionId,
|
||||||
|
doc = @Model.ShowDocumentation,
|
||||||
|
diffOnly = @Model.ShowDiffOnly,
|
||||||
|
revisionId = @Model.Revision.RevisionId
|
||||||
|
});
|
||||||
|
if (@Model.DiffRevisionId != null)
|
||||||
|
{
|
||||||
|
if (@Model.DiffRevisionId == @revision.RevisionId)
|
||||||
|
{
|
||||||
|
<option style="font-size: 0.8em;" value="@urlValue" selected data-content="@optionName"></option>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<option style="font-size: 0.8em;" value="@urlValue" data-content="@optionName"></option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (@Model.DiffRevisionId != @revision.RevisionId)
|
||||||
|
{
|
||||||
|
<option style="font-size: 0.8em;" value="@urlValue" data-content="@optionName"></option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
<div class="row px-3" data-review-id="@Model.Review.ReviewId" data-revision-id="@Model.Revision.RevisionId" data-language="@Model.Review.Language">
|
<div class="row px-3" data-review-id="@Model.Review.ReviewId" data-revision-id="@Model.Revision.RevisionId" data-language="@Model.Review.Language">
|
||||||
<div id="review-left" class="col-2 rounded-1 border">
|
@{
|
||||||
|
var reviewLeftDisplay = String.Empty;
|
||||||
|
var reviewRightSize = "10";
|
||||||
|
if (Model.GetUserPreference().HideLeftNavigation == true)
|
||||||
|
{
|
||||||
|
reviewLeftDisplay = "d-none";
|
||||||
|
reviewRightSize = "12";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<div id="review-left" class="col-2 rounded-1 border @reviewLeftDisplay">
|
||||||
<div class="namespace-view">
|
<div class="namespace-view">
|
||||||
@if (Model.CodeFile != null)
|
@if (Model.CodeFile != null)
|
||||||
{
|
{
|
||||||
|
@ -343,9 +367,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="review-right" class="col-10 rounded-1 border">
|
<div id="review-right" class="col-@reviewRightSize rounded-1 border">
|
||||||
<table class="code-window">
|
<table class="code-window">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@{
|
||||||
|
TempData["UserPreference"] = Model.GetUserPreference();
|
||||||
|
}
|
||||||
@foreach (var line in Model.Lines)
|
@foreach (var line in Model.Lines)
|
||||||
{
|
{
|
||||||
<partial name="_CodeLine" model="@line" />
|
<partial name="_CodeLine" model="@line" />
|
||||||
|
|
|
@ -239,6 +239,17 @@ namespace APIViewWeb.Pages.Assemblies
|
||||||
await _manager.ToggleApprovalAsync(User, id, revisionId);
|
await _manager.ToggleApprovalAsync(User, id, revisionId);
|
||||||
return RedirectToPage(new { id = id });
|
return RedirectToPage(new { id = id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IActionResult OnGetUpdatePageSettings(bool hideLineNumbers = false, bool hideLeftNavigation = false)
|
||||||
|
{
|
||||||
|
_preferenceCache.UpdateUserPreference(new UserPreferenceModel() {
|
||||||
|
UserName = User.GetGitHubLogin(),
|
||||||
|
HideLeftNavigation = hideLeftNavigation,
|
||||||
|
HideLineNumbers = hideLineNumbers
|
||||||
|
});
|
||||||
|
return new EmptyResult();
|
||||||
|
}
|
||||||
|
|
||||||
public Dictionary<string, string> GetRoutingData(string diffRevisionId = null, bool? showDocumentation = null, bool? showDiffOnly = null, string revisionId = null)
|
public Dictionary<string, string> GetRoutingData(string diffRevisionId = null, bool? showDocumentation = null, bool? showDiffOnly = null, string revisionId = null)
|
||||||
{
|
{
|
||||||
var routingData = new Dictionary<string, string>();
|
var routingData = new Dictionary<string, string>();
|
||||||
|
@ -248,5 +259,10 @@ namespace APIViewWeb.Pages.Assemblies
|
||||||
routingData["diffOnly"] = (showDiffOnly ?? false).ToString();
|
routingData["diffOnly"] = (showDiffOnly ?? false).ToString();
|
||||||
return routingData;
|
return routingData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UserPreferenceModel GetUserPreference()
|
||||||
|
{
|
||||||
|
return _preferenceCache.GetUserPreferences(User.GetGitHubLogin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
@using ApiView
|
@using ApiView
|
||||||
@using APIView.DIff
|
@using APIView.DIff
|
||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
|
@using APIViewWeb.Models;
|
||||||
@model APIViewWeb.Models.CodeLineModel
|
@model APIViewWeb.Models.CodeLineModel
|
||||||
@{
|
@{
|
||||||
bool isRemoved = Model.Kind == DiffLineKind.Removed;
|
bool isRemoved = Model.Kind == DiffLineKind.Removed;
|
||||||
|
@ -22,14 +23,23 @@
|
||||||
isContent = foldableClassParts.Any(x => x.EndsWith("-content"));
|
isContent = foldableClassParts.Any(x => x.EndsWith("-content"));
|
||||||
hiddenSectionClass = isContent ? "d-none" : "";
|
hiddenSectionClass = isContent ? "d-none" : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var userPreference = TempData["UserPreference"] as UserPreferenceModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
<tr class="code-line @lineClass @foldableClass @hiddenSectionClass" data-line-id="@(isRemoved ? string.Empty : Model.CodeLine.ElementId)">
|
<tr class="code-line @lineClass @foldableClass @hiddenSectionClass" data-line-id="@(isRemoved ? string.Empty : Model.CodeLine.ElementId)">
|
||||||
<td class="line-details">
|
<td class="line-details">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="line-number @lineClass"><span>@Model.LineNumber</span></td>
|
@if(userPreference.HideLineNumbers == true)
|
||||||
<td class="line-details-button-cell">
|
{
|
||||||
|
<td class="line-number @lineClass d-none"><span>@Model.LineNumber</span></td>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<td class="line-number @lineClass"><span>@Model.LineNumber</span></td>
|
||||||
|
}
|
||||||
|
<td class="line-details-button-cell @lineClass">
|
||||||
@if (!isRemoved && Model.CodeLine.ElementId != null)
|
@if (!isRemoved && Model.CodeLine.ElementId != null)
|
||||||
{
|
{
|
||||||
<a class="line-comment-button">+</a>
|
<a class="line-comment-button">+</a>
|
||||||
|
@ -39,7 +49,7 @@
|
||||||
<a class="line-comment-button" style="visibility: hidden;">+</a> // Added for visual consistency
|
<a class="line-comment-button" style="visibility: hidden;">+</a> // Added for visual consistency
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td class="line-details-button-cell">
|
<td class="line-details-button-cell @lineClass">
|
||||||
@if (isHeading)
|
@if (isHeading)
|
||||||
{
|
{
|
||||||
<span class="row-fold-caret"><i class="fa-solid fa-angle-right"></i></span>
|
<span class="row-fold-caret"><i class="fa-solid fa-angle-right"></i></span>
|
||||||
|
|
|
@ -3,21 +3,42 @@ using Microsoft.Extensions.Caching.Memory;
|
||||||
using APIViewWeb.Models;
|
using APIViewWeb.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
namespace APIViewWeb.Repositories
|
namespace APIViewWeb.Repositories
|
||||||
{
|
{
|
||||||
public class UserPreferenceCache
|
public class UserPreferenceCache
|
||||||
{
|
{
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
public UserPreferenceCache(IMemoryCache cache)
|
public UserPreferenceCache(IMemoryCache cache, IMapper mapper)
|
||||||
{
|
{
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
|
_mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateUserPreference(UserPreferenceModel preference)
|
public void UpdateUserPreference(UserPreferenceModel preference)
|
||||||
{
|
{
|
||||||
_cache.Set(preference.UserName, preference);
|
UserPreferenceModel existingPreference = GetUserPreferences(preference.UserName);
|
||||||
|
if (existingPreference == null)
|
||||||
|
{
|
||||||
|
_cache.Set(preference.UserName, preference);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_mapper.Map<UserPreferenceModel, UserPreferenceModel>(preference, existingPreference);
|
||||||
|
_cache.Set(preference.UserName, existingPreference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserPreferenceModel GetUserPreferences(string userName)
|
||||||
|
{
|
||||||
|
if (_cache.TryGetValue(userName, out UserPreferenceModel _preference))
|
||||||
|
{
|
||||||
|
return _preference;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<string> GetLangauge(string userName)
|
public IEnumerable<string> GetLangauge(string userName)
|
||||||
|
|
|
@ -194,6 +194,7 @@ namespace APIViewWeb
|
||||||
services.AddSingleton<IAuthorizationHandler, PullRequestPermissionRequirementHandler>();
|
services.AddSingleton<IAuthorizationHandler, PullRequestPermissionRequirementHandler>();
|
||||||
services.AddHostedService<ReviewBackgroundHostedService>();
|
services.AddHostedService<ReviewBackgroundHostedService>();
|
||||||
services.AddHostedService<PullRequestBackgroundHostedService>();
|
services.AddHostedService<PullRequestBackgroundHostedService>();
|
||||||
|
services.AddAutoMapper(Assembly.GetExecutingAssembly());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> GetMicrosoftEmailAsync(OAuthCreatingTicketContext context)
|
private static async Task<string> GetMicrosoftEmailAsync(OAuthCreatingTicketContext context)
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Загрузка…
Ссылка в новой задаче