diff --git a/DigitalLearningSolutions.Data/DataServices/FrameworkDataService.cs b/DigitalLearningSolutions.Data/DataServices/FrameworkDataService.cs index 4627c67572..9781639ad9 100644 --- a/DigitalLearningSolutions.Data/DataServices/FrameworkDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/FrameworkDataService.cs @@ -2404,7 +2404,7 @@ public IEnumerable GetBulkCompetenciesForFramework(int framework if (frameworkId < 1) { return connection.Query( - @"SELECT NULL AS ID, '' AS CompetencyGroup, '' AS GroupDescription, '' AS Competency, '' AS CompetencyDescription, NULL AS AlwaysShowDescription, '' AS FlagsCsv" + @"SELECT NULL AS ID, '' AS CompetencyGroup, '' AS GroupDescription, '' AS Competency, '' AS CompetencyDescription, 0 AS AlwaysShowDescription, '' AS FlagsCsv" ); } else diff --git a/DigitalLearningSolutions.Data/Models/Frameworks/Import/CompetencyTableRow.cs b/DigitalLearningSolutions.Data/Models/Frameworks/Import/CompetencyTableRow.cs index ab79a40b43..1f99fa9550 100644 --- a/DigitalLearningSolutions.Data/Models/Frameworks/Import/CompetencyTableRow.cs +++ b/DigitalLearningSolutions.Data/Models/Frameworks/Import/CompetencyTableRow.cs @@ -26,10 +26,10 @@ public CompetencyTableRow(IXLTable table, IXLRangeRow row) RowNumber = row.RowNumber(); id = row.Cell(1).GetValue(); - CompetencyGroup = FindFieldValue("CompetencyGroup"); - Competency = FindFieldValue("Competency"); - CompetencyDescription = FindFieldValue("CompetencyDescription"); - GroupDescription = FindFieldValue("GroupDescription"); + CompetencyGroup = row.Cell(2).GetValue(); + GroupDescription = row.Cell(3).GetValue(); + Competency = row.Cell(4).GetValue(); + CompetencyDescription = row.Cell(5).GetValue(); AlwaysShowDescriptionRaw = FindFieldValue("AlwaysShowDescription"); AlwaysShowDescription = bool.TryParse(AlwaysShowDescriptionRaw, out var hasPrn) ? hasPrn : (bool?)null; FlagsCsv = FindFieldValue("FlagsCSV"); diff --git a/DigitalLearningSolutions.Data/Models/Frameworks/Import/ImportCompetenciesResult.cs b/DigitalLearningSolutions.Data/Models/Frameworks/Import/ImportCompetenciesResult.cs index 3c2bc8e287..53f0beed1a 100644 --- a/DigitalLearningSolutions.Data/Models/Frameworks/Import/ImportCompetenciesResult.cs +++ b/DigitalLearningSolutions.Data/Models/Frameworks/Import/ImportCompetenciesResult.cs @@ -22,6 +22,7 @@ IReadOnlyCollection competencyTableRows { ProcessedCount = competencyTableRows.Count; CompetencyAddedCount = competencyTableRows.Count(dr => dr.RowStatus == RowStatus.CompetencyInserted | dr.RowStatus == RowStatus.CompetencyGroupAndCompetencyInserted); + CompetencyUpdatedCount = competencyTableRows.Count(dr => dr.RowStatus == RowStatus.CompetencyUpdated); GroupAddedCount = competencyTableRows.Count(dr => dr.RowStatus == RowStatus.CompetencyGroupInserted | dr.RowStatus == RowStatus.CompetencyGroupAndCompetencyInserted); SkippedCount = competencyTableRows.Count(dr => dr.RowStatus == RowStatus.Skipped); Errors = competencyTableRows.Where(dr => dr.Error.HasValue).Select(dr => (dr.RowNumber, dr.Error!.Value)); diff --git a/DigitalLearningSolutions.Web/Controllers/FrameworksController/ImportCompetencies.cs b/DigitalLearningSolutions.Web/Controllers/FrameworksController/ImportCompetencies.cs index d713235f4f..dad1bbd4c1 100644 --- a/DigitalLearningSolutions.Web/Controllers/FrameworksController/ImportCompetencies.cs +++ b/DigitalLearningSolutions.Web/Controllers/FrameworksController/ImportCompetencies.cs @@ -3,7 +3,7 @@ using DigitalLearningSolutions.Web.Helpers; using DigitalLearningSolutions.Web.Models; using DigitalLearningSolutions.Web.Services; -using DigitalLearningSolutions.Web.ViewModels.Frameworks; +using DigitalLearningSolutions.Web.ViewModels.Frameworks.Import; using GDS.MultiPageFormData.Enums; using Microsoft.AspNetCore.Mvc; using System.IO; @@ -16,21 +16,19 @@ public partial class FrameworksController public IActionResult ImportCompetencies(int frameworkId, string tabname, bool isNotBlank) { var adminId = GetAdminId(); + var framework = frameworkService.GetFrameworkDetailByFrameworkId(frameworkId, adminId); var userRole = frameworkService.GetAdminUserRoleForFrameworkId(adminId, frameworkId); if (userRole < 2) return StatusCode(403); - var model = new ImportCompetenciesViewModel() - { - FrameworkId = frameworkId, - IsNotBlank = isNotBlank - }; - return View("Developer/ImportCompetencies", model); + var model = new ImportCompetenciesViewModel(framework, isNotBlank); + + return View("Developer/Import/Index", model); } - public IActionResult DownloadCompetencies(int frameworkId, int DownloadOption) + public IActionResult DownloadCompetencies(int frameworkId, int DownloadOption, string vocabulary) { - string fileName = DownloadOption == 2 ? $"DLS Competencies for Bulk Update {clockUtility.UtcToday:yyyy-MM-dd}.xlsx" : "DLS Competencies for Bulk Upload.xlsx"; + string fileName = DownloadOption == 2 ? $"DLS {FrameworkVocabularyHelper.VocabularyPlural(vocabulary)} for Bulk Update {clockUtility.UtcToday:yyyy-MM-dd}.xlsx" : $"DLS {FrameworkVocabularyHelper.VocabularyPlural(vocabulary)} for Bulk Upload.xlsx"; var content = importCompetenciesFromFileService.GetCompetencyFileForFramework( - frameworkId, DownloadOption == 2 ? false : true + frameworkId, DownloadOption == 2 ? false : true, vocabulary ); return File( content, @@ -40,11 +38,11 @@ public IActionResult DownloadCompetencies(int frameworkId, int DownloadOption) } [HttpPost] [Route("/Framework/{frameworkId}/{tabname}/Import")] - [Route("/Framework/{frameworkId}/{tabname}/ImportCompleted")] - public IActionResult StartImport(ImportCompetenciesViewModel model, string tabname, bool isNotBlank) + [Route("/Framework/{frameworkId}/{tabname}/Import/Uploaded")] + public IActionResult StartImport(ImportCompetenciesFormData model, int frameworkId, string tabname, bool isNotBlank) { if (!ModelState.IsValid) - return View("Developer/ImportCompetencies", model); + return View("Developer/Import/Index", model); try { var adminUserID = User.GetAdminIdKnownNotNull(); @@ -52,12 +50,12 @@ public IActionResult StartImport(ImportCompetenciesViewModel model, string tabna if (!workbook.Worksheets.Contains(ImportCompetenciesFromFileService.CompetenciesSheetName)) { ModelState.AddModelError("ImportFile", CommonValidationErrorMessages.InvalidCompetenciesUploadExcelFile); - return View("Developer/ImportCompetencies", model); + return View("Developer/Import/Index", model); } var competenciesFileName = FileHelper.UploadFile(webHostEnvironment, model.ImportFile); - setupBulkUploadData(model.FrameworkId, adminUserID, competenciesFileName, tabname, isNotBlank); + setupBulkUploadData(frameworkId, adminUserID, competenciesFileName, tabname, isNotBlank); - return RedirectToAction("ImportCompleted", "Frameworks", new { frameworkId = model.FrameworkId, tabname }); + return RedirectToAction("ImportCompleted", "Frameworks", new { frameworkId, tabname }); } catch (DocumentFormat.OpenXml.Packaging.OpenXmlPackageException) { @@ -66,10 +64,10 @@ public IActionResult StartImport(ImportCompetenciesViewModel model, string tabna } catch (InvalidHeadersException) { - return View("Developer/ImportFailed"); + return View("Developer/Import/ImportFailed"); } } - [Route("/Framework/{frameworkId}/{tabname}/ImportCompleted")] + [Route("/Framework/{frameworkId}/{tabname}/Import/Uploaded")] public IActionResult ImportCompleted() { var data = GetBulkUploadData(); @@ -78,13 +76,13 @@ public IActionResult ImportCompleted() var workbook = new XLWorkbook(filePath); try { - var results = importCompetenciesFromFileService.PreProcessCompetenciesTable(workbook); - var resultsModel = new ImportCompetenciesPreProcessViewModel(results) { IsNotBlank = data.IsNotBlank, TabName = data.TabName }; + var results = importCompetenciesFromFileService.PreProcessCompetenciesTable(workbook, data.FrameworkVocubulary); + var resultsModel = new ImportCompetenciesPreProcessViewModel(results, data) { IsNotBlank = data.IsNotBlank, TabName = data.TabName }; data.CompetenciesToProcessCount = resultsModel.ToProcessCount; data.CompetenciesToAddCount = resultsModel.CompetenciesToAddCount; data.CompetenciesToUpdateCount = resultsModel.CompetenciesToUpdateCount; setBulkUploadData(data); - return View("Developer/ImportCompleted", resultsModel); + return View("Developer/Import/ImportCompleted", resultsModel); } catch (InvalidHeadersException) { @@ -92,13 +90,20 @@ public IActionResult ImportCompleted() return View("ImportFailed"); } } + [Route("/Framework/{frameworkId}/{tabname}/Import/AssessmentQuestions")] + public IActionResult AddAssessmentQuestions() + { + var data = GetBulkUploadData(); + return View(); + } private void setupBulkUploadData(int frameworkId, int adminUserID, string competenciessFileName, string tabName, bool isNotBlank) { TempData.Clear(); multiPageFormService.ClearMultiPageFormData(MultiPageFormDataFeature.AddCustomWebForm("BulkCompetencyDataCWF"), TempData); + var framework = frameworkService.GetFrameworkDetailByFrameworkId(frameworkId, adminUserID); var today = clockUtility.UtcToday; - var bulkUploadData = new BulkCompetenciesData(frameworkId, adminUserID, competenciessFileName, tabName, isNotBlank); + var bulkUploadData = new BulkCompetenciesData(framework, adminUserID, competenciessFileName, tabName, isNotBlank); setBulkUploadData(bulkUploadData); } private void setBulkUploadData(BulkCompetenciesData bulkUploadData) diff --git a/DigitalLearningSolutions.Web/Models/BulkCompetenciesData.cs b/DigitalLearningSolutions.Web/Models/BulkCompetenciesData.cs index 290e263477..44ae69f92b 100644 --- a/DigitalLearningSolutions.Web/Models/BulkCompetenciesData.cs +++ b/DigitalLearningSolutions.Web/Models/BulkCompetenciesData.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using DigitalLearningSolutions.Data.Models.Frameworks; +using System.Collections; +using System.Collections.Generic; using System.Linq; namespace DigitalLearningSolutions.Web.Models @@ -6,15 +8,21 @@ namespace DigitalLearningSolutions.Web.Models public class BulkCompetenciesData { public BulkCompetenciesData() { } - public BulkCompetenciesData(int frameworkId, int adminUserId, string competenciesFileName, string tabName, bool isNotBlank) + public BulkCompetenciesData(DetailFramework framework, int adminUserId, string competenciesFileName, string tabName, bool isNotBlank) { - FrameworkId = frameworkId; + FrameworkId = framework.ID; + FrameworkName = framework.FrameworkName; + PublishStatusID = framework.PublishStatusID; + FrameworkVocubulary = framework.FrameworkConfig; AdminUserId = adminUserId; CompetenciesFileName = competenciesFileName; TabName = tabName; IsNotBlank = isNotBlank; } public int FrameworkId { get; set; } + public string? FrameworkName { get; set; } + public int PublishStatusID { get; set; } + public string FrameworkVocubulary { get; set; } public string TabName { get; set; } public int AdminUserId { get; set; } public bool IsNotBlank { get; set; } diff --git a/DigitalLearningSolutions.Web/Services/ImportCompetenciesFromFileService.cs b/DigitalLearningSolutions.Web/Services/ImportCompetenciesFromFileService.cs index 1746ebe904..d8611a86f8 100644 --- a/DigitalLearningSolutions.Web/Services/ImportCompetenciesFromFileService.cs +++ b/DigitalLearningSolutions.Web/Services/ImportCompetenciesFromFileService.cs @@ -12,29 +12,27 @@ namespace DigitalLearningSolutions.Web.Services using DigitalLearningSolutions.Data.Exceptions; using DigitalLearningSolutions.Data.Helpers; using DigitalLearningSolutions.Data.Models.Frameworks.Import; - using DigitalLearningSolutions.Web.Models; - using Microsoft.AspNetCore.Http; public interface IImportCompetenciesFromFileService { - byte[] GetCompetencyFileForFramework(int frameworkId, bool v); - public ImportCompetenciesResult PreProcessCompetenciesTable(IXLWorkbook workbook); - public ImportCompetenciesResult ProcessCompetenciesFromFile(IXLWorkbook workbook, int adminUserId, int frameworkId); + byte[] GetCompetencyFileForFramework(int frameworkId, bool isBlank, string vocabulary); + public ImportCompetenciesResult PreProcessCompetenciesTable(IXLWorkbook workbook, string vocabulary); + public ImportCompetenciesResult ProcessCompetenciesFromFile(IXLWorkbook workbook, int adminUserId, int frameworkId, string vocabulary); } public class ImportCompetenciesFromFileService : IImportCompetenciesFromFileService { private readonly IFrameworkService frameworkService; private static readonly XLTableTheme TableTheme = XLTableTheme.TableStyleLight9; - public const string CompetenciesSheetName = "CompetenciesBulkUpload"; + public const string CompetenciesSheetName = "FrameworkBulkUpload"; public ImportCompetenciesFromFileService( IFrameworkService frameworkService ) { this.frameworkService = frameworkService; } - public ImportCompetenciesResult PreProcessCompetenciesTable(IXLWorkbook workbook) + public ImportCompetenciesResult PreProcessCompetenciesTable(IXLWorkbook workbook, string vocabulary) { - var table = OpenCompetenciesTable(workbook); + var table = OpenCompetenciesTable(workbook, vocabulary); var competencyRows = table.Rows().Skip(1).Select(row => new CompetencyTableRow(table, row)).ToList(); foreach (var competencyRow in competencyRows) { @@ -54,14 +52,14 @@ private void PreProcessCompetencyRow(CompetencyTableRow competencyRow) competencyRow.RowStatus = RowStatus.CompetencyUpdated; } } - public ImportCompetenciesResult ProcessCompetenciesFromFile(IXLWorkbook workbook, int adminUserId, int frameworkId) + public ImportCompetenciesResult ProcessCompetenciesFromFile(IXLWorkbook workbook, int adminUserId, int frameworkId, string vocabulary) { int maxFrameworkCompetencyId = frameworkService.GetMaxFrameworkCompetencyID(); int maxFrameworkCompetencyGroupId = frameworkService.GetMaxFrameworkCompetencyGroupID(); - var table = OpenCompetenciesTable(workbook); + var table = OpenCompetenciesTable(workbook, vocabulary); return ProcessCompetenciesTable(table, adminUserId, frameworkId, maxFrameworkCompetencyId, maxFrameworkCompetencyGroupId); } - internal IXLTable OpenCompetenciesTable(IXLWorkbook workbook) + internal IXLTable OpenCompetenciesTable(IXLWorkbook workbook, string vocabulary) { var worksheet = workbook.Worksheet(1); worksheet.Columns(1, 15).Unhide(); @@ -70,7 +68,7 @@ internal IXLTable OpenCompetenciesTable(IXLWorkbook workbook) throw new InvalidHeadersException(); } var table = worksheet.Tables.Table(0); - if (!ValidateHeaders(table)) + if (!ValidateHeaders(table, vocabulary)) { throw new InvalidHeadersException(); } @@ -132,15 +130,15 @@ CompetencyTableRow competencyRow return maxFrameworkCompetencyGroupId; } - private static bool ValidateHeaders(IXLTable table) + private static bool ValidateHeaders(IXLTable table, string Vocabulary) { var expectedHeaders = new List { "ID", - "CompetencyGroup", + Vocabulary + "Group", "GroupDescription", - "Competency", - "CompetencyDescription", + Vocabulary, + Vocabulary + "Description", "AlwaysShowDescription", "FlagsCSV" }.OrderBy(x => x); @@ -148,10 +146,10 @@ private static bool ValidateHeaders(IXLTable table) return actualHeaders.SequenceEqual(expectedHeaders); } - public byte[] GetCompetencyFileForFramework(int frameworkId, bool blank) + public byte[] GetCompetencyFileForFramework(int frameworkId, bool blank, string vocabulary) { using var workbook = new XLWorkbook(); - PopulateCompetenciesSheet(workbook, frameworkId, blank); + PopulateCompetenciesSheet(workbook, frameworkId, blank, vocabulary); if (blank) { ClosedXmlHelper.HideWorkSheetColumn(workbook, "ID"); @@ -167,7 +165,7 @@ public byte[] GetCompetencyFileForFramework(int frameworkId, bool blank) workbook.SaveAs(stream); return stream.ToArray(); } - private void PopulateCompetenciesSheet(IXLWorkbook workbook, int frameworkId, bool blank) + private void PopulateCompetenciesSheet(IXLWorkbook workbook, int frameworkId, bool blank, string vocabulary) { @@ -184,8 +182,10 @@ private void PopulateCompetenciesSheet(IXLWorkbook workbook, int frameworkId, bo FlagsCSV = x.FlagsCsv, } ); - ClosedXmlHelper.AddSheetToWorkbook(workbook, CompetenciesSheetName, competencies, TableTheme); + ClosedXmlHelper.RenameWorksheetColumn(workbook, "CompetencyGroup", vocabulary + "Group"); + ClosedXmlHelper.RenameWorksheetColumn(workbook, "Competency", vocabulary); + ClosedXmlHelper.RenameWorksheetColumn(workbook, "CompetencyDescription", vocabulary + "Description"); } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/Frameworks/ImportCompetenciesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesFormData.cs similarity index 69% rename from DigitalLearningSolutions.Web/ViewModels/Frameworks/ImportCompetenciesViewModel.cs rename to DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesFormData.cs index 27fa9f38b6..98604cc8ee 100644 --- a/DigitalLearningSolutions.Web/ViewModels/Frameworks/ImportCompetenciesViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesFormData.cs @@ -1,13 +1,11 @@ -namespace DigitalLearningSolutions.Web.ViewModels.Frameworks +namespace DigitalLearningSolutions.Web.ViewModels.Frameworks.Import { using DigitalLearningSolutions.Web.Attributes; using Microsoft.AspNetCore.Http; using System.ComponentModel.DataAnnotations; - public class ImportCompetenciesViewModel + public class ImportCompetenciesFormData { - public int FrameworkId { get; set; } - public bool IsNotBlank { get; set; } [Required(ErrorMessage = "Import competencies file is required")] [AllowedExtensions(new[] { ".xlsx" }, "Import competencies file must be in xlsx format")] [MaxFileSize(5 * 1024 * 1024, "Maximum allowed file size is 5MB")] diff --git a/DigitalLearningSolutions.Web/ViewModels/Frameworks/ImportCompetenciesPreProcessViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesPreProcessViewModel.cs similarity index 59% rename from DigitalLearningSolutions.Web/ViewModels/Frameworks/ImportCompetenciesPreProcessViewModel.cs rename to DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesPreProcessViewModel.cs index fac6c884c1..f92f056115 100644 --- a/DigitalLearningSolutions.Web/ViewModels/Frameworks/ImportCompetenciesPreProcessViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesPreProcessViewModel.cs @@ -3,21 +3,29 @@ using DigitalLearningSolutions.Web.Models; using System.Linq; using DigitalLearningSolutions.Data.Models.Frameworks.Import; +using DigitalLearningSolutions.Web.Helpers; -namespace DigitalLearningSolutions.Web.ViewModels.Frameworks +namespace DigitalLearningSolutions.Web.ViewModels.Frameworks.Import { public class ImportCompetenciesPreProcessViewModel { - public ImportCompetenciesPreProcessViewModel(ImportCompetenciesResult bulkCompetenciesResult) + public ImportCompetenciesPreProcessViewModel(ImportCompetenciesResult bulkCompetenciesResult, BulkCompetenciesData bulkCompetenciesData) { + FrameworkName = bulkCompetenciesData.FrameworkName; + PublishStatusID = bulkCompetenciesData.PublishStatusID; + FrameworkVocabularySingular = FrameworkVocabularyHelper.VocabularySingular(bulkCompetenciesData.FrameworkVocubulary); + FrameworkVocabularyPlural = FrameworkVocabularyHelper.VocabularyPlural(bulkCompetenciesData.FrameworkVocubulary); ToProcessCount = bulkCompetenciesResult.ProcessedCount; CompetenciesToAddCount = bulkCompetenciesResult.CompetencyAddedCount; - CompetenciesToUpdateCount = bulkCompetenciesResult.CompetencyUpdatedCount; + ToUpdateOrSkipCount = bulkCompetenciesResult.CompetencyUpdatedCount; CompetencyGroupsToAddCount = bulkCompetenciesResult.GroupAddedCount; CompetencyGroupsToUpdateCount = bulkCompetenciesResult.GroupUpdatedCount; - Errors = bulkCompetenciesResult.Errors.Select(x => (x.RowNumber, MapReasonToErrorMessage(x.Reason))); + Errors = bulkCompetenciesResult.Errors.Select(x => (x.RowNumber, MapReasonToErrorMessage(x.Reason, FrameworkVocabularyHelper.VocabularySingular(bulkCompetenciesData.FrameworkVocubulary)))); } - + public string? FrameworkName { get; set; } + public int PublishStatusID { get; set; } + public string FrameworkVocabularySingular { get; set; } + public string FrameworkVocabularyPlural { get; set; } public IEnumerable<(int RowNumber, string ErrorMessage)> Errors { get; set; } public int ErrorCount => Errors.Count(); public int ToProcessCount { get; set; } @@ -30,18 +38,18 @@ public ImportCompetenciesPreProcessViewModel(ImportCompetenciesResult bulkCompet public bool IsNotBlank { get; set; } public string TabName { get; set; } - private static string MapReasonToErrorMessage(ImportCompetenciesResult.ErrorReason reason) + private static string MapReasonToErrorMessage(ImportCompetenciesResult.ErrorReason reason, string vocabularySingular) { return reason switch { ImportCompetenciesResult.ErrorReason.TooLongCompetencyGroupName => "Group name must be 255 characters or less.", ImportCompetenciesResult.ErrorReason.MissingCompetencyName => - "Competency is blank. Competency is a required field and cannot be left blank", + vocabularySingular + " is blank. " + vocabularySingular + " is a required field and cannot be left blank", ImportCompetenciesResult.ErrorReason.InvalidId => - "The ID provided does not match a Competency ID in this Framework", + "The ID provided does not match a " + vocabularySingular + " ID in this Framework", ImportCompetenciesResult.ErrorReason.TooLongCompetencyName => - "Competency must be 255 characters or less.", + vocabularySingular + " must be 500 characters or less.", ImportCompetenciesResult.ErrorReason.InvalidAlwaysShowDescription => "Always show description is invalid. The Always show description field must contain 'TRUE' or 'FALSE'", _ => "Unspecified error.", diff --git a/DigitalLearningSolutions.Web/ViewModels/Frameworks/ImportCompetenciesResultsViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesResultsViewModel.cs similarity index 94% rename from DigitalLearningSolutions.Web/ViewModels/Frameworks/ImportCompetenciesResultsViewModel.cs rename to DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesResultsViewModel.cs index d76b0338ae..b47108fe15 100644 --- a/DigitalLearningSolutions.Web/ViewModels/Frameworks/ImportCompetenciesResultsViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesResultsViewModel.cs @@ -1,4 +1,4 @@ -namespace DigitalLearningSolutions.Web.ViewModels.Frameworks +namespace DigitalLearningSolutions.Web.ViewModels.Frameworks.Import { using DigitalLearningSolutions.Data.Models.Frameworks.Import; using System.Collections.Generic; @@ -28,6 +28,7 @@ private string MapReasonToErrorMessage(ImportCompetenciesResult.ErrorReason reas "Competency name was not provided. Competency name is a required field and cannot be left blank", ImportCompetenciesResult.ErrorReason.TooLongCompetencyName => "Competency name must be 500 characters or fewer", ImportCompetenciesResult.ErrorReason.TooLongCompetencyGroupName => "Competency group name must be 255 characters or fewer", + _ => "Unknown error", }; } } diff --git a/DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesViewModel.cs new file mode 100644 index 0000000000..698b278dc1 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/Frameworks/Import/ImportCompetenciesViewModel.cs @@ -0,0 +1,25 @@ +namespace DigitalLearningSolutions.Web.ViewModels.Frameworks.Import +{ + using DigitalLearningSolutions.Data.Models.Frameworks; + using DigitalLearningSolutions.Web.Helpers; + + public class ImportCompetenciesViewModel : ImportCompetenciesFormData + { + public ImportCompetenciesViewModel(DetailFramework framework, bool isNotBlank) + { + FrameworkID = framework.ID; + FrameworkName = framework.FrameworkName; + FrameworkVocabularySingular = FrameworkVocabularyHelper.VocabularySingular(framework.FrameworkConfig); + FrameworkVocabularyPlural = FrameworkVocabularyHelper.VocabularyPlural(framework.FrameworkConfig); + PublishStatusID = framework.PublishStatusID; + IsNotBlank = isNotBlank; + } + public int FrameworkID { get; set; } + public string FrameworkName { get; set; } + public string FrameworkVocabularySingular { get; set; } + public string FrameworkVocabularyPlural { get; set; } + public int PublishStatusID { get; set; } + public bool IsNotBlank { get; set; } + + } +} diff --git a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/ImportCompleted.cshtml b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/ImportCompleted.cshtml new file mode 100644 index 0000000000..1db1e511ba --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/ImportCompleted.cshtml @@ -0,0 +1,85 @@ +@inject IConfiguration Configuration +@using DigitalLearningSolutions.Web.Extensions +@using DigitalLearningSolutions.Web.ViewModels.Frameworks.Import +@using Microsoft.Extensions.Configuration +@model ImportCompetenciesPreProcessViewModel +@{ + ViewData["Title"] = "Framework - Import Competencies"; + ViewData["Application"] = "Framework Service"; + ViewData["HeaderPathName"] = "Framework Service"; + var errorHasOccurred = !ViewData.ModelState.IsValid; + var cancelLinkData = Html.GetRouteValues(); +} + +@section NavMenuItems { + +} +@section NavBreadcrumbs { + +} +

Delegate file uploaded

+
+

@(Model.ErrorCount == 0 ? "Your file is error free and ready to be processed. Check the information below looks, correct before processing" : "Your file contains the following, including some errors:")

+
    +
  • @Model.ToProcessCount @(Model.ToProcessCount == 1 ? "row" : "rows") to process
  • +
  • @Model.CompetenciesToAddCount new @(Model.CompetenciesToAddCount == 1 ? Model.FrameworkVocabularySingular.ToLower() : Model.FrameworkVocabularyPlural.ToLower()) to add
  • +
  • @Model.ToUpdateOrSkipCount @Model.FrameworkVocabularySingular.ToLower() @(Model.ToUpdateOrSkipCount == 1 ? "record" : "records") to update (or skip if unchanged)
  • + @if (Model.ErrorCount > 0) + { +
  • @Model.ErrorCount @(Model.ErrorCount == 1 ? "row" : "rows") containing errors that cannot be processed
  • + } + else + { +
  • No errors
  • + } +
+ @if (Model.ErrorCount == 0) + { + Continue + } + else + { +

Check the information below. You will need fix these errors before continuing or remove the rows with errors from your spreadsheet:

+
+ + Error: @Model.ErrorCount @Model.FrameworkVocabularySingular.ToLower() @(Model.ErrorCount == 1 ? "row" : "rows") contain errors and cannot be processed + +
+ @foreach (var (rowNumber, errorMessage) in Model.Errors) + { +
+
+ Row @rowNumber +
+
+ @errorMessage +
+ +
+ } +
+
+

Upload corrected file

+

+ Once you have made corrections to the Excel competency workbook to address the errors above, save and restart the upload process. +

+
+ + + + + + + + } + +
diff --git a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/ImportFailed.cshtml b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/ImportFailed.cshtml new file mode 100644 index 0000000000..c16803e9df --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/ImportFailed.cshtml @@ -0,0 +1,45 @@ +@inject IConfiguration Configuration +@using DigitalLearningSolutions.Web.Extensions +@using DigitalLearningSolutions.Web.ViewModels.Frameworks.Import +@using Microsoft.Extensions.Configuration +@model ImportCompetenciesResultsViewModel +@{ + ViewData["Title"] = "Framework - Import Failed"; + ViewData["Application"] = "Framework Service"; + ViewData["HeaderPathName"] = "Framework Service"; + var errorHasOccurred = !ViewData.ModelState.IsValid; + var cancelLinkData = Html.GetRouteValues(); +} + +@section NavMenuItems { + +} +@section NavBreadcrumbs { + +} + +
+
+

Import failed

+
+

+ The file that you uploaded either does not have the correct column headers on the first row or is not formatted as a table. +

+ +

Refer to the instructions on the Import Competencies page to make sure your Excel file has the correct column headers.

+ + + + +
+
+
diff --git a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/Index.cshtml b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/Index.cshtml new file mode 100644 index 0000000000..649f7a608f --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/Index.cshtml @@ -0,0 +1,116 @@ +@using DigitalLearningSolutions.Web.Extensions +@using DigitalLearningSolutions.Web.ViewModels.Frameworks.Import +@model ImportCompetenciesViewModel +@{ + ViewData["Application"] = "Framework Service"; + ViewData["HeaderPathName"] = "Framework Service"; + var errorHasOccurred = !ViewData.ModelState.IsValid; + ViewData["Title"] = errorHasOccurred ? "Error: Bulk upload " + Model.FrameworkVocabularyPlural.ToLower() : "Bulk upload " + Model.FrameworkVocabularyPlural.ToLower(); + var cancelLinkData = Html.GetRouteValues(); +} + +@section NavMenuItems { + +} +@section NavBreadcrumbs { + +} +
+
+ @if (errorHasOccurred) + { + + } +

Bulk upload @(Model.IsNotBlank ? "or update" : "") @Model.FrameworkVocabularyPlural.ToLower()

+
+ @if (Model.PublishStatusID == 3) + { + + } + @* *@ +
+ @if (Model.IsNotBlank) + { + +

+ To bulk add and/or update @Model.FrameworkVocabularyPlural.ToLower() in the framework, @Model.FrameworkName, download an Excel workbook using one of the options below. +

+
+
+ +

+ What would you like to download? +

+
+
+ Select one option +
+
+
+ + +
+
+
+ This Excel file will be empty.
+ New @Model.FrameworkVocabularyPlural.ToLower() can be added by including their details on a blank row. +
+ + Download template + +
+
+ + +
+
+
+ This Excel file will include all existing @Model.FrameworkVocabularyPlural.ToLower() whose details you can update.
+ New @Model.FrameworkVocabularyPlural.ToLower() can be added by including their details on a blank row. +
+ + Download @Model.FrameworkVocabularyPlural.ToLower() + +
+
+
+
+ } + else + { +

+ Download a blank template for bulk adding @Model.FrameworkVocabularyPlural.ToLower() to your framework, @Model.FrameworkName. This Excel file will be empty. New @Model.FrameworkVocabularyPlural.ToLower() can be added by including their details on a blank row. +

+ + Download template + + } + +
+ +

Upload file

+

+ Once you have an Excel @Model.FrameworkVocabularyPlural.ToLower() workbook, add or update @Model.FrameworkVocabularyPlural.ToLower() to the worksheet, save and start the upload process. +

+
+ + + + + +
+
+
diff --git a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/UploadResults.cshtml b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/UploadResults.cshtml new file mode 100644 index 0000000000..16aac10fde --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/Import/UploadResults.cshtml @@ -0,0 +1,65 @@ +@inject IConfiguration Configuration +@using DigitalLearningSolutions.Web.Extensions +@using DigitalLearningSolutions.Web.ViewModels.Frameworks.Import +@using Microsoft.Extensions.Configuration +@model ImportCompetenciesResultsViewModel +@{ + ViewData["Title"] = "Framework - Import Competencies"; + ViewData["Application"] = "Framework Service"; + ViewData["HeaderPathName"] = "Framework Service"; + var errorHasOccurred = !ViewData.ModelState.IsValid; + var cancelLinkData = Html.GetRouteValues(); +} + +@section NavMenuItems { + +} +@section NavBreadcrumbs { + +} + +
+
+

Import competencies complete

+
+

Summary of results:

+
    +
  • @Model.ProcessedCount @(Model.ProcessedCount == 1 ? "line" : "lines") processed
  • +
  • @Model.CompetencyGroupsInsertedCount new @(Model.CompetencyGroupsInsertedCount == 1 ? "competency group" : "competency groups") inserted
  • +
  • @Model.CompetenciesInsertedCount new @(Model.CompetenciesInsertedCount == 1 ? "competency" : "competencies") inserted
  • +
  • @Model.SkippedCount rows @(Model.SkippedCount == 1 ? "record" : "records") skipped (nothing inserted but no errors)
  • +
  • @Model.ErrorCount @(Model.ErrorCount == 1 ? "line" : "lines") skipped due to errors
  • +
+ + @if (Model.ErrorCount > 0) + { +
+

+ + Important: + The imported Excel worksheet contained errors + +

+

The lines below were skipped due to errors during processing:

+
    + @foreach (var (rowNumber, errorMessage) in Model.Errors) + { +
  • Line @rowNumber: @errorMessage
  • + } +
+
+ } + + +
+
+
diff --git a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/ImportCompetencies.cshtml b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/ImportCompetencies.cshtml deleted file mode 100644 index 56ae470de0..0000000000 --- a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/ImportCompetencies.cshtml +++ /dev/null @@ -1,110 +0,0 @@ -@using DigitalLearningSolutions.Web.Extensions -@using DigitalLearningSolutions.Web.ViewModels.Frameworks -@model ImportCompetenciesViewModel -@{ - ViewData["Application"] = "Framework Service"; - ViewData["HeaderPathName"] = "Framework Service"; - var errorHasOccurred = !ViewData.ModelState.IsValid; - ViewData["Title"] = errorHasOccurred ? "Error: Bulk upload competencies" : "Bulk upload competencies"; - var cancelLinkData = Html.GetRouteValues(); -} - -@section NavMenuItems { - -} -@section NavBreadcrumbs { - -} -
-
- @if (errorHasOccurred) - { - - } -

Bulk upload @(Model.IsNotBlank ? "or update" : "") competencies

- -
- @if (Model.IsNotBlank) - { - -

- To bulk add and/or update competencies in your framework, download an Excel workbook using one of the options below. -

-
-
- -

- What would you like to download? -

-
-
- Select one option -
-
-
- - -
-
-
- This Excel file will be empty.
- New competencies can be added by including their details on a blank row. -
- - Download template - -
-
- - -
-
-
- This Excel file will include all existing competencies whose details you can update.
- New competencies can be added by including their details on a blank row. -
- - Download competencies - -
-
-
-
- } - else - { -

- Download a blank template for bulk adding competencies to your framework. This Excel file will be empty. New competencies can be added by including their details on a blank row. -

- - Download template - - } - -
- -

Upload file

-

- Once you have an Excel competencies workbook, add or update competencies to the worksheet, save and start the upload process. -

-
- - - - - -
-
diff --git a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/ImportCompleted.cshtml b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/ImportCompleted.cshtml deleted file mode 100644 index 5b355f572e..0000000000 --- a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/ImportCompleted.cshtml +++ /dev/null @@ -1,83 +0,0 @@ -@inject IConfiguration Configuration -@using DigitalLearningSolutions.Web.Extensions -@using DigitalLearningSolutions.Web.ViewModels.Frameworks -@using Microsoft.Extensions.Configuration -@model ImportCompetenciesPreProcessViewModel -@{ - ViewData["Title"] = "Framework - Import Competencies"; - ViewData["Application"] = "Framework Service"; - ViewData["HeaderPathName"] = "Framework Service"; - var errorHasOccurred = !ViewData.ModelState.IsValid; - var cancelLinkData = Html.GetRouteValues(); -} - -@section NavMenuItems { - -} -@section NavBreadcrumbs { - -} -

Delegate file uploaded

-

@(Model.ErrorCount == 0 ? "Your file is error free and ready to be processed. Check the information below looks, correct before processing" : "Your file contains the following, including some errors:")

-
    -
  • @Model.ToProcessCount @(Model.ToProcessCount == 1 ? "row" : "rows") to process
  • -
  • @Model.CompetenciesToAddCount new @(Model.CompetenciesToAddCount == 1 ? "competency" : "competencies") to add
  • -
  • @Model.ToUpdateOrSkipCount delegate @(Model.ToUpdateOrSkipCount == 1 ? "record" : "records") to update (or skip if unchanged)
  • - @if (Model.ErrorCount > 0) - { -
  • @Model.ErrorCount @(Model.ErrorCount == 1 ? "row" : "rows") containing errors that cannot be processed
  • - } - else - { -
  • No errors
  • - } -
-@if (Model.ErrorCount == 0) -{ - Continue -} -else -{ -

Check the information below. You will need fix these errors before continuing or remove the rows with errors from your spreadsheet:

-
- - Error: @Model.ErrorCount delegate @(Model.ErrorCount == 1 ? "row" : "rows") contain errors and cannot be processed - -
- @foreach (var (rowNumber, errorMessage) in Model.Errors) - { -
-
- Row @rowNumber -
-
- @errorMessage -
- -
- } -
-
-

Upload corrected file

-

- Once you have made corrections to the Excel competency workbook to address the errors above, save and restart the upload process. -

-
- - - - - - - -} - diff --git a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/ImportFailed.cshtml b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/ImportFailed.cshtml deleted file mode 100644 index 0176c0b656..0000000000 --- a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/ImportFailed.cshtml +++ /dev/null @@ -1,44 +0,0 @@ -@inject IConfiguration Configuration -@using DigitalLearningSolutions.Web.Extensions -@using DigitalLearningSolutions.Web.ViewModels.Frameworks -@using Microsoft.Extensions.Configuration -@model ImportCompetenciesResultsViewModel -@{ - ViewData["Title"] = "Framework - Import Failed"; - ViewData["Application"] = "Framework Service"; - ViewData["HeaderPathName"] = "Framework Service"; - var errorHasOccurred = !ViewData.ModelState.IsValid; - var cancelLinkData = Html.GetRouteValues(); -} - -@section NavMenuItems { - -} - @section NavBreadcrumbs { - -} - -
-
-

Import failed

- -

- The file that you uploaded either does not have the correct column headers on the first row or is not formatted as a table. -

- -

Refer to the instructions on the Import Competencies page to make sure your Excel file has the correct column headers.

- - - - -
-
diff --git a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/UploadResults.cshtml b/DigitalLearningSolutions.Web/Views/Frameworks/Developer/UploadResults.cshtml deleted file mode 100644 index fefffeae4f..0000000000 --- a/DigitalLearningSolutions.Web/Views/Frameworks/Developer/UploadResults.cshtml +++ /dev/null @@ -1,64 +0,0 @@ -@inject IConfiguration Configuration -@using DigitalLearningSolutions.Web.Extensions -@using DigitalLearningSolutions.Web.ViewModels.Frameworks -@using Microsoft.Extensions.Configuration -@model ImportCompetenciesResultsViewModel -@{ - ViewData["Title"] = "Framework - Import Competencies"; - ViewData["Application"] = "Framework Service"; - ViewData["HeaderPathName"] = "Framework Service"; - var errorHasOccurred = !ViewData.ModelState.IsValid; - var cancelLinkData = Html.GetRouteValues(); -} - -@section NavMenuItems { - -} - @section NavBreadcrumbs { - -} - -
-
-

Import competencies complete

- -

Summary of results:

-
    -
  • @Model.ProcessedCount @(Model.ProcessedCount == 1 ? "line" : "lines") processed
  • -
  • @Model.CompetencyGroupsInsertedCount new @(Model.CompetencyGroupsInsertedCount == 1 ? "competency group" : "competency groups") inserted
  • -
  • @Model.CompetenciesInsertedCount new @(Model.CompetenciesInsertedCount == 1 ? "competency" : "competencies") inserted
  • -
  • @Model.SkippedCount rows @(Model.SkippedCount == 1 ? "record" : "records") skipped (nothing inserted but no errors)
  • -
  • @Model.ErrorCount @(Model.ErrorCount == 1 ? "line" : "lines") skipped due to errors
  • -
- - @if (Model.ErrorCount > 0) - { -
-

- - Important: - The imported Excel worksheet contained errors - -

-

The lines below were skipped due to errors during processing:

-
    - @foreach (var (rowNumber, errorMessage) in Model.Errors) - { -
  • Line @rowNumber: @errorMessage
  • - } -
-
- } - - -
-