From 3b38c6b216c5c41425d2a3c00fdba9b5e5629316 Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Fri, 18 Jun 2021 10:51:22 +0100 Subject: [PATCH 01/10] HEEDLS-467 Add Contract Details page --- .../DataServices/CentresDataService.cs | 5 +- .../Models/Centre.cs | 3 + .../ContractDetailsController.cs | 35 +++++ .../Helpers/DisplayStringHelper.cs | 33 +++++ .../trackingSystem/contractDetails.scss | 23 +++ .../Common/NumberOfAdministratorsViewModel.cs | 35 +++-- .../ContractDetailsViewModel.cs | 116 +++++++++++++++ .../Centre/ContractDetails/Index.cshtml | 139 ++++++++++++++++++ .../_DashboardBottomCardGroup.cshtml | 2 +- 9 files changed, 374 insertions(+), 17 deletions(-) create mode 100644 DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs create mode 100644 DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs create mode 100644 DigitalLearningSolutions.Web/Styles/trackingSystem/contractDetails.scss create mode 100644 DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs create mode 100644 DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml diff --git a/DigitalLearningSolutions.Data/DataServices/CentresDataService.cs b/DigitalLearningSolutions.Data/DataServices/CentresDataService.cs index 403b3e5940..d726edbe0f 100644 --- a/DigitalLearningSolutions.Data/DataServices/CentresDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CentresDataService.cs @@ -129,7 +129,10 @@ ORDER BY CentreName" c.CCLicences AS CcLicenceSpots, c.Trainers AS TrainerSpots, c.IPPrefix, - ct.ContractType + ct.ContractType, + c.CustomCourses, + c.ServerSpaceUsed, + c.ServerSpaceBytes FROM Centres AS c INNER JOIN Regions AS r ON r.RegionID = c.RegionID INNER JOIN ContractTypes as ct on ct.ContractTypeID = c.ContractTypeId diff --git a/DigitalLearningSolutions.Data/Models/Centre.cs b/DigitalLearningSolutions.Data/Models/Centre.cs index a232b26305..f0d7a7fcea 100644 --- a/DigitalLearningSolutions.Data/Models/Centre.cs +++ b/DigitalLearningSolutions.Data/Models/Centre.cs @@ -31,5 +31,8 @@ public class Centre public int TrainerSpots { get; set; } public string? IpPrefix { get; set; } public string? ContractType { get; set; } + public int CustomCourses { get; set; } + public long ServerSpaceUsed { get; set; } + public long ServerSpaceBytes { get; set; } } } diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs new file mode 100644 index 0000000000..8aa6592c99 --- /dev/null +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs @@ -0,0 +1,35 @@ +namespace DigitalLearningSolutions.Web.Controllers.TrackingSystem.Centre.ContractDetails +{ + using DigitalLearningSolutions.Data.DataServices; + using DigitalLearningSolutions.Data.Services; + using DigitalLearningSolutions.Web.Helpers; + using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.ContractDetails; + using Microsoft.AspNetCore.Authorization; + using Microsoft.AspNetCore.Mvc; + + [Authorize(Policy = CustomPolicies.UserCentreAdmin)] + [Route("/TrackingSystem/Centre/ContractDetails")] + public class ContractDetailsController : Controller + { + private readonly ICentresDataService centresDataService; + private readonly IUserDataService userDataService; + private readonly ICourseService courseService; + + public ContractDetailsController(ICentresDataService centresDataService, IUserDataService userDataService, ICourseService courseService) + { + this.centresDataService = centresDataService; + this.userDataService = userDataService; + this.courseService = courseService; + } + + public IActionResult Index() + { + int centreId = User.GetCentreId(); + var centreDetails = centresDataService.GetCentreDetailsById(centreId)!; + var adminUsersAtCentre = userDataService.GetAdminUsersByCentreId(centreId); + var numberOfCourses = courseService.GetNumberOfActiveCoursesAtCentreForCategory(centreId, 0); + + return View(new ContractDetailsViewModel(adminUsersAtCentre, centreDetails, numberOfCourses)); + } + } +} diff --git a/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs b/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs new file mode 100644 index 0000000000..a3d8657ae1 --- /dev/null +++ b/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs @@ -0,0 +1,33 @@ +namespace DigitalLearningSolutions.Web.Helpers +{ + using System; + + public static class DisplayStringHelper + { + private const string Divider = " / "; + + public static string GenerateNumberWithLimitDisplayString(int number, int limit) + { + return limit == -1 ? number.ToString() : number + Divider + limit; + } + + public static string GenerateBytesLimitDisplayString(long number, long limit) + { + return GenerateBytesDisplayString(number) + Divider + GenerateBytesDisplayString(limit); + } + + private static string GenerateBytesDisplayString(long byteCount) + { + var units = new[] { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" }; + if (byteCount == 0) + { + return 0 + units[0]; + } + + var bytes = Math.Abs(byteCount); + var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024))); + var number = Math.Round(bytes / Math.Pow(1024, place), 1); + return (Math.Sign(byteCount) * number) + units[place]; + } + } +} diff --git a/DigitalLearningSolutions.Web/Styles/trackingSystem/contractDetails.scss b/DigitalLearningSolutions.Web/Styles/trackingSystem/contractDetails.scss new file mode 100644 index 0000000000..bf78695da2 --- /dev/null +++ b/DigitalLearningSolutions.Web/Styles/trackingSystem/contractDetails.scss @@ -0,0 +1,23 @@ +@import "~nhsuk-frontend/packages/core/all"; + +.coloured-card-number { + &--blue { + color: $color_nhsuk-blue; + } + + &--green { + color: $color_nhsuk-green; + } + + &--yellow { + color: #d97f00; + } + + &--red { + color: $color_nhsuk-red; + } + + &--grey { + color: $color_nhsuk-grey-1; + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/Common/NumberOfAdministratorsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Common/NumberOfAdministratorsViewModel.cs index 20c92433fb..714af9f08d 100644 --- a/DigitalLearningSolutions.Web/ViewModels/Common/NumberOfAdministratorsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/Common/NumberOfAdministratorsViewModel.cs @@ -4,16 +4,10 @@ using System.Linq; using DigitalLearningSolutions.Data.Models; using DigitalLearningSolutions.Data.Models.User; + using DigitalLearningSolutions.Web.Helpers; public class NumberOfAdministratorsViewModel { - public string Admins { get; set; } - public string Supervisors { get; set; } - public string Trainers { get; set; } - public string CmsAdministrators { get; set; } - public string CmsManagers { get; set; } - public string CcLicences { get; set; } - public NumberOfAdministratorsViewModel(Centre centreDetails, List adminUsers) { Admins = adminUsers.Count(a => a.IsCentreAdmin).ToString(); @@ -24,15 +18,26 @@ public NumberOfAdministratorsViewModel(Centre centreDetails, List adm var cmsManagers = adminUsers.Count(a => a.IsContentManager) - cmsAdministrators; var ccLicences = adminUsers.Count(a => a.IsContentCreator); - Trainers = GenerateDisplayString(trainers, centreDetails.TrainerSpots); - CmsAdministrators = GenerateDisplayString(cmsAdministrators, centreDetails.CmsAdministratorSpots); - CmsManagers = GenerateDisplayString(cmsManagers, centreDetails.CmsManagerSpots); - CcLicences = GenerateDisplayString(ccLicences, centreDetails.CcLicenceSpots); + Trainers = DisplayStringHelper.GenerateNumberWithLimitDisplayString(trainers, centreDetails.TrainerSpots); + CmsAdministrators = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + cmsAdministrators, + centreDetails.CmsAdministratorSpots + ); + CmsManagers = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + cmsManagers, + centreDetails.CmsManagerSpots + ); + CcLicences = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + ccLicences, + centreDetails.CcLicenceSpots + ); } - private string GenerateDisplayString(int number, int limit) - { - return limit == -1 ? number.ToString() : number + " / " + limit; - } + public string Admins { get; set; } + public string Supervisors { get; set; } + public string Trainers { get; set; } + public string CmsAdministrators { get; set; } + public string CmsManagers { get; set; } + public string CcLicences { get; set; } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs new file mode 100644 index 0000000000..5e35b7f274 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs @@ -0,0 +1,116 @@ +namespace DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.ContractDetails +{ + using System; + using System.Collections.Generic; + using System.Linq; + using DigitalLearningSolutions.Data.Models; + using DigitalLearningSolutions.Data.Models.User; + using DigitalLearningSolutions.Web.Helpers; + + public class ContractDetailsViewModel + { + public ContractDetailsViewModel(List adminUsers, Centre centreDetails, int numberOfCourses) + { + Administrators = adminUsers.Count(a => a.IsCentreAdmin).ToString(); + Supervisors = adminUsers.Count(a => a.IsSupervisor).ToString(); + + var trainers = adminUsers.Count(a => a.IsTrainer); + var cmsAdministrators = adminUsers.Count(a => a.ImportOnly); + var cmsManagers = adminUsers.Count(a => a.IsContentManager) - cmsAdministrators; + var contentCreators = adminUsers.Count(a => a.IsContentCreator); + + Trainers = DisplayStringHelper.GenerateNumberWithLimitDisplayString(trainers, centreDetails.TrainerSpots); + TrainersColour = GetColourFromPercentageFilled(trainers, centreDetails.TrainerSpots); + + CmsAdministrators = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + cmsAdministrators, + centreDetails.CmsAdministratorSpots + ); + CmsAdministratorsColour = GetColourFromPercentageFilled( + cmsAdministrators, + centreDetails.CmsAdministratorSpots + ); + + CmsManagers = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + cmsManagers, + centreDetails.CmsManagerSpots + ); + CmsManagersColour = GetColourFromPercentageFilled( + cmsManagers, + centreDetails.CmsManagerSpots + ); + + ContentCreators = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + contentCreators, + centreDetails.CcLicenceSpots + ); + ContentCreatorsColour = GetColourFromPercentageFilled( + contentCreators, + centreDetails.CcLicenceSpots + ); + + CustomCourses = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + numberOfCourses, + centreDetails.CustomCourses + ); + CustomCoursesColour = GetColourFromPercentageFilled(numberOfCourses, centreDetails.CustomCourses); + + ServerSpace = DisplayStringHelper.GenerateBytesLimitDisplayString( + centreDetails.ServerSpaceUsed, + centreDetails.ServerSpaceBytes + ); + ServerSpaceColour = GetColourFromPercentageFilled( + centreDetails.ServerSpaceUsed, + centreDetails.ServerSpaceBytes + ); + } + + public string Administrators { get; set; } + + public string CmsAdministrators { get; set; } + public string CmsAdministratorsColour { get; set; } + + public string CmsManagers { get; set; } + public string CmsManagersColour { get; set; } + + public string ContentCreators { get; set; } + public string ContentCreatorsColour { get; set; } + + public string Trainers { get; set; } + public string TrainersColour { get; set; } + + public string Supervisors { get; set; } + + public string CustomCourses { get; set; } + public string CustomCoursesColour { get; set; } + + public string ServerSpace { get; set; } + public string ServerSpaceColour { get; set; } + + private string GetColourFromPercentageFilled(long number, long? limit) + { + if (limit == 0 && number == 0) + { + return "grey"; + } + + var usage = (double)number / limit.Value; + if (usage < 0.6) + { + return "green"; + } + + if (usage >= 0.6 && usage < 1) + { + return "yellow"; + } + + if (usage >= 1) + { + return "red"; + } + + return "blue"; + } + } +} diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml new file mode 100644 index 0000000000..5325ac398d --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml @@ -0,0 +1,139 @@ +@inject IConfiguration Configuration + +@using DigitalLearningSolutions.Web.Helpers +@using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.ContractDetails +@using Microsoft.Extensions.Configuration +@model ContractDetailsViewModel + + + +@{ + ViewData["Title"] = "Contract details"; + ViewData["Application"] = "Tracking System"; + ViewData["HeaderPath"] = $"{Configuration["AppRootPath"]}/TrackingSystem/Centre/Dashboard"; + ViewData["HeaderPathName"] = "Tracking System"; +} + +@section NavMenuItems { + +} + +@section NavBreadcrumbs { + +} + +
+
+

Contract details

+ +
    +
  • +
    +
    +

    + @Model.Administrators +

    + Administrators +
    +
    +
  • + +
  • +
    +
    +

    + @Model.CmsAdministrators +

    + CMS administrators +
    +
    +
  • + +
  • +
    +
    +

    + @Model.CmsManagers +

    + CMS managers +
    +
    +
  • + +
  • +
    +
    +

    + @Model.Trainers +

    + Trainers +
    +
    +
  • + +
  • +
    +
    +

    + @Model.Supervisors +

    + Supervisors +
    +
    +
  • + +
  • +
    +
    +

    + @Model.ContentCreators +

    + Content creators +
    +
    +
  • + +
  • +
    +
    +

    + @Model.CustomCourses +

    + Custom courses +
    +
    +
  • + +
  • +
    +
    +

    + @Model.ServerSpace +

    + Server space +
    +
    +
  • +
+ + + View pricing plans + + @if (User.HasCentreManagerPermissions()) { + + Manage users + + } +
+
diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/Dashboard/_DashboardBottomCardGroup.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/Dashboard/_DashboardBottomCardGroup.cshtml index 739a02bd5b..784a371f85 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/Dashboard/_DashboardBottomCardGroup.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/Dashboard/_DashboardBottomCardGroup.cshtml @@ -4,7 +4,7 @@

- Contract details + Contract details

See details about your contract type

From ec21d13b4672480257bfbe2e713d419fc3469128 Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Mon, 21 Jun 2021 09:21:56 +0100 Subject: [PATCH 02/10] HEEDLS-467 Add unit tests for display strings --- .../Helpers/DisplayStringHelperTests.cs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs diff --git a/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs new file mode 100644 index 0000000000..42876cca05 --- /dev/null +++ b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs @@ -0,0 +1,74 @@ +namespace DigitalLearningSolutions.Web.Tests.Helpers +{ + using DigitalLearningSolutions.Web.Helpers; + using FluentAssertions; + using NUnit.Framework; + + public class DisplayStringHelperTests + { + private const long Gigabyte = 1073741824; + + [Test] + public void GenerateNumberWithLimitDisplayString_returns_expected_string_with_limit() + { + // When + var result = DisplayStringHelper.GenerateNumberWithLimitDisplayString(1, 5); + + // Then + result.Should().Be("1 / 5"); + } + + [Test] + public void GenerateNumberWithLimitDisplayString_returns_expected_string_with_no_limit() + { + // When + var result = DisplayStringHelper.GenerateNumberWithLimitDisplayString(1, -1); + + // Then + result.Should().Be("1"); + } + + [Test] + public void GenerateBytesLimitDisplayString_returns_expected_string_for_bytes() + { + // When + var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, 120); + + // Then + result.Should().Be("12B / 120B"); + } + + [Test] + public void GenerateBytesLimitDisplayString_returns_expected_string_for_kilobytes() + { + // When + var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, 1200); + + // Then + result.Should().Be("12B / 1.2KiB"); + } + + [Test] + public void GenerateBytesLimitDisplayString_returns_expected_string_for_gigabytes() + { + // When + var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, Gigabyte); + + // Then + result.Should().Be("12B / 1GiB"); + } + + [Test] + public void GenerateBytesLimitDisplayString_returns_expected_string_when_less_than_next_size() + { + // Given + var bytes = Gigabyte - 10; + + // When + var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, bytes); + + // Then + result.Should().Be("12B / 1024MiB"); + } + } +} From 3e156f7e4b8922110fe5833b77c6e272dc3b89b0 Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Mon, 21 Jun 2021 10:14:36 +0100 Subject: [PATCH 03/10] HEEDLS-467 Add unit tests for ContractDetailsViewModel --- .../TestHelpers/CentreTestHelper.cs | 10 +- .../Centre/ContractDetailsViewModelTests.cs | 153 ++++++++++++++++++ .../ContractDetailsViewModel.cs | 5 + 3 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 DigitalLearningSolutions.Web.Tests/ViewModels/TrackingSystem/Centre/ContractDetailsViewModelTests.cs diff --git a/DigitalLearningSolutions.Data.Tests/TestHelpers/CentreTestHelper.cs b/DigitalLearningSolutions.Data.Tests/TestHelpers/CentreTestHelper.cs index c21e63b92d..78dceff1c3 100644 --- a/DigitalLearningSolutions.Data.Tests/TestHelpers/CentreTestHelper.cs +++ b/DigitalLearningSolutions.Data.Tests/TestHelpers/CentreTestHelper.cs @@ -34,7 +34,10 @@ public static Centre GetDefaultCentre int ccLicenceSpots = 0, int trainerSpots = 0, string? ipPrefix = "194.176.105", - string? contractType = "Basic" + string? contractType = "Basic", + int customCourses = 0, + long serverSpaceUsed = 0, + long serverSpaceBytes = 0 ) { return new Centre @@ -67,7 +70,10 @@ public static Centre GetDefaultCentre CcLicenceSpots = ccLicenceSpots, TrainerSpots = trainerSpots, IpPrefix = ipPrefix, - ContractType = contractType + ContractType = contractType, + CustomCourses = customCourses, + ServerSpaceBytes = serverSpaceBytes, + ServerSpaceUsed = serverSpaceUsed }; } } diff --git a/DigitalLearningSolutions.Web.Tests/ViewModels/TrackingSystem/Centre/ContractDetailsViewModelTests.cs b/DigitalLearningSolutions.Web.Tests/ViewModels/TrackingSystem/Centre/ContractDetailsViewModelTests.cs new file mode 100644 index 0000000000..f1f5efd5a0 --- /dev/null +++ b/DigitalLearningSolutions.Web.Tests/ViewModels/TrackingSystem/Centre/ContractDetailsViewModelTests.cs @@ -0,0 +1,153 @@ +namespace DigitalLearningSolutions.Web.Tests.ViewModels.TrackingSystem.Centre +{ + using System.Collections.Generic; + using DigitalLearningSolutions.Data.Models.User; + using DigitalLearningSolutions.Data.Tests.TestHelpers; + using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.ContractDetails; + using FluentAssertions; + using NUnit.Framework; + + public class ContractDetailsViewModelTests + { + [Test] + public void AdminUsers_and_Centre_populate_expected_values() + { + // Given + var centre = CentreTestHelper.GetDefaultCentre( + cmsAdministratorSpots: 3, + cmsManagerSpots: 13, + ccLicenceSpots: 14, + trainerSpots: 15, + customCourses: 12, + serverSpaceUsed: 1024, + serverSpaceBytes: 1073741824 + ); + var adminUsersAtCentre = GetAdminUsersForTest(); + + // When + var viewModel = new ContractDetailsViewModel(adminUsersAtCentre, centre, 10); + + // Then + viewModel.Administrators.Should().Be("7"); + viewModel.Supervisors.Should().Be("6"); + viewModel.CmsAdministrators.Should().Be("4 / 3"); + viewModel.CmsAdministratorsColour.Should().Be("red"); + viewModel.CmsManagers.Should().Be("1 / 13"); + viewModel.CmsManagersColour.Should().Be("green"); + viewModel.ContentCreators.Should().Be("2 / 14"); + viewModel.ContentCreatorsColour.Should().Be("green"); + viewModel.Trainers.Should().Be("1 / 15"); + viewModel.TrainersColour.Should().Be("green"); + viewModel.CustomCourses.Should().Be("10 / 12"); + viewModel.CustomCoursesColour.Should().Be("yellow"); + viewModel.ServerSpace.Should().Be("1KiB / 1GiB"); + viewModel.ServerSpaceColour.Should().Be("green"); + } + + [Test] + public void AdminUsers_and_Centre_populate_expected_values_with_no_limit() + { + // Given + var centre = CentreTestHelper.GetDefaultCentre( + cmsAdministratorSpots: -1, + cmsManagerSpots: -1, + ccLicenceSpots: -1, + trainerSpots: -1, + customCourses: 12, + serverSpaceUsed: 0, + serverSpaceBytes: 0 + ); + var adminUsersAtCentre = GetAdminUsersForTest(); + + // When + var viewModel = new ContractDetailsViewModel(adminUsersAtCentre, centre, 10); + + // Then + viewModel.Administrators.Should().Be("7"); + viewModel.Supervisors.Should().Be("6"); + viewModel.CmsAdministrators.Should().Be("4"); + viewModel.CmsAdministratorsColour.Should().Be("blue"); + viewModel.CmsManagers.Should().Be("1"); + viewModel.CmsManagersColour.Should().Be("blue"); + viewModel.ContentCreators.Should().Be("2"); + viewModel.ContentCreatorsColour.Should().Be("blue"); + viewModel.Trainers.Should().Be("1"); + viewModel.TrainersColour.Should().Be("blue"); + viewModel.CustomCourses.Should().Be("10 / 12"); + viewModel.CustomCoursesColour.Should().Be("yellow"); + viewModel.ServerSpace.Should().Be("0B / 0B"); + viewModel.ServerSpaceColour.Should().Be("grey"); + } + + private List GetAdminUsersForTest() + { + return new List + { + UserTestHelper.GetDefaultAdminUser( + isCentreAdmin: true, + isSupervisor: true, + isContentManager: true, + importOnly: true, + isContentCreator: false, + isTrainer: true + ), + UserTestHelper.GetDefaultAdminUser( + isCentreAdmin: true, + isSupervisor: true, + isContentManager: true, + importOnly: false, + isContentCreator: true, + isTrainer: false + ), + UserTestHelper.GetDefaultAdminUser( + isCentreAdmin: true, + isSupervisor: true, + isContentManager: false, + importOnly: true, + isContentCreator: true, + isTrainer: false + ), + UserTestHelper.GetDefaultAdminUser( + isCentreAdmin: true, + isSupervisor: true, + isContentManager: true, + importOnly: true, + isContentCreator: false, + isTrainer: false + ), + UserTestHelper.GetDefaultAdminUser( + isCentreAdmin: true, + isSupervisor: true, + isContentManager: true, + importOnly: true, + isContentCreator: false, + isTrainer: false + ), + UserTestHelper.GetDefaultAdminUser( + isCentreAdmin: true, + isSupervisor: true, + isContentManager: true, + importOnly: false, + isContentCreator: false, + isTrainer: false + ), + UserTestHelper.GetDefaultAdminUser( + isCentreAdmin: true, + isSupervisor: false, + isContentManager: false, + importOnly: false, + isContentCreator: false, + isTrainer: false + ), + UserTestHelper.GetDefaultAdminUser( + isCentreAdmin: false, + isSupervisor: false, + isContentManager: false, + importOnly: false, + isContentCreator: false, + isTrainer: false + ) + }; + } + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs index 5e35b7f274..ebeb9168a4 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs @@ -94,6 +94,11 @@ private string GetColourFromPercentageFilled(long number, long? limit) return "grey"; } + if (limit < 0) + { + return "blue"; + } + var usage = (double)number / limit.Value; if (usage < 0.6) { From 3f089fa2e82cb6737da7747a6ccc7a1723b232a3 Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Mon, 21 Jun 2021 10:20:27 +0100 Subject: [PATCH 04/10] HEEDLS-467 Add contract details page to accessibility tests --- .../AccessibilityTests/BasicAccessibilityTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/BasicAccessibilityTests.cs b/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/BasicAccessibilityTests.cs index dfd86cc2c3..9a5e655b04 100644 --- a/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/BasicAccessibilityTests.cs +++ b/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/BasicAccessibilityTests.cs @@ -31,6 +31,7 @@ public void Page_has_no_accessibility_errors(string url, string pageTitle) [InlineData("/MyAccount/EditDetails", "Edit details")] [InlineData("/TrackingSystem/Centre/Administrators", "Centre administrators")] [InlineData("/TrackingSystem/Centre/Dashboard", "Centre dashboard")] + [InlineData("/TrackingSystem/Centre/ContractDetails", "Contract details")] [InlineData("/TrackingSystem/CentreConfiguration", "Centre configuration")] [InlineData("/TrackingSystem/CentreConfiguration/EditCentreManagerDetails", "Edit centre manager details")] [InlineData("/TrackingSystem/CentreConfiguration/EditCentreWebsiteDetails", "Edit centre content on DLS website")] From fdeb56ac0f3cc6c0b36dac1be6d8417f41ea9d95 Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Tue, 22 Jun 2021 14:53:05 +0100 Subject: [PATCH 05/10] HEEDLS-467 Review markups --- .../Helpers/DisplayStringHelperTests.cs | 6 +- .../ContractDetailsController.cs | 2 +- .../Helpers/DisplayStringHelper.cs | 6 +- .../ContractDetailsViewModel.cs | 14 +-- .../Centre/ContractDetails/Index.cshtml | 90 +----------------- .../_ContractDetailsList.cshtml | 92 +++++++++++++++++++ 6 files changed, 104 insertions(+), 106 deletions(-) create mode 100644 DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/_ContractDetailsList.cshtml diff --git a/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs index 42876cca05..b1a57b8f89 100644 --- a/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs @@ -6,7 +6,7 @@ public class DisplayStringHelperTests { - private const long Gigabyte = 1073741824; + private const long Gibibyte = 1073741824; [Test] public void GenerateNumberWithLimitDisplayString_returns_expected_string_with_limit() @@ -52,7 +52,7 @@ public void GenerateBytesLimitDisplayString_returns_expected_string_for_kilobyte public void GenerateBytesLimitDisplayString_returns_expected_string_for_gigabytes() { // When - var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, Gigabyte); + var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, Gibibyte); // Then result.Should().Be("12B / 1GiB"); @@ -62,7 +62,7 @@ public void GenerateBytesLimitDisplayString_returns_expected_string_for_gigabyte public void GenerateBytesLimitDisplayString_returns_expected_string_when_less_than_next_size() { // Given - var bytes = Gigabyte - 10; + var bytes = Gibibyte - 10; // When var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, bytes); diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs index 8aa6592c99..9d4911a6f7 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs @@ -24,7 +24,7 @@ public ContractDetailsController(ICentresDataService centresDataService, IUserDa public IActionResult Index() { - int centreId = User.GetCentreId(); + var centreId = User.GetCentreId(); var centreDetails = centresDataService.GetCentreDetailsById(centreId)!; var adminUsersAtCentre = userDataService.GetAdminUsersByCentreId(centreId); var numberOfCourses = courseService.GetNumberOfActiveCoursesAtCentreForCategory(centreId, 0); diff --git a/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs b/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs index a3d8657ae1..191cedd161 100644 --- a/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs @@ -5,6 +5,7 @@ public static class DisplayStringHelper { private const string Divider = " / "; + private static readonly string[] Units = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" }; public static string GenerateNumberWithLimitDisplayString(int number, int limit) { @@ -18,16 +19,15 @@ public static string GenerateBytesLimitDisplayString(long number, long limit) private static string GenerateBytesDisplayString(long byteCount) { - var units = new[] { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" }; if (byteCount == 0) { - return 0 + units[0]; + return 0 + Units[0]; } var bytes = Math.Abs(byteCount); var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024))); var number = Math.Round(bytes / Math.Pow(1024, place), 1); - return (Math.Sign(byteCount) * number) + units[place]; + return (Math.Sign(byteCount) * number) + Units[place]; } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs index ebeb9168a4..0125a40527 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs @@ -1,6 +1,5 @@ namespace DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.ContractDetails { - using System; using System.Collections.Generic; using System.Linq; using DigitalLearningSolutions.Data.Models; @@ -87,25 +86,20 @@ public ContractDetailsViewModel(List adminUsers, Centre centreDetails public string ServerSpace { get; set; } public string ServerSpaceColour { get; set; } - private string GetColourFromPercentageFilled(long number, long? limit) + private string GetColourFromPercentageFilled(long number, long limit) { if (limit == 0 && number == 0) { return "grey"; } - if (limit < 0) - { - return "blue"; - } - - var usage = (double)number / limit.Value; - if (usage < 0.6) + var usage = (double)number / limit; + if (0 <= usage && usage < 0.6) { return "green"; } - if (usage >= 0.6 && usage < 1) + if (0.6 <= usage && usage < 1) { return "yellow"; } diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml index 5325ac398d..c88e986924 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml @@ -37,95 +37,7 @@

Contract details

-
    -
  • -
    -
    -

    - @Model.Administrators -

    - Administrators -
    -
    -
  • - -
  • -
    -
    -

    - @Model.CmsAdministrators -

    - CMS administrators -
    -
    -
  • - -
  • -
    -
    -

    - @Model.CmsManagers -

    - CMS managers -
    -
    -
  • - -
  • -
    -
    -

    - @Model.Trainers -

    - Trainers -
    -
    -
  • - -
  • -
    -
    -

    - @Model.Supervisors -

    - Supervisors -
    -
    -
  • - -
  • -
    -
    -

    - @Model.ContentCreators -

    - Content creators -
    -
    -
  • - -
  • -
    -
    -

    - @Model.CustomCourses -

    - Custom courses -
    -
    -
  • - -
  • -
    -
    -

    - @Model.ServerSpace -

    - Server space -
    -
    -
  • -
+ View pricing plans diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/_ContractDetailsList.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/_ContractDetailsList.cshtml new file mode 100644 index 0000000000..b60e0b558d --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/_ContractDetailsList.cshtml @@ -0,0 +1,92 @@ +@using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.ContractDetails +@model ContractDetailsViewModel + +
    +
  • +
    +
    +

    + @Model.Administrators +

    + Administrators +
    +
    +
  • + +
  • +
    +
    +

    + @Model.CmsAdministrators +

    + CMS administrators +
    +
    +
  • + +
  • +
    +
    +

    + @Model.CmsManagers +

    + CMS managers +
    +
    +
  • + +
  • +
    +
    +

    + @Model.Trainers +

    + Trainers +
    +
    +
  • + +
  • +
    +
    +

    + @Model.Supervisors +

    + Supervisors +
    +
    +
  • + +
  • +
    +
    +

    + @Model.ContentCreators +

    + Content creators +
    +
    +
  • + +
  • +
    +
    +

    + @Model.CustomCourses +

    + Custom courses +
    +
    +
  • + +
  • +
    +
    +

    + @Model.ServerSpace +

    + Server space +
    +
    +
  • +
From a26d61398896d1839a665d729432157717b614ac Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Wed, 23 Jun 2021 12:53:01 +0100 Subject: [PATCH 06/10] HEEDLS-467 Add extra space --- .../Centre/ContractDetails/ContractDetailsViewModel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs index 0125a40527..bac563f0b0 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs @@ -94,6 +94,7 @@ private string GetColourFromPercentageFilled(long number, long limit) } var usage = (double)number / limit; + if (0 <= usage && usage < 0.6) { return "green"; From b4aaa0e296c667a61af3c525283f9ec1a91e0568 Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Mon, 28 Jun 2021 11:32:29 +0100 Subject: [PATCH 07/10] HEEDLS-467 Refactoring display string helpers --- .../Helpers/DisplayStringHelperTests.cs | 20 ++++---- .../ContractDetailsController.cs | 12 +++-- .../Helpers/DisplayColourHelper.cs | 33 ++++++++++++ .../Helpers/DisplayStringHelper.cs | 4 +- .../trackingSystem/contractDetails.scss | 2 + .../Common/NumberOfAdministratorsViewModel.cs | 8 +-- .../ContractDetailsViewModel.cs | 51 +++++-------------- .../Centre/ContractDetails/Index.cshtml | 2 +- 8 files changed, 73 insertions(+), 59 deletions(-) create mode 100644 DigitalLearningSolutions.Web/Helpers/DisplayColourHelper.cs diff --git a/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs index b1a57b8f89..da0c0f621d 100644 --- a/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs @@ -12,7 +12,7 @@ public class DisplayStringHelperTests public void GenerateNumberWithLimitDisplayString_returns_expected_string_with_limit() { // When - var result = DisplayStringHelper.GenerateNumberWithLimitDisplayString(1, 5); + var result = DisplayStringHelper.FormatNumberWithLimit(1, 5); // Then result.Should().Be("1 / 5"); @@ -22,50 +22,50 @@ public void GenerateNumberWithLimitDisplayString_returns_expected_string_with_li public void GenerateNumberWithLimitDisplayString_returns_expected_string_with_no_limit() { // When - var result = DisplayStringHelper.GenerateNumberWithLimitDisplayString(1, -1); + var result = DisplayStringHelper.FormatNumberWithLimit(1, -1); // Then result.Should().Be("1"); } [Test] - public void GenerateBytesLimitDisplayString_returns_expected_string_for_bytes() + public void FormatBytesWithLimit_returns_expected_string_for_bytes() { // When - var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, 120); + var result = DisplayStringHelper.FormatBytesWithLimit(12, 120); // Then result.Should().Be("12B / 120B"); } [Test] - public void GenerateBytesLimitDisplayString_returns_expected_string_for_kilobytes() + public void FormatBytesWithLimit_returns_expected_string_for_kilobytes() { // When - var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, 1200); + var result = DisplayStringHelper.FormatBytesWithLimit(12, 1200); // Then result.Should().Be("12B / 1.2KiB"); } [Test] - public void GenerateBytesLimitDisplayString_returns_expected_string_for_gigabytes() + public void FormatBytesWithLimit_returns_expected_string_for_gibibytes() { // When - var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, Gibibyte); + var result = DisplayStringHelper.FormatBytesWithLimit(12, Gibibyte); // Then result.Should().Be("12B / 1GiB"); } [Test] - public void GenerateBytesLimitDisplayString_returns_expected_string_when_less_than_next_size() + public void FormatBytesWithLimit_returns_expected_string_when_less_than_next_size() { // Given var bytes = Gibibyte - 10; // When - var result = DisplayStringHelper.GenerateBytesLimitDisplayString(12, bytes); + var result = DisplayStringHelper.FormatBytesWithLimit(12, bytes); // Then result.Should().Be("12B / 1024MiB"); diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs index 9d4911a6f7..0b898b8904 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs @@ -12,10 +12,14 @@ public class ContractDetailsController : Controller { private readonly ICentresDataService centresDataService; - private readonly IUserDataService userDataService; private readonly ICourseService courseService; + private readonly IUserDataService userDataService; - public ContractDetailsController(ICentresDataService centresDataService, IUserDataService userDataService, ICourseService courseService) + public ContractDetailsController( + ICentresDataService centresDataService, + IUserDataService userDataService, + ICourseService courseService + ) { this.centresDataService = centresDataService; this.userDataService = userDataService; @@ -29,7 +33,9 @@ public IActionResult Index() var adminUsersAtCentre = userDataService.GetAdminUsersByCentreId(centreId); var numberOfCourses = courseService.GetNumberOfActiveCoursesAtCentreForCategory(centreId, 0); - return View(new ContractDetailsViewModel(adminUsersAtCentre, centreDetails, numberOfCourses)); + var model = new ContractDetailsViewModel(adminUsersAtCentre, centreDetails, numberOfCourses); + + return View(model); } } } diff --git a/DigitalLearningSolutions.Web/Helpers/DisplayColourHelper.cs b/DigitalLearningSolutions.Web/Helpers/DisplayColourHelper.cs new file mode 100644 index 0000000000..6c2ce8f80f --- /dev/null +++ b/DigitalLearningSolutions.Web/Helpers/DisplayColourHelper.cs @@ -0,0 +1,33 @@ +namespace DigitalLearningSolutions.Web.Helpers +{ + public static class DisplayColourHelper + { + // The colour strings here correspond to css classes defined in contractDetails.scss + public static string GetDisplayColourForPercentage(long number, long limit) + { + if (limit == 0 && number == 0) + { + return "grey"; + } + + var usage = (double)number / limit; + + if (0 <= usage && usage < 0.6) + { + return "green"; + } + + if (0.6 <= usage && usage < 1) + { + return "yellow"; + } + + if (usage >= 1) + { + return "red"; + } + + return "blue"; + } + } +} diff --git a/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs b/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs index 191cedd161..119e655287 100644 --- a/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs @@ -7,12 +7,12 @@ public static class DisplayStringHelper private const string Divider = " / "; private static readonly string[] Units = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" }; - public static string GenerateNumberWithLimitDisplayString(int number, int limit) + public static string FormatNumberWithLimit(int number, int limit) { return limit == -1 ? number.ToString() : number + Divider + limit; } - public static string GenerateBytesLimitDisplayString(long number, long limit) + public static string FormatBytesWithLimit(long number, long limit) { return GenerateBytesDisplayString(number) + Divider + GenerateBytesDisplayString(limit); } diff --git a/DigitalLearningSolutions.Web/Styles/trackingSystem/contractDetails.scss b/DigitalLearningSolutions.Web/Styles/trackingSystem/contractDetails.scss index bf78695da2..e6fe30d61a 100644 --- a/DigitalLearningSolutions.Web/Styles/trackingSystem/contractDetails.scss +++ b/DigitalLearningSolutions.Web/Styles/trackingSystem/contractDetails.scss @@ -1,5 +1,7 @@ @import "~nhsuk-frontend/packages/core/all"; +// The colours here are tied to the colour conversion from percentages +// defined in DisplayColourHelper .coloured-card-number { &--blue { color: $color_nhsuk-blue; diff --git a/DigitalLearningSolutions.Web/ViewModels/Common/NumberOfAdministratorsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Common/NumberOfAdministratorsViewModel.cs index 714af9f08d..c6ffdab939 100644 --- a/DigitalLearningSolutions.Web/ViewModels/Common/NumberOfAdministratorsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/Common/NumberOfAdministratorsViewModel.cs @@ -18,16 +18,16 @@ public NumberOfAdministratorsViewModel(Centre centreDetails, List adm var cmsManagers = adminUsers.Count(a => a.IsContentManager) - cmsAdministrators; var ccLicences = adminUsers.Count(a => a.IsContentCreator); - Trainers = DisplayStringHelper.GenerateNumberWithLimitDisplayString(trainers, centreDetails.TrainerSpots); - CmsAdministrators = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + Trainers = DisplayStringHelper.FormatNumberWithLimit(trainers, centreDetails.TrainerSpots); + CmsAdministrators = DisplayStringHelper.FormatNumberWithLimit( cmsAdministrators, centreDetails.CmsAdministratorSpots ); - CmsManagers = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + CmsManagers = DisplayStringHelper.FormatNumberWithLimit( cmsManagers, centreDetails.CmsManagerSpots ); - CcLicences = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + CcLicences = DisplayStringHelper.FormatNumberWithLimit( ccLicences, centreDetails.CcLicenceSpots ); diff --git a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs index bac563f0b0..5ab8121619 100644 --- a/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/TrackingSystem/Centre/ContractDetails/ContractDetailsViewModel.cs @@ -18,47 +18,47 @@ public ContractDetailsViewModel(List adminUsers, Centre centreDetails var cmsManagers = adminUsers.Count(a => a.IsContentManager) - cmsAdministrators; var contentCreators = adminUsers.Count(a => a.IsContentCreator); - Trainers = DisplayStringHelper.GenerateNumberWithLimitDisplayString(trainers, centreDetails.TrainerSpots); - TrainersColour = GetColourFromPercentageFilled(trainers, centreDetails.TrainerSpots); + Trainers = DisplayStringHelper.FormatNumberWithLimit(trainers, centreDetails.TrainerSpots); + TrainersColour = DisplayColourHelper.GetDisplayColourForPercentage(trainers, centreDetails.TrainerSpots); - CmsAdministrators = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + CmsAdministrators = DisplayStringHelper.FormatNumberWithLimit( cmsAdministrators, centreDetails.CmsAdministratorSpots ); - CmsAdministratorsColour = GetColourFromPercentageFilled( + CmsAdministratorsColour = DisplayColourHelper.GetDisplayColourForPercentage( cmsAdministrators, centreDetails.CmsAdministratorSpots ); - CmsManagers = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + CmsManagers = DisplayStringHelper.FormatNumberWithLimit( cmsManagers, centreDetails.CmsManagerSpots ); - CmsManagersColour = GetColourFromPercentageFilled( + CmsManagersColour = DisplayColourHelper.GetDisplayColourForPercentage( cmsManagers, centreDetails.CmsManagerSpots ); - ContentCreators = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + ContentCreators = DisplayStringHelper.FormatNumberWithLimit( contentCreators, centreDetails.CcLicenceSpots ); - ContentCreatorsColour = GetColourFromPercentageFilled( + ContentCreatorsColour = DisplayColourHelper.GetDisplayColourForPercentage( contentCreators, centreDetails.CcLicenceSpots ); - CustomCourses = DisplayStringHelper.GenerateNumberWithLimitDisplayString( + CustomCourses = DisplayStringHelper.FormatNumberWithLimit( numberOfCourses, centreDetails.CustomCourses ); - CustomCoursesColour = GetColourFromPercentageFilled(numberOfCourses, centreDetails.CustomCourses); + CustomCoursesColour = DisplayColourHelper.GetDisplayColourForPercentage(numberOfCourses, centreDetails.CustomCourses); - ServerSpace = DisplayStringHelper.GenerateBytesLimitDisplayString( + ServerSpace = DisplayStringHelper.FormatBytesWithLimit( centreDetails.ServerSpaceUsed, centreDetails.ServerSpaceBytes ); - ServerSpaceColour = GetColourFromPercentageFilled( + ServerSpaceColour = DisplayColourHelper.GetDisplayColourForPercentage( centreDetails.ServerSpaceUsed, centreDetails.ServerSpaceBytes ); @@ -85,32 +85,5 @@ public ContractDetailsViewModel(List adminUsers, Centre centreDetails public string ServerSpace { get; set; } public string ServerSpaceColour { get; set; } - - private string GetColourFromPercentageFilled(long number, long limit) - { - if (limit == 0 && number == 0) - { - return "grey"; - } - - var usage = (double)number / limit; - - if (0 <= usage && usage < 0.6) - { - return "green"; - } - - if (0.6 <= usage && usage < 1) - { - return "yellow"; - } - - if (usage >= 1) - { - return "red"; - } - - return "blue"; - } } } diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml index c88e986924..db876c5a78 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml @@ -35,7 +35,7 @@
-

Contract details

+

Contract details

From ddd3dc8ab87916f9f4a25280741b750d315ba5a9 Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Mon, 28 Jun 2021 11:49:10 +0100 Subject: [PATCH 08/10] HEEDLS-467 Add unit tests for DisplayColourHelper --- .../Helpers/DisplayColourHelperTests.cs | 79 +++++++++++++++++++ .../Helpers/DisplayColourHelper.cs | 5 ++ 2 files changed, 84 insertions(+) create mode 100644 DigitalLearningSolutions.Web.Tests/Helpers/DisplayColourHelperTests.cs diff --git a/DigitalLearningSolutions.Web.Tests/Helpers/DisplayColourHelperTests.cs b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayColourHelperTests.cs new file mode 100644 index 0000000000..f52ab2e2c9 --- /dev/null +++ b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayColourHelperTests.cs @@ -0,0 +1,79 @@ +namespace DigitalLearningSolutions.Web.Tests.Helpers +{ + using DigitalLearningSolutions.Web.Helpers; + using FluentAssertions; + using NUnit.Framework; + + public class DisplayColourHelperTests + { + [Test] + public void GetDisplayColourForPercentage_returns_grey_for_zero_of_zero() + { + // When + var result = DisplayColourHelper.GetDisplayColourForPercentage(0, 0); + + // Then + result.Should().BeEquivalentTo("grey"); + } + + [Test] + public void GetDisplayColourForPercentage_returns_blue_for_no_limit() + { + // When + var result = DisplayColourHelper.GetDisplayColourForPercentage(10, -1); + + // Then + result.Should().BeEquivalentTo("blue"); + } + + [Test] + public void GetDisplayColourForPercentage_returns_blue_for_no_limit_with_no_value() + { + // When + var result = DisplayColourHelper.GetDisplayColourForPercentage(0, -1); + + // Then + result.Should().BeEquivalentTo("blue"); + } + + [Test] + public void GetDisplayColourForPercentage_returns_green_for_under_sixty_percent() + { + // When + var result = DisplayColourHelper.GetDisplayColourForPercentage(59, 100); + + // Then + result.Should().BeEquivalentTo("green"); + } + + [Test] + public void GetDisplayColourForPercentage_returns_yellow_for_sixty_percent() + { + // When + var result = DisplayColourHelper.GetDisplayColourForPercentage(60, 100); + + // Then + result.Should().BeEquivalentTo("yellow"); + } + + [Test] + public void GetDisplayColourForPercentage_returns_red_for_one_hundred_percent() + { + // When + var result = DisplayColourHelper.GetDisplayColourForPercentage(100, 100); + + // Then + result.Should().BeEquivalentTo("red"); + } + + [Test] + public void GetDisplayColourForPercentage_returns_red_for_zero_limit_with_value() + { + // When + var result = DisplayColourHelper.GetDisplayColourForPercentage(100, 0); + + // Then + result.Should().BeEquivalentTo("red"); + } + } +} diff --git a/DigitalLearningSolutions.Web/Helpers/DisplayColourHelper.cs b/DigitalLearningSolutions.Web/Helpers/DisplayColourHelper.cs index 6c2ce8f80f..e66a2d334c 100644 --- a/DigitalLearningSolutions.Web/Helpers/DisplayColourHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/DisplayColourHelper.cs @@ -10,6 +10,11 @@ public static string GetDisplayColourForPercentage(long number, long limit) return "grey"; } + if (limit < 0) + { + return "blue"; + } + var usage = (double)number / limit; if (0 <= usage && usage < 0.6) From b0a059e6deee6359e334c3d8a61af1f817f45f96 Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Mon, 28 Jun 2021 14:30:13 +0100 Subject: [PATCH 09/10] HEEDLS-467 Refactor to match changes made for other dashboard pages --- .../ContractDetailsController.cs | 11 +++++------ .../Centre/ContractDetails/Index.cshtml | 18 ++++-------------- 2 files changed, 9 insertions(+), 20 deletions(-) rename DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/{ContractDetails => Dashboard}/ContractDetailsController.cs (78%) diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Dashboard/ContractDetailsController.cs similarity index 78% rename from DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs rename to DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Dashboard/ContractDetailsController.cs index 0b898b8904..3c5b0e7eb4 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/ContractDetails/ContractDetailsController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Dashboard/ContractDetailsController.cs @@ -1,7 +1,6 @@ -namespace DigitalLearningSolutions.Web.Controllers.TrackingSystem.Centre.ContractDetails +namespace DigitalLearningSolutions.Web.Controllers.TrackingSystem.Centre.Dashboard { using DigitalLearningSolutions.Data.DataServices; - using DigitalLearningSolutions.Data.Services; using DigitalLearningSolutions.Web.Helpers; using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.ContractDetails; using Microsoft.AspNetCore.Authorization; @@ -12,18 +11,18 @@ public class ContractDetailsController : Controller { private readonly ICentresDataService centresDataService; - private readonly ICourseService courseService; + private readonly ICourseDataService courseDataService; private readonly IUserDataService userDataService; public ContractDetailsController( ICentresDataService centresDataService, IUserDataService userDataService, - ICourseService courseService + ICourseDataService courseDataService ) { this.centresDataService = centresDataService; this.userDataService = userDataService; - this.courseService = courseService; + this.courseDataService = courseDataService; } public IActionResult Index() @@ -31,7 +30,7 @@ public IActionResult Index() var centreId = User.GetCentreId(); var centreDetails = centresDataService.GetCentreDetailsById(centreId)!; var adminUsersAtCentre = userDataService.GetAdminUsersByCentreId(centreId); - var numberOfCourses = courseService.GetNumberOfActiveCoursesAtCentreForCategory(centreId, 0); + var numberOfCourses = courseDataService.GetNumberOfActiveCoursesAtCentreForCategory(centreId, 0); var model = new ContractDetailsViewModel(adminUsersAtCentre, centreDetails, numberOfCourses); diff --git a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml index db876c5a78..b7b6cc125c 100644 --- a/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml +++ b/DigitalLearningSolutions.Web/Views/TrackingSystem/Centre/ContractDetails/Index.cshtml @@ -19,30 +19,20 @@ } @section NavBreadcrumbs { -
+ }

Contract details

- + View pricing plans - @if (User.HasCentreManagerPermissions()) { + @if (User.HasCentreManagerPermissions()) + { Manage users From c8139cf4b4f764ee5c52a7e3c89222d9d5492b71 Mon Sep 17 00:00:00 2001 From: Alex Jackson Date: Tue, 29 Jun 2021 14:00:13 +0100 Subject: [PATCH 10/10] HEEDLS-467 Throw exception on negative byte count --- .../Helpers/DisplayStringHelperTests.cs | 11 +++++++++++ .../Helpers/DisplayStringHelper.cs | 10 +++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs index da0c0f621d..0379118d26 100644 --- a/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Helpers/DisplayStringHelperTests.cs @@ -1,5 +1,6 @@ namespace DigitalLearningSolutions.Web.Tests.Helpers { + using System; using DigitalLearningSolutions.Web.Helpers; using FluentAssertions; using NUnit.Framework; @@ -70,5 +71,15 @@ public void FormatBytesWithLimit_returns_expected_string_when_less_than_next_siz // Then result.Should().Be("12B / 1024MiB"); } + + [Test] + public void FormatBytesWithLimit_throws_exception_with_negative_bytes() + { + // When + Action action = () => DisplayStringHelper.FormatBytesWithLimit(-1, 0); + + // Then + action.Should().Throw(); + } } } diff --git a/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs b/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs index 119e655287..5071e48ed7 100644 --- a/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs @@ -19,14 +19,18 @@ public static string FormatBytesWithLimit(long number, long limit) private static string GenerateBytesDisplayString(long byteCount) { + if (byteCount < 0) + { + throw new ArgumentOutOfRangeException(nameof(byteCount), $"Byte count cannot be negative: {byteCount}"); + } + if (byteCount == 0) { return 0 + Units[0]; } - var bytes = Math.Abs(byteCount); - var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024))); - var number = Math.Round(bytes / Math.Pow(1024, place), 1); + var place = Convert.ToInt32(Math.Floor(Math.Log(byteCount, 1024))); + var number = Math.Round(byteCount / Math.Pow(1024, place), 1); return (Math.Sign(byteCount) * number) + Units[place]; } }