diff --git a/DigitalLearningSolutions.Data.Migrations/202508181154_CreateOrAlterMoveCompetenciesAndGroups.cs b/DigitalLearningSolutions.Data.Migrations/202508181154_CreateOrAlterMoveCompetenciesAndGroups.cs new file mode 100644 index 0000000000..60ac1b3cfb --- /dev/null +++ b/DigitalLearningSolutions.Data.Migrations/202508181154_CreateOrAlterMoveCompetenciesAndGroups.cs @@ -0,0 +1,19 @@ +namespace DigitalLearningSolutions.Data.Migrations +{ + using FluentMigrator; + [Migration(202508181154)] + public class CreateOrAlterMoveCompetenciesAndGroups : Migration + { + public override void Up() + { + Execute.Sql(Properties.Resources.TD_483_uspMoveCompetencyInSelfAssessmentCreateOrAlter_UP); + Execute.Sql(Properties.Resources.TD_483_uspMoveCompetencyGroupInSelfAssessmentCreateOrAlter_UP); + } + public override void Down() + { + Execute.Sql("DROP PROCEDURE IF EXISTS [dbo].[usp_MoveCompetencyGroupInSelfAssessment]"); + Execute.Sql("DROP PROCEDURE IF EXISTS [dbo].[usp_MoveCompetencyInSelfAssessment]"); + Execute.Sql("DROP PROCEDURE IF EXISTS [dbo].[usp_RenumberSelfAssessmentStructure]"); + } + } +} diff --git a/DigitalLearningSolutions.Data.Migrations/Properties/Resources.Designer.cs b/DigitalLearningSolutions.Data.Migrations/Properties/Resources.Designer.cs index 631af7bc66..853e2c3623 100644 --- a/DigitalLearningSolutions.Data.Migrations/Properties/Resources.Designer.cs +++ b/DigitalLearningSolutions.Data.Migrations/Properties/Resources.Designer.cs @@ -2237,6 +2237,58 @@ internal static string TD_4634_Alter_GetCompletedCoursesForCandidate_UP { } } + /// + /// Looks up a localized string similar to + ///CREATE OR ALTER PROCEDURE usp_RenumberSelfAssessmentStructure + /// @SelfAssessmentID INT + ///AS + ///BEGIN + /// SET NOCOUNT ON; + /// + /// /* + /// Step 1: Build an ordered list of groups + /// - Each group is ranked by its current Min(Ordering) + /// - Ungrouped competencies (NULL CompetencyGroupID) are treated as their own "pseudo group" + /// */ + /// ;WITH GroupRanks AS ( + /// SELECT + /// CompetencyGroupID, + /// ROW_NUMBER() OVER (ORDER BY MIN(Ordering)) AS GroupRank + /// FROM Sel [rest of string was truncated]";. + /// + internal static string TD_483_uspMoveCompetencyGroupInSelfAssessmentCreateOrAlter_UP { + get { + return ResourceManager.GetString("TD-483-uspMoveCompetencyGroupInSelfAssessmentCreateOrAlter_UP", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to CREATE OR ALTER PROCEDURE usp_MoveCompetencyInSelfAssessment + /// @SelfAssessmentID INT, + /// @CompetencyID INT, + /// @Direction NVARCHAR(10) + ///AS + ///BEGIN + /// SET NOCOUNT ON; + /// + /// DECLARE @GroupID INT, @CurrentOrder INT; + /// + /// SELECT + /// @GroupID = CompetencyGroupID, + /// @CurrentOrder = Ordering + /// FROM SelfAssessmentStructure + /// WHERE SelfAssessmentID = @SelfAssessmentID AND CompetencyID = @CompetencyID; + /// + /// IF @GroupID IS NULL + /// BEGIN + /// -- Can't reorder ungrouped competencies [rest of string was truncated]";. + /// + internal static string TD_483_uspMoveCompetencyInSelfAssessmentCreateOrAlter_UP { + get { + return ResourceManager.GetString("TD-483-uspMoveCompetencyInSelfAssessmentCreateOrAlter_UP", resourceCulture); + } + } + /// /// Looks up a localized string similar to /****** Object: StoredProcedure [dbo].[GetActivitiesForDelegateEnrolment] Script Date: 22/10/2024 16:55:08 ******/ ///SET ANSI_NULLS ON diff --git a/DigitalLearningSolutions.Data.Migrations/Properties/Resources.resx b/DigitalLearningSolutions.Data.Migrations/Properties/Resources.resx index 41e1de40a2..34cedd5de9 100644 --- a/DigitalLearningSolutions.Data.Migrations/Properties/Resources.resx +++ b/DigitalLearningSolutions.Data.Migrations/Properties/Resources.resx @@ -499,6 +499,12 @@ ..\Scripts\TD-5759_CreateOrAlterSelfAssessmentReportSPandTVF-Fix_UP.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + ..\Scripts\TD-483-uspMoveCompetencyInSelfAssessmentCreateOrAlter_UP.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ..\Scripts\TD-483-uspMoveCompetencyGroupInSelfAssessmentCreateOrAlter_UP.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + ..\Scripts\TD-5535-Alter_GetActivitiesForDelegateEnrolment_Down.sql;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16 diff --git a/DigitalLearningSolutions.Data.Migrations/Scripts/TD-483-uspMoveCompetencyGroupInSelfAssessmentCreateOrAlter_UP.sql b/DigitalLearningSolutions.Data.Migrations/Scripts/TD-483-uspMoveCompetencyGroupInSelfAssessmentCreateOrAlter_UP.sql new file mode 100644 index 0000000000..f42d8894c7 --- /dev/null +++ b/DigitalLearningSolutions.Data.Migrations/Scripts/TD-483-uspMoveCompetencyGroupInSelfAssessmentCreateOrAlter_UP.sql @@ -0,0 +1,164 @@ + +CREATE OR ALTER PROCEDURE usp_RenumberSelfAssessmentStructure + @SelfAssessmentID INT +AS +BEGIN + SET NOCOUNT ON; + + /* + Step 1: Build an ordered list of groups + - Each group is ranked by its current Min(Ordering) + - Ungrouped competencies (NULL CompetencyGroupID) are treated as their own "pseudo group" + */ + ;WITH GroupRanks AS ( + SELECT + CompetencyGroupID, + ROW_NUMBER() OVER (ORDER BY MIN(Ordering)) AS GroupRank + FROM SelfAssessmentStructure + WHERE SelfAssessmentID = @SelfAssessmentID + GROUP BY CompetencyGroupID + ) + /* + Step 2: Renumber groups and competencies + - Groups get ranked (1,2,3…) + - Within each group, competencies are ordered by their current Ordering and renumbered (1,2,3…) + */ + UPDATE sas + SET sas.Ordering = rn.NewOrdering + FROM SelfAssessmentStructure sas + INNER JOIN ( + SELECT + s.ID, + -- new group position * 1000 + row within group + -- gives room between groups and avoids clashes + (g.GroupRank * 1000) + + ROW_NUMBER() OVER (PARTITION BY s.CompetencyGroupID, g.GroupRank ORDER BY s.Ordering, s.ID) AS NewOrdering + FROM SelfAssessmentStructure s + INNER JOIN GroupRanks g + ON g.CompetencyGroupID = s.CompetencyGroupID + WHERE s.SelfAssessmentID = @SelfAssessmentID + ) rn ON sas.ID = rn.ID; + +END + +GO + +CREATE OR ALTER PROCEDURE usp_MoveCompetencyGroupInSelfAssessment + @SelfAssessmentID INT, + @GroupID INT, + @Direction NVARCHAR(10) -- 'up' or 'down' +AS +BEGIN + SET NOCOUNT ON; + SET XACT_ABORT ON; + + BEGIN TRY + BEGIN TRAN; + + /* 1) Rank groups by current Min(Ordering) (NULL groups excluded here; include if desired). */ + ;WITH GroupRanks AS ( + SELECT + CompetencyGroupID, + MIN(Ordering) AS MinOrder, + ROW_NUMBER() OVER ( + ORDER BY MIN(Ordering), MIN(CompetencyGroupID) + ) AS RankPos + FROM SelfAssessmentStructure + WHERE SelfAssessmentID = @SelfAssessmentID + AND CompetencyGroupID IS NOT NULL + GROUP BY CompetencyGroupID + ) + SELECT * + INTO #Groups + FROM GroupRanks; + + DECLARE @CurRank INT, @SwapRank INT, @SwapGroupID INT; + + SELECT @CurRank = RankPos + FROM #Groups + WHERE CompetencyGroupID = @GroupID; + + IF @CurRank IS NULL + BEGIN + DROP TABLE #Groups; + COMMIT TRAN; RETURN; -- nothing to do + END + + IF LOWER(@Direction) = 'up' + SET @SwapRank = @CurRank - 1; + ELSE IF LOWER(@Direction) = 'down' + SET @SwapRank = @CurRank + 1; + ELSE + BEGIN + DROP TABLE #Groups; + ROLLBACK TRAN; THROW 50000, 'Direction must be ''up'' or ''down''.', 1; + END + + SELECT @SwapGroupID = CompetencyGroupID + FROM #Groups + WHERE RankPos = @SwapRank; + + IF @SwapGroupID IS NULL + BEGIN + DROP TABLE #Groups; + COMMIT TRAN; RETURN; -- already at top/bottom + END + + /* 2) Build a mapping where ONLY the two groups swap ranks; others keep theirs. */ + SELECT + g.CompetencyGroupID, + CASE + WHEN g.CompetencyGroupID = @GroupID THEN @SwapRank + WHEN g.CompetencyGroupID = @SwapGroupID THEN @CurRank + ELSE g.RankPos + END AS NewRank + INTO #RankMap + FROM #Groups g; + + /* 3) Choose a block size big enough to keep groups separated when we recompute. + Using count(rows in this self assessment) + 10 is a safe dynamic choice. */ + DECLARE @Block INT = + (SELECT COUNT(*) FROM SelfAssessmentStructure WHERE SelfAssessmentID = @SelfAssessmentID) + 10; + + /* 4) Recompute EVERY row’s Ordering from the rank map (this sets the new global order). + We preserve within-group relative order using the existing Ordering (and ID as tiebreak). */ + ;WITH NewOrders AS ( + SELECT + s.ID, + (m.NewRank * @Block) + + ROW_NUMBER() OVER ( + PARTITION BY s.CompetencyGroupID + ORDER BY s.Ordering, s.ID + ) AS NewOrdering + FROM SelfAssessmentStructure s + JOIN #RankMap m + ON m.CompetencyGroupID = s.CompetencyGroupID + WHERE s.SelfAssessmentID = @SelfAssessmentID + ) + UPDATE s + SET s.Ordering = n.NewOrdering + FROM SelfAssessmentStructure s + JOIN NewOrders n ON n.ID = s.ID; + + /* 5) (Optional) Compress to 1..N while keeping the just-established relative order. */ + ;WITH Ordered AS ( + SELECT ID, + ROW_NUMBER() OVER (ORDER BY Ordering, ID) AS Seq + FROM SelfAssessmentStructure + WHERE SelfAssessmentID = @SelfAssessmentID + ) + UPDATE s + SET s.Ordering = o.Seq + FROM SelfAssessmentStructure s + JOIN Ordered o ON o.ID = s.ID; + + DROP TABLE #Groups; + DROP TABLE #RankMap; + + COMMIT TRAN; + END TRY + BEGIN CATCH + IF @@TRANCOUNT > 0 ROLLBACK TRAN; + THROW; + END CATCH +END; diff --git a/DigitalLearningSolutions.Data.Migrations/Scripts/TD-483-uspMoveCompetencyInSelfAssessmentCreateOrAlter_UP.sql b/DigitalLearningSolutions.Data.Migrations/Scripts/TD-483-uspMoveCompetencyInSelfAssessmentCreateOrAlter_UP.sql new file mode 100644 index 0000000000..176422b549 --- /dev/null +++ b/DigitalLearningSolutions.Data.Migrations/Scripts/TD-483-uspMoveCompetencyInSelfAssessmentCreateOrAlter_UP.sql @@ -0,0 +1,59 @@ +CREATE OR ALTER PROCEDURE usp_MoveCompetencyInSelfAssessment + @SelfAssessmentID INT, + @CompetencyID INT, + @Direction NVARCHAR(10) +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @GroupID INT, @CurrentOrder INT; + + SELECT + @GroupID = CompetencyGroupID, + @CurrentOrder = Ordering + FROM SelfAssessmentStructure + WHERE SelfAssessmentID = @SelfAssessmentID AND CompetencyID = @CompetencyID; + + IF @GroupID IS NULL + BEGIN + -- Can't reorder ungrouped competencies via group-based logic + RETURN; + END + + DECLARE @TargetCompetencyID INT, @TargetOrder INT; + + IF @Direction = 'up' + BEGIN + SELECT TOP 1 + @TargetCompetencyID = CompetencyID, + @TargetOrder = Ordering + FROM SelfAssessmentStructure + WHERE SelfAssessmentID = @SelfAssessmentID + AND CompetencyGroupID = @GroupID + AND Ordering < @CurrentOrder + ORDER BY Ordering DESC; + END + ELSE IF @Direction = 'down' + BEGIN + SELECT TOP 1 + @TargetCompetencyID = CompetencyID, + @TargetOrder = Ordering + FROM SelfAssessmentStructure + WHERE SelfAssessmentID = @SelfAssessmentID + AND CompetencyGroupID = @GroupID + AND Ordering > @CurrentOrder + ORDER BY Ordering ASC; + END + + IF @TargetCompetencyID IS NOT NULL + BEGIN + -- Swap the orderings + UPDATE SelfAssessmentStructure + SET Ordering = @TargetOrder + WHERE SelfAssessmentID = @SelfAssessmentID AND CompetencyID = @CompetencyID; + + UPDATE SelfAssessmentStructure + SET Ordering = @CurrentOrder + WHERE SelfAssessmentID = @SelfAssessmentID AND CompetencyID = @TargetCompetencyID; + END +END diff --git a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs index 2f597dc696..c07c7f4e43 100644 --- a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs @@ -1,15 +1,12 @@ namespace DigitalLearningSolutions.Data.DataServices { + using Dapper; + using DigitalLearningSolutions.Data.Models.CompetencyAssessments; + using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Data; using System.Linq; - using Dapper; - using DigitalLearningSolutions.Data.Models.Common; - using DigitalLearningSolutions.Data.Models.CompetencyAssessments; - using DigitalLearningSolutions.Data.Models.Frameworks; - using DocumentFormat.OpenXml.Wordprocessing; - using Microsoft.Extensions.Logging; public interface ICompetencyAssessmentDataService { @@ -28,12 +25,16 @@ public interface ICompetencyAssessmentDataService CompetencyAssessmentTaskStatus GetOrInsertAndReturnAssessmentTaskStatus(int assessmentId, bool frameworkBased); - int[] GetLinkedFrameworkIds (int assessmentId); + int[] GetLinkedFrameworkIds(int assessmentId); int? GetPrimaryLinkedFrameworkId(int assessmentId); int GetCompetencyCountByFrameworkId(int assessmentId, int frameworkId); + IEnumerable GetCompetenciesForCompetencyAssessment(int competencyAssessmentId); + IEnumerable GetLinkedFrameworksForCompetencyAssessment(int competencyAssessmentId); + int[] GetLinkedFrameworkCompetencyIds(int competencyAssessmentId, int frameworkId); + //UPDATE DATA bool UpdateCompetencyAssessmentName(int competencyAssessmentId, int adminId, string competencyAssessmentName); @@ -55,14 +56,23 @@ int categoryId bool UpdateSelectCompetenciesTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); bool UpdateOptionalCompetenciesTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); bool UpdateRoleRequirementsTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); + void MoveCompetencyInSelfAssessment(int competencyAssessmentId, + int competencyId, + string direction + ); + void MoveCompetencyGroupInSelfAssessment(int competencyAssessmentId, + int groupId, + string direction + ); //INSERT DATA int InsertCompetencyAssessment(int adminId, int centreId, string competencyAssessmentName); bool InsertSelfAssessmentFramework(int adminId, int selfAssessmentId, int frameworkId); + bool InsertCompetenciesIntoAssessmentFromFramework(int[] selectedCompetencyIds, int frameworkId, int competencyAssessmentId); //DELETE DATA bool RemoveFrameworkCompetenciesFromAssessment(int competencyAssessmentId, int frameworkId); - + bool RemoveCompetencyFromAssessment(int competencyAssessmentId, int competencyId); } public class CompetencyAssessmentDataService : ICompetencyAssessmentDataService @@ -361,7 +371,7 @@ WHERE NOT EXISTS (SELECT 1 FROM SelfAssessmentFrameworks WHERE SelfAssessmentId new { adminId, selfAssessmentId, frameworkId } ); } - if (numberOfAffectedRows < 1) + if (numberOfAffectedRows < 1) { logger.LogWarning( "Not inserting SelfAssessmentFrameworks record as db insert failed. " + @@ -632,5 +642,117 @@ public bool UpdateRoleRequirementsTaskStatus(int assessmentId, bool taskStatus, } return true; } + + public IEnumerable GetCompetenciesForCompetencyAssessment(int competencyAssessmentId) + { + return connection.Query( + @"SELECT sas.ID AS StructureId, sas.CompetencyID, f.ID AS FrameworkId, f.FrameworkName, cg.ID AS GroupId, cg.Name AS GroupName, c.Name AS CompetencyName, c.Description AS CompetencyDescription, sas.Optional + FROM SelfAssessmentStructure AS sas INNER JOIN + Competencies AS c ON sas.CompetencyID = c.ID INNER JOIN + CompetencyGroups AS cg ON sas.CompetencyGroupID = cg.ID INNER JOIN + FrameworkCompetencies ON c.ID = FrameworkCompetencies.CompetencyID INNER JOIN + Frameworks AS f ON FrameworkCompetencies.FrameworkID = f.ID INNER JOIN + SelfAssessmentFrameworks ON f.ID = SelfAssessmentFrameworks.FrameworkId AND sas.SelfAssessmentID = SelfAssessmentFrameworks.SelfAssessmentId + WHERE (sas.SelfAssessmentID = @competencyAssessmentId) + ORDER BY sas.Ordering", new { competencyAssessmentId } + ); + } + + public IEnumerable GetLinkedFrameworksForCompetencyAssessment(int competencyAssessmentId) + { + return connection.Query( + @"SELECT f.ID, + FrameworkName, + f.OwnerAdminID, + f.BrandID, + f.CategoryID, + f.TopicID, + f.CreatedDate, + f.PublishStatusID, + f.UpdatedByAdminID + FROM SelfAssessmentFrameworks saf INNER JOIN + Frameworks AS f ON saf.FrameworkId = f.ID + WHERE (saf.SelfAssessmentId = @competencyAssessmentId) AND (saf.RemovedDate IS NULL) + ORDER BY f.FrameworkName", new { competencyAssessmentId } + ); + } + + public int[] GetLinkedFrameworkCompetencyIds(int competencyAssessmentId, int frameworkId) + { + return [.. connection.Query( + @"SELECT sas.CompetencyID + FROM SelfAssessmentStructure AS sas INNER JOIN + FrameworkCompetencies AS fc ON sas.CompetencyID = fc.CompetencyID + WHERE (sas.SelfAssessmentID = @competencyAssessmentId) AND (fc.FrameworkID = @frameworkId) + ORDER BY fc.Ordering", + new { competencyAssessmentId, frameworkId} + )]; + } + + public bool InsertCompetenciesIntoAssessmentFromFramework(int[] selectedCompetencyIds, int frameworkId, int competencyAssessmentId) + { + var currentMaxOrdering = connection.ExecuteScalar( + @"SELECT ISNULL(MAX(Ordering), 0) FROM SelfAssessmentStructure WHERE SelfAssessmentID = @competencyAssessmentId", + new { competencyAssessmentId } + ); + var numberOfAffectedRows = connection.Execute( + @"INSERT INTO SelfAssessmentStructure (SelfAssessmentID, CompetencyID, Ordering, CompetencyGroupID) + SELECT + @competencyAssessmentId, + FC.CompetencyID, + ROW_NUMBER() OVER (ORDER BY FCG.Ordering, FC.Ordering) + @currentMaxOrdering, + FCG.CompetencyGroupID + FROM FrameworkCompetencies AS FC + INNER JOIN FrameworkCompetencyGroups AS FCG ON FC.FrameworkCompetencyGroupID = FCG.ID + WHERE FC.FrameworkID = @frameworkId + AND FC.CompetencyID IN @selectedCompetencyIds AND FC.CompetencyID NOT IN (SELECT CompetencyID FROM SelfAssessmentStructure WHERE SelfAssessmentID = @competencyAssessmentId)", + new { selectedCompetencyIds, frameworkId, competencyAssessmentId, currentMaxOrdering } + ); + if (numberOfAffectedRows < 1) + { + logger.LogWarning( + "Not inserting competencies into assessment as db update failed. " + + $"assessmentId: {competencyAssessmentId}, frameworkId: {frameworkId}, selectedCompetencyIds: {selectedCompetencyIds}" + ); + return false; + } + return true; + } + public bool RemoveCompetencyFromAssessment(int competencyAssessmentId, int competencyId) + { + var numberOfAffectedRows = connection.Execute( + @"DELETE FROM SelfAssessmentStructure + WHERE SelfAssessmentID = @competencyAssessmentId AND CompetencyID = @competencyId", + new { competencyAssessmentId, competencyId } + ); + if (numberOfAffectedRows < 1) + { + logger.LogWarning( + "Not removing competency from assessment as db update failed. " + + $"assessmentId: {competencyAssessmentId}, competencyId: {competencyId}" + ); + return false; + } + return true; + } + + public void MoveCompetencyInSelfAssessment(int competencyAssessmentId, int competencyId, string direction) + { + connection.Execute( + "usp_MoveCompetencyInSelfAssessment", + new { SelfAssessmentID = competencyAssessmentId, CompetencyID = competencyId, Direction = direction }, + commandType: CommandType.StoredProcedure + ); + + } + + public void MoveCompetencyGroupInSelfAssessment(int competencyAssessmentId, int groupId, string direction) + { + connection.Execute( + "usp_MoveCompetencyGroupInSelfAssessment", + new { SelfAssessmentID = competencyAssessmentId, GroupID = groupId, Direction = direction }, + commandType: CommandType.StoredProcedure + ); + } } } diff --git a/DigitalLearningSolutions.Data/DataServices/FrameworkDataService.cs b/DigitalLearningSolutions.Data/DataServices/FrameworkDataService.cs index 3e2ee21beb..297fc983a3 100644 --- a/DigitalLearningSolutions.Data/DataServices/FrameworkDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/FrameworkDataService.cs @@ -51,9 +51,9 @@ public interface IFrameworkDataService CollaboratorNotification? GetCollaboratorNotification(int id, int invitedByAdminId); // Competencies/groups: - IEnumerable GetFrameworkCompetencyGroups(int frameworkId); + IEnumerable GetFrameworkCompetencyGroups(int frameworkId, int? assessmentId); - IEnumerable GetFrameworkCompetenciesUngrouped(int frameworkId); + IEnumerable GetFrameworkCompetenciesUngrouped(int frameworkId, int? assessmentId); CompetencyGroupBase? GetCompetencyGroupBaseById(int Id); @@ -861,18 +861,23 @@ public void RemoveCustomFlag(int flagId) ); } - public IEnumerable GetFrameworkCompetencyGroups(int frameworkId) + public IEnumerable GetFrameworkCompetencyGroups(int frameworkId, int? assessmentId) { + var assessmentFilter = assessmentId.HasValue ? + @$"AND c.ID NOT IN (SELECT CompetencyID + FROM SelfAssessmentStructure + WHERE (SelfAssessmentID = {assessmentId}))" + : string.Empty; var result = connection.Query( - @"SELECT fcg.ID, fcg.CompetencyGroupID, cg.Name, cg.Description, fcg.Ordering, fc.ID, c.ID AS CompetencyID, c.Name, c.Description, fc.Ordering, COUNT(caq.AssessmentQuestionID) AS AssessmentQuestions + @$"SELECT fcg.ID, fcg.CompetencyGroupID, cg.Name, fcg.Ordering, fc.ID, c.ID AS CompetencyID, c.Name, c.Description, fc.Ordering, + (SELECT COUNT(*) FROM CompetencyAssessmentQuestions caq WHERE caq.CompetencyID = c.ID) AS AssessmentQuestions ,(SELECT COUNT(*) FROM CompetencyLearningResources clr WHERE clr.CompetencyID = c.ID AND clr.RemovedDate IS NULL) AS CompetencyLearningResourcesCount FROM FrameworkCompetencyGroups AS fcg INNER JOIN CompetencyGroups AS cg ON fcg.CompetencyGroupID = cg.ID INNER JOIN FrameworkCompetencies AS fc ON fcg.ID = fc.FrameworkCompetencyGroupID LEFT OUTER JOIN - Competencies AS c ON fc.CompetencyID = c.ID LEFT OUTER JOIN - CompetencyAssessmentQuestions AS caq ON c.ID = caq.CompetencyID - WHERE (fcg.FrameworkID = @frameworkId) - GROUP BY fcg.ID, fcg.CompetencyGroupID, cg.Name, cg.Description, fcg.Ordering, fc.ID, c.ID, c.Name, c.Description, fc.Ordering + Competencies AS c ON fc.CompetencyID = c.ID + WHERE (fcg.FrameworkID = @frameworkId) {assessmentFilter} + GROUP BY fcg.ID, fcg.CompetencyGroupID, cg.Name, fcg.Ordering, fc.ID, c.ID, c.Name, c.Description, fc.Ordering ORDER BY fcg.Ordering, fc.Ordering", (frameworkCompetencyGroup, frameworkCompetency) => { @@ -882,29 +887,36 @@ FROM FrameworkCompetencyGroups AS fcg INNER JOIN }, new { frameworkId } ); - return result.GroupBy(frameworkCompetencyGroup => frameworkCompetencyGroup.CompetencyGroupID).Select( - group => - { - var groupedFrameworkCompetencyGroup = group.First(); - groupedFrameworkCompetencyGroup.FrameworkCompetencies = group.Where(frameworkCompetencyGroup => frameworkCompetencyGroup.FrameworkCompetencies.Count > 0) - .Select( - frameworkCompetencyGroup => frameworkCompetencyGroup.FrameworkCompetencies.Single() - ).ToList(); - return groupedFrameworkCompetencyGroup; - } - ); + return result + .GroupBy(fcg => fcg.CompetencyGroupID) + .Select(group => + { + var groupedFrameworkCompetencyGroup = group.First(); + + // Flatten all FrameworkCompetencies from all instances in this group + groupedFrameworkCompetencyGroup.FrameworkCompetencies = group + .SelectMany(g => g.FrameworkCompetencies) + .Where(fc => fc != null). + Distinct().ToList(); + + return groupedFrameworkCompetencyGroup; + }); } - public IEnumerable GetFrameworkCompetenciesUngrouped(int frameworkId) + public IEnumerable GetFrameworkCompetenciesUngrouped(int frameworkId, int? assessmentId) { + var assessmentFilter = assessmentId.HasValue ? + @$"AND c.ID NOT IN (SELECT CompetencyID + FROM SelfAssessmentStructure + WHERE (SelfAssessmentID = {assessmentId}))" + : string.Empty; return connection.Query( - @"SELECT fc.ID, c.ID AS CompetencyID, c.Name, c.Description, fc.Ordering, COUNT(caq.AssessmentQuestionID) AS AssessmentQuestions,(select COUNT(CompetencyId) from CompetencyLearningResources where CompetencyID=c.ID) AS CompetencyLearningResourcesCount + @$"SELECT fc.ID, c.ID AS CompetencyID, c.Name, c.Description, fc.Ordering, + (SELECT COUNT(*) FROM CompetencyAssessmentQuestions caq WHERE caq.CompetencyID = c.ID) AS AssessmentQuestions,(select COUNT(CompetencyId) from CompetencyLearningResources where CompetencyID=c.ID) AS CompetencyLearningResourcesCount FROM FrameworkCompetencies AS fc INNER JOIN Competencies AS c ON fc.CompetencyID = c.ID - LEFT OUTER JOIN - CompetencyAssessmentQuestions AS caq ON c.ID = caq.CompetencyID WHERE fc.FrameworkID = @frameworkId - AND fc.FrameworkCompetencyGroupID IS NULL + AND fc.FrameworkCompetencyGroupID IS NULL {assessmentFilter} GROUP BY fc.ID, c.ID, c.Name, c.Description, fc.Ordering ORDER BY fc.Ordering", new { frameworkId } diff --git a/DigitalLearningSolutions.Data/Models/CompetencyAssessments/Competency.cs b/DigitalLearningSolutions.Data/Models/CompetencyAssessments/Competency.cs new file mode 100644 index 0000000000..d28685ef92 --- /dev/null +++ b/DigitalLearningSolutions.Data/Models/CompetencyAssessments/Competency.cs @@ -0,0 +1,15 @@ +namespace DigitalLearningSolutions.Data.Models.CompetencyAssessments +{ + public class Competency + { + public int StructureId { get; set; } + public int CompetencyID { get; set; } + public int FrameworkId { get; set; } + public string? FrameworkName { get; set; } + public string? GroupName { get; set; } + public int GroupId { get; set; } + public string? CompetencyName { get; set; } + public string? CompetencyDescription { get; set; } + public bool Optional { get; set; } + } +} diff --git a/DigitalLearningSolutions.Data/Models/CompetencyAssessments/LinkedFrameworks.cs b/DigitalLearningSolutions.Data/Models/CompetencyAssessments/LinkedFrameworks.cs new file mode 100644 index 0000000000..c7fb0e4f2d --- /dev/null +++ b/DigitalLearningSolutions.Data/Models/CompetencyAssessments/LinkedFrameworks.cs @@ -0,0 +1,8 @@ +namespace DigitalLearningSolutions.Data.Models.CompetencyAssessments +{ + using DigitalLearningSolutions.Data.Models.Frameworks; + public class LinkedFramework : BaseFramework + { + public int AssessmentFrameworkCompetencyCount { get; set; } = 0; + } +} diff --git a/DigitalLearningSolutions.Data/Models/Frameworks/BaseFramework.cs b/DigitalLearningSolutions.Data/Models/Frameworks/BaseFramework.cs index 0291d3d13f..38adaf1cb8 100644 --- a/DigitalLearningSolutions.Data/Models/Frameworks/BaseFramework.cs +++ b/DigitalLearningSolutions.Data/Models/Frameworks/BaseFramework.cs @@ -22,7 +22,6 @@ public class BaseFramework : BaseSearchableItem public string? UpdatedBy { get; set; } public int UserRole { get; set; } public int? FrameworkReviewID { get; set; } - public override string SearchableName { get => SearchableNameOverrideForFuzzySharp ?? FrameworkName; diff --git a/DigitalLearningSolutions.Data/Models/Frameworks/FrameworkCompetency.cs b/DigitalLearningSolutions.Data/Models/Frameworks/FrameworkCompetency.cs index a42d3d10fe..cf2117457c 100644 --- a/DigitalLearningSolutions.Data/Models/Frameworks/FrameworkCompetency.cs +++ b/DigitalLearningSolutions.Data/Models/Frameworks/FrameworkCompetency.cs @@ -1,6 +1,7 @@ namespace DigitalLearningSolutions.Data.Models.Frameworks { using DigitalLearningSolutions.Data.Models.SearchSortFilterPaginate; + using System.Collections.Generic; using System.ComponentModel.DataAnnotations; public class FrameworkCompetency : BaseSearchableItem { @@ -15,6 +16,7 @@ public class FrameworkCompetency : BaseSearchableItem public int CompetencyLearningResourcesCount { get; set; } public string? FrameworkName { get; set; } public bool? AlwaysShowDescription { get; set; } + public IEnumerable CompetencyFlags { get; set; } = new List(); public override string SearchableName { diff --git a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs index 0d8d3ec490..b0fb7fa9de 100644 --- a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs +++ b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs @@ -1,23 +1,19 @@ namespace DigitalLearningSolutions.Web.Controllers.CompetencyAssessmentsController { + using DigitalLearningSolutions.Data.Enums; using DigitalLearningSolutions.Data.Models.CompetencyAssessments; + using DigitalLearningSolutions.Data.Models.Frameworks; + using DigitalLearningSolutions.Data.Models.SelfAssessments; + using DigitalLearningSolutions.Web.Attributes; + using DigitalLearningSolutions.Web.Helpers; + using DigitalLearningSolutions.Web.Models.Enums; using DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments; using Microsoft.AspNetCore.Mvc; + using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.Extensions.Logging; + using Serilog.Extensions.Hosting; using System.Collections.Generic; - using DigitalLearningSolutions.Data.Enums; - using DigitalLearningSolutions.Web.Attributes; - using DigitalLearningSolutions.Web.Models.Enums; - using DigitalLearningSolutions.Web.Helpers; using System.Linq; - using AspNetCoreGeneratedDocument; - using Microsoft.AspNetCore.Mvc.Rendering; - using DigitalLearningSolutions.Data.Models.Centres; - using DigitalLearningSolutions.Data.Models.Frameworks; - using Microsoft.CodeAnalysis.CSharp.Syntax; - using DigitalLearningSolutions.Data.Models.Courses; - using DigitalLearningSolutions.Web.Services; - using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Delegates.GroupCourses; public partial class CompetencyAssessmentsController { @@ -481,5 +477,168 @@ public IActionResult RemoveFramework(ConfirmRemoveFrameworkSourceViewModel model competencyAssessmentService.RemoveSelfAssessmentFramework(model.CompetencyAssessmentId, model.FrameworkId, adminId); return RedirectToAction("SelectFrameworkSources", new { model.CompetencyAssessmentId, actionName = "Summary" }); } + [Route("/CompetencyAssessments/{competencyAssessmentId}/Competencies")] + public IActionResult ViewSelectedCompetencies(int competencyAssessmentId) + { + + var competencies = competencyAssessmentService.GetCompetenciesForCompetencyAssessment(competencyAssessmentId); + var linkedFrameworks = competencyAssessmentService.GetLinkedFrameworksForCompetencyAssessment(competencyAssessmentId); + if (!competencies.Any()) + { + return RedirectToAction("AddCompetenciesSelectFramework", new { competencyAssessmentId }); + } + var adminId = GetAdminID(); + var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); + if (competencyAssessmentBase == null) + { + logger.LogWarning($"Failed to load Competencies page for competencyAssessmentId: {competencyAssessmentId} adminId: {adminId}"); + return StatusCode(500); + } + if (competencyAssessmentBase.UserRole < 2) + { + return StatusCode(403); + } + var competencyAssessmentTaskStatus = competencyAssessmentService.GetCompetencyAssessmentTaskStatus(competencyAssessmentId, null); + var model = new ViewSelectedCompetenciesViewModel(competencyAssessmentBase, competencies, linkedFrameworks, competencyAssessmentTaskStatus.SelectCompetenciesTaskStatus); + return View(model); + } + [Route("/CompetencyAssessments/{competencyAssessmentId}/Competencies/Add/SelectFramework")] + public IActionResult AddCompetenciesSelectFramework(int competencyAssessmentId) + { + var linkedFrameworks = competencyAssessmentService.GetLinkedFrameworksForCompetencyAssessment(competencyAssessmentId); + if (!linkedFrameworks.Any()) + { + return RedirectToAction("SelectFrameworkSources", new { competencyAssessmentId, actionName = "AddFramework" }); + } + var adminId = GetAdminID(); + var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); + if (competencyAssessmentBase == null) + { + logger.LogWarning($"Failed to load Competencies page for competencyAssessmentId: {competencyAssessmentId} adminId: {adminId}"); + return StatusCode(500); + } + if (competencyAssessmentBase.UserRole < 2) + { + return StatusCode(403); + } + + var model = new AddCompetenciesSelectFrameworkViewModel(competencyAssessmentBase, linkedFrameworks); + return View(model); + } + [HttpPost] + [Route("/CompetencyAssessments/{competencyAssessmentId}/Competencies/Add/SelectFramework")] + public IActionResult AddCompetenciesSelectFramework(AddCompetenciesSelectFrameworkFormData formdata) + { + if (!ModelState.IsValid) + { + var competencyAssessmentId = formdata.ID; + var linkedFrameworks = competencyAssessmentService.GetLinkedFrameworksForCompetencyAssessment(competencyAssessmentId); + var adminId = GetAdminID(); + var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); + var model = new AddCompetenciesSelectFrameworkViewModel(competencyAssessmentBase, linkedFrameworks); + model.FrameworkId = formdata.FrameworkId; + return View("AddCompetenciesSelectFramework", model); + } + else + { + return RedirectToAction("AddCompetencies", new { competencyAssessmentId = formdata.ID, frameworkId = formdata.FrameworkId }); + } + } + [Route("/CompetencyAssessments/{competencyAssessmentId}/Competencies/Add/{frameworkId}")] + public IActionResult AddCompetencies(int competencyAssessmentId, int frameworkId) + { + var adminId = GetAdminID(); + var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); + if (competencyAssessmentBase == null) + { + logger.LogWarning($"Failed to load Competencies page for competencyAssessmentId: {competencyAssessmentId} adminId: {adminId}"); + return StatusCode(500); + } + if (competencyAssessmentBase.UserRole < 2) + { + return StatusCode(403); + } + var framework = frameworkService.GetBaseFrameworkByFrameworkId(frameworkId, adminId); + var selectedFrameworkCompetencies = competencyAssessmentService.GetLinkedFrameworkCompetencyIds(competencyAssessmentId, frameworkId); + var groupedCompetencies = frameworkService.GetFrameworkCompetencyGroups(frameworkId, competencyAssessmentId); + var ungroupedCompetencies = frameworkService.GetFrameworkCompetenciesUngrouped(frameworkId, competencyAssessmentId); + var competencyIds = ungroupedCompetencies.Select(c => c.CompetencyID).ToArray(); + var competencyFlags = frameworkService.GetSelectedCompetencyFlagsByCompetecyIds(competencyIds); + foreach (var competency in ungroupedCompetencies) + competency.CompetencyFlags = competencyFlags.Where(f => f.CompetencyId == competency.CompetencyID); + foreach (var group in groupedCompetencies) + { + competencyIds = group.FrameworkCompetencies.Select(c => c.CompetencyID).ToArray(); + competencyFlags = frameworkService.GetSelectedCompetencyFlagsByCompetecyIds(competencyIds); + foreach (var competency in group.FrameworkCompetencies) + competency.CompetencyFlags = competencyFlags.Where(f => f.CompetencyId == competency.CompetencyID); + } + var model = new AddCompetenciesViewModel(competencyAssessmentBase, groupedCompetencies, ungroupedCompetencies, frameworkId, framework.FrameworkName, selectedFrameworkCompetencies); + return View(model); + } + [HttpPost] + [Route("/CompetencyAssessments/{competencyAssessmentId}/Competencies/Add/{frameworkId}")] + public IActionResult AddComptencies(AddCompetenciesFormData model, int competencyAssessmentId, int frameworkId) + { + if (!ModelState.IsValid) + { + //reload model and view + } + if (model.SelectedCompetencyIds != null) + { + competencyAssessmentService.InsertCompetenciesIntoAssessmentFromFramework(model.SelectedCompetencyIds, frameworkId, competencyAssessmentId); + } + competencyAssessmentService.UpdateSelectCompetenciesTaskStatus(competencyAssessmentId, false, null); + return RedirectToAction("ViewSelectedCompetencies", new { competencyAssessmentId }); + } + [Route("/CompetencyAssessments/{competencyAssessmentId}/Competencies/Delete/{competencyId}")] + public IActionResult DeleteCompetency(int competencyAssessmentId, int competencyId) + { + competencyAssessmentService.RemoveCompetencyFromAssessment(competencyAssessmentId, competencyId); + return RedirectToAction("ViewSelectedCompetencies", new { competencyAssessmentId }); + } + public IActionResult MoveCompetencyInSelfAssessment(int competencyAssessmentId, int competencyId, string direction) + { + var adminId = GetAdminID(); + var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); + if (competencyAssessmentBase == null) + { + logger.LogWarning($"Failed to load Competencies page for competencyAssessmentId: {competencyAssessmentId} adminId: {adminId}"); + return StatusCode(500); + } + if (competencyAssessmentBase.UserRole < 2) + { + return StatusCode(403); + } + competencyAssessmentService.MoveCompetencyInSelfAssessment(competencyAssessmentId, competencyId, direction); + return new RedirectResult(Url.Action("ViewSelectedCompetencies", new { competencyAssessmentId }) + "#competency-" + competencyId.ToString()); + } + public IActionResult MoveCompetencyGroupInSelfAssessment(int competencyAssessmentId, int groupId, string direction) + { + var adminId = GetAdminID(); + var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); + if (competencyAssessmentBase == null) + { + logger.LogWarning($"Failed to load Competencies page for competencyAssessmentId: {competencyAssessmentId} adminId: {adminId}"); + return StatusCode(500); + } + if (competencyAssessmentBase.UserRole < 2) + { + return StatusCode(403); + } + competencyAssessmentService.MoveCompetencyGroupInSelfAssessment(competencyAssessmentId, groupId, direction); + return new RedirectResult(Url.Action("ViewSelectedCompetencies", new { competencyAssessmentId }) + "#group-" + groupId.ToString()); + } + [HttpPost] + [Route("/CompetencyAssessments/{competencyAssessmentId}/Competencies")] + public IActionResult ViewSelectedCompetencies(ViewSelectedCompetenciesFormData model) + { + if (model.TaskStatus == null) + { + model.TaskStatus = false; + } + competencyAssessmentService.UpdateSelectCompetenciesTaskStatus(model.ID, model.TaskStatus.Value, null); + return RedirectToAction("ManageCompetencyAssessment", new { competencyAssessmentId = model.ID }); + } } } diff --git a/DigitalLearningSolutions.Web/Controllers/FrameworksController/Frameworks.cs b/DigitalLearningSolutions.Web/Controllers/FrameworksController/Frameworks.cs index fc9e8eb335..3d3a85d9cf 100644 --- a/DigitalLearningSolutions.Web/Controllers/FrameworksController/Frameworks.cs +++ b/DigitalLearningSolutions.Web/Controllers/FrameworksController/Frameworks.cs @@ -723,9 +723,9 @@ public IActionResult ViewFramework(string tabname, int frameworkId, int? framewo model.TabNavLinks = new TabsNavViewModel(FrameworkTab.Details, routeData); break; case "Structure": - model.FrameworkCompetencyGroups = frameworkService.GetFrameworkCompetencyGroups(frameworkId).ToList(); + model.FrameworkCompetencyGroups = frameworkService.GetFrameworkCompetencyGroups(frameworkId, null).ToList(); model.CompetencyFlags = frameworkService.GetCompetencyFlagsByFrameworkId(frameworkId, null, selected: true); - model.FrameworkCompetencies = frameworkService.GetFrameworkCompetenciesUngrouped(frameworkId); + model.FrameworkCompetencies = frameworkService.GetFrameworkCompetenciesUngrouped(frameworkId, null); model.TabNavLinks = new TabsNavViewModel(FrameworkTab.Structure, routeData); break; case "Comments": @@ -746,9 +746,9 @@ public IActionResult PrintLayout(int frameworkId) { DetailFramework = detailFramework, }; - model.FrameworkCompetencyGroups = frameworkService.GetFrameworkCompetencyGroups(frameworkId).ToList(); + model.FrameworkCompetencyGroups = frameworkService.GetFrameworkCompetencyGroups(frameworkId, null).ToList(); model.CompetencyFlags = frameworkService.GetCompetencyFlagsByFrameworkId(frameworkId, null, selected: true); - model.FrameworkCompetencies = frameworkService.GetFrameworkCompetenciesUngrouped(frameworkId); + model.FrameworkCompetencies = frameworkService.GetFrameworkCompetenciesUngrouped(frameworkId, null); return View("Developer/FrameworkPrintLayout", model); } [ResponseCache(CacheProfileName = "Never")] diff --git a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs index e2d6cd8870..0026a2e1f3 100644 --- a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs +++ b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs @@ -815,7 +815,7 @@ public IActionResult RetiringSelfAssessmentConfirmed(RetiringSelfAssessmentViewM { if (ModelState.IsValid && retiringSelfAssessment.ActionConfirmed) { - var sessionEnrolOnRoleProfile = multiPageFormService.GetMultiPageFormData( + var sessionEnrolOnRoleProfile = multiPageFormService.GetMultiPageFormData( MultiPageFormDataFeature.EnrolDelegateOnProfileAssessment, TempData ).GetAwaiter().GetResult(); diff --git a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs index 80bb557030..6d13912a3b 100644 --- a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs @@ -1,9 +1,6 @@ using DigitalLearningSolutions.Data.DataServices; -using DigitalLearningSolutions.Data.Models.Common; using DigitalLearningSolutions.Data.Models.CompetencyAssessments; -using DocumentFormat.OpenXml.EMMA; using System.Collections.Generic; -using System.Threading.Tasks; namespace DigitalLearningSolutions.Web.Services { @@ -27,8 +24,13 @@ public interface ICompetencyAssessmentService int[] GetLinkedFrameworkIds(int assessmentId); int? GetPrimaryLinkedFrameworkId(int assessmentId); + IEnumerable GetCompetenciesForCompetencyAssessment(int competencyAssessmentId); + IEnumerable GetLinkedFrameworksForCompetencyAssessment(int competencyAssessmentId); + bool RemoveSelfAssessmentFramework(int assessmentId, int frameworkId, int adminId); + int[] GetLinkedFrameworkCompetencyIds(int competencyAssessmentId, int frameworkId); + //UPDATE DATA bool UpdateCompetencyAssessmentName(int competencyAssessmentId, int adminId, string competencyAssessmentName); bool UpdateCompetencyRoleProfileLinks(int competencyAssessmentId, int adminId, int? professionalGroupId, int? subGroupId, int? roleId); @@ -43,16 +45,25 @@ public interface ICompetencyAssessmentService bool UpdateSelectCompetenciesTaskStatus(int competencyAssessmentId, bool taskStatus, bool? previousStatus); bool UpdateOptionalCompetenciesTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); bool UpdateRoleRequirementsTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); + void MoveCompetencyInSelfAssessment(int competencyAssessmentId, + int competencyId, + string direction + ); + void MoveCompetencyGroupInSelfAssessment(int competencyAssessmentId, + int groupId, + string direction + ); //INSERT DATA int InsertCompetencyAssessment(int adminId, int centreId, string competencyAssessmentName, int? frameworkId); bool InsertSelfAssessmentFramework(int adminId, int assessmentId, int frameworkId); int GetCompetencyCountByFrameworkId(int competencyAssessmentId, int frameworkId); + bool InsertCompetenciesIntoAssessmentFromFramework(int[] selectedCompetencyIds, int frameworkId, int competencyAssessmentId); //DELETE DATA bool RemoveFrameworkCompetenciesFromAssessment(int competencyAssessmentId, int frameworkId); - - } + bool RemoveCompetencyFromAssessment(int competencyAssessmentId, int competencyId); + } public class CompetencyAssessmentService : ICompetencyAssessmentService { private readonly ICompetencyAssessmentDataService competencyAssessmentDataService; @@ -218,5 +229,40 @@ public bool UpdateRoleRequirementsTaskStatus(int assessmentId, bool taskStatus, { return competencyAssessmentDataService.UpdateRoleRequirementsTaskStatus(assessmentId, taskStatus, previousStatus); } + + public IEnumerable GetCompetenciesForCompetencyAssessment(int competencyAssessmentId) + { + return competencyAssessmentDataService.GetCompetenciesForCompetencyAssessment(competencyAssessmentId); + } + + public IEnumerable GetLinkedFrameworksForCompetencyAssessment(int competencyAssessmentId) + { + return competencyAssessmentDataService.GetLinkedFrameworksForCompetencyAssessment(competencyAssessmentId); + } + + public int[] GetLinkedFrameworkCompetencyIds(int competencyAssessmentId, int frameworkId) + { + return competencyAssessmentDataService.GetLinkedFrameworkCompetencyIds(competencyAssessmentId, frameworkId); + } + + public bool InsertCompetenciesIntoAssessmentFromFramework(int[] selectedCompetencyIds, int frameworkId, int competencyAssessmentId) + { + return competencyAssessmentDataService.InsertCompetenciesIntoAssessmentFromFramework(selectedCompetencyIds, frameworkId, competencyAssessmentId); + } + + public bool RemoveCompetencyFromAssessment(int competencyAssessmentId, int competencyId) + { + return competencyAssessmentDataService.RemoveCompetencyFromAssessment(competencyAssessmentId, competencyId); + } + + public void MoveCompetencyInSelfAssessment(int competencyAssessmentId, int competencyId, string direction) + { + competencyAssessmentDataService.MoveCompetencyInSelfAssessment(competencyAssessmentId, competencyId, direction); + } + + public void MoveCompetencyGroupInSelfAssessment(int competencyAssessmentId, int groupId, string direction) + { + competencyAssessmentDataService.MoveCompetencyGroupInSelfAssessment(competencyAssessmentId, groupId, direction); + } } } diff --git a/DigitalLearningSolutions.Web/Services/FrameworkService.cs b/DigitalLearningSolutions.Web/Services/FrameworkService.cs index 4d7b3e13bf..a4bd97de16 100644 --- a/DigitalLearningSolutions.Web/Services/FrameworkService.cs +++ b/DigitalLearningSolutions.Web/Services/FrameworkService.cs @@ -46,9 +46,9 @@ public interface IFrameworkService CollaboratorNotification? GetCollaboratorNotification(int id, int invitedByAdminId); // Competencies/groups: - IEnumerable GetFrameworkCompetencyGroups(int frameworkId); + IEnumerable GetFrameworkCompetencyGroups(int frameworkId, int? assessmentId); - IEnumerable GetFrameworkCompetenciesUngrouped(int frameworkId); + IEnumerable GetFrameworkCompetenciesUngrouped(int frameworkId, int? assessmentId); CompetencyGroupBase? GetCompetencyGroupBaseById(int Id); @@ -481,9 +481,9 @@ public IEnumerable GetFrameworkByFrameworkName(string framewor return frameworkDataService.GetFrameworkByFrameworkName(frameworkName, adminId); } - public IEnumerable GetFrameworkCompetenciesUngrouped(int frameworkId) + public IEnumerable GetFrameworkCompetenciesUngrouped(int frameworkId, int? assessmentId) { - return frameworkDataService.GetFrameworkCompetenciesUngrouped(frameworkId); + return frameworkDataService.GetFrameworkCompetenciesUngrouped(frameworkId, assessmentId); } public FrameworkCompetency? GetFrameworkCompetencyById(int Id) @@ -496,9 +496,9 @@ public IEnumerable GetFrameworkCompetenciesUngrouped(int fr return frameworkDataService.GetFrameworkCompetencyForPreview(frameworkCompetencyId); } - public IEnumerable GetFrameworkCompetencyGroups(int frameworkId) + public IEnumerable GetFrameworkCompetencyGroups(int frameworkId, int? assessmentId) { - return frameworkDataService.GetFrameworkCompetencyGroups(frameworkId); + return frameworkDataService.GetFrameworkCompetencyGroups(frameworkId, assessmentId); } public string? GetFrameworkConfigForFrameworkId(int frameworkId) diff --git a/DigitalLearningSolutions.Web/Services/ImportCompetenciesFromFileService.cs b/DigitalLearningSolutions.Web/Services/ImportCompetenciesFromFileService.cs index 6d773ffd02..241aea962f 100644 --- a/DigitalLearningSolutions.Web/Services/ImportCompetenciesFromFileService.cs +++ b/DigitalLearningSolutions.Web/Services/ImportCompetenciesFromFileService.cs @@ -37,7 +37,7 @@ public ImportCompetenciesResult PreProcessCompetenciesTable(IXLWorkbook workbook var newCompetencyIds = competencyRows.Select(row => row.ID ?? 0).ToList(); var existingIds = frameworkService.GetFrameworkCompetencyOrder(frameworkId, newCompetencyIds); var existingGroups = frameworkService - .GetFrameworkCompetencyGroups(frameworkId) + .GetFrameworkCompetencyGroups(frameworkId, null) .Select(row => row.Name) .Distinct() .ToList(); @@ -150,7 +150,7 @@ internal ImportCompetenciesResult ProcessCompetenciesTable(IXLTable table, int a .ToList(); for (int i = 0; i < competencyGroupCount; i++) { - var existingGroups = frameworkService.GetFrameworkCompetencyGroups(frameworkId).Select(row => new { row.ID, row.Name }) + var existingGroups = frameworkService.GetFrameworkCompetencyGroups(frameworkId, null).Select(row => new { row.ID, row.Name }) .Distinct() .ToList(); var placesToMove = Math.Abs(existingGroups.FindIndex(group => group.Name == distinctCompetencyGroups[i]) - i); diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesSelectFrameworkFormData.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesSelectFrameworkFormData.cs new file mode 100644 index 0000000000..1dc5b60ed9 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesSelectFrameworkFormData.cs @@ -0,0 +1,10 @@ +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +{ + using System.ComponentModel.DataAnnotations; + public class AddCompetenciesSelectFrameworkFormData + { + public int ID { get; set; } + [Required(ErrorMessage = "Select a linked framework")] + public int? FrameworkId { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesSelectFrameworkViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesSelectFrameworkViewModel.cs new file mode 100644 index 0000000000..98a09de671 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesSelectFrameworkViewModel.cs @@ -0,0 +1,28 @@ +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +{ + using DigitalLearningSolutions.Data.Models.CompetencyAssessments; + using DigitalLearningSolutions.Data.Models.Frameworks; + using DigitalLearningSolutions.Web.Helpers; + using System.Collections.Generic; + + public class AddCompetenciesSelectFrameworkViewModel : AddCompetenciesSelectFrameworkFormData + { + public AddCompetenciesSelectFrameworkViewModel( + CompetencyAssessmentBase competencyAssessmentBase, + IEnumerable linkedFrameworks + ) + { + ID = competencyAssessmentBase.ID; + CompetencyAssessmentName = competencyAssessmentBase.CompetencyAssessmentName; + LinkedFrameworks = linkedFrameworks; + UserRole = competencyAssessmentBase.UserRole; + VocabularySingular = FrameworkVocabularyHelper.VocabularySingular(competencyAssessmentBase.Vocabulary); + VocabularyPlural = FrameworkVocabularyHelper.VocabularyPlural(competencyAssessmentBase.Vocabulary); + } + public string? CompetencyAssessmentName { get; set; } + public int UserRole { get; set; } + public string VocabularySingular { get; set; } + public string VocabularyPlural { get; set; } + public IEnumerable LinkedFrameworks { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewFormData.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewFormData.cs new file mode 100644 index 0000000000..0e6d2ed887 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewFormData.cs @@ -0,0 +1,9 @@ +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +{ + public class AddCompetenciesFormData + { + public int ID { get; set; } + public int[] SelectedCompetencyIds { get; set; } + public int FrameworkId { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewModel.cs new file mode 100644 index 0000000000..38b9e87765 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewModel.cs @@ -0,0 +1,33 @@ +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +{ + using DigitalLearningSolutions.Data.Models.CompetencyAssessments; + using DigitalLearningSolutions.Data.Models.Frameworks; + using DigitalLearningSolutions.Web.Helpers; + using System.Collections.Generic; + public class AddCompetenciesViewModel + { + public AddCompetenciesViewModel(CompetencyAssessmentBase competencyAssessmentBase, IEnumerable groupedCompetencies, IEnumerable ungroupedCompetencies, int frameworkId, string? frameworkName, int[] selectedFrameworkCompetencies) + { + ID = competencyAssessmentBase.ID; + CompetencyAssessmentName = competencyAssessmentBase.CompetencyAssessmentName; + UserRole = competencyAssessmentBase.UserRole; + VocabularySingular = FrameworkVocabularyHelper.VocabularySingular(competencyAssessmentBase.Vocabulary); + VocabularyPlural = FrameworkVocabularyHelper.VocabularyPlural(competencyAssessmentBase.Vocabulary); + GroupedCompetencies = groupedCompetencies; + UngroupedCompetencies = ungroupedCompetencies; + FrameworkId = frameworkId; + FrameworkName = frameworkName; + SelectedCompetencyIds = selectedFrameworkCompetencies; + } + public int ID { get; set; } + public string CompetencyAssessmentName { get; set; } + public int UserRole { get; set; } + public string VocabularySingular { get; set; } + public string VocabularyPlural { get; set; } + public IEnumerable GroupedCompetencies { get; set; } + public IEnumerable UngroupedCompetencies { get; set; } + public int[] SelectedCompetencyIds { get; set; } + public int FrameworkId { get; set; } + public string? FrameworkName { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ManageCompetencyAssessmentViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ManageCompetencyAssessmentViewModel.cs index a4a3f41115..05c0a7a846 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ManageCompetencyAssessmentViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ManageCompetencyAssessmentViewModel.cs @@ -1,4 +1,5 @@ using DigitalLearningSolutions.Data.Models.CompetencyAssessments; +using DigitalLearningSolutions.Web.Helpers; namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments { @@ -13,12 +14,14 @@ CompetencyAssessmentTaskStatus competencyAssessmentTaskStatus PublishStatusID = competencyAssessmentBase.PublishStatusID; UserRole = competencyAssessmentBase.UserRole; CompetencyAssessmentTaskStatus = competencyAssessmentTaskStatus; - Vocabulary = competencyAssessmentBase.Vocabulary; + VocabularySingular = FrameworkVocabularyHelper.VocabularySingular(competencyAssessmentBase.Vocabulary); + VocabularyPlural = FrameworkVocabularyHelper.VocabularyPlural(competencyAssessmentBase.Vocabulary); } public string CompetencyAssessmentName { get; set; } public int PublishStatusID { get; set; } public int UserRole { get; set; } - public string? Vocabulary { get; set; } + public string VocabularySingular { get; set; } + public string VocabularyPlural { get; set; } public CompetencyAssessmentTaskStatus CompetencyAssessmentTaskStatus { get; set; } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs index 846a0fb2dd..6f7de8cfdd 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations; public class SelectFrameworkSourcesFormData { - [Required] + [Required(ErrorMessage = "Select a framework")] public int FrameworkId { get; set; } public int CompetencyAssessmentId { get; set; } public bool? TaskStatus { get; set; } diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ViewSelectedCompetenciesFormData.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ViewSelectedCompetenciesFormData.cs new file mode 100644 index 0000000000..467a9845e1 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ViewSelectedCompetenciesFormData.cs @@ -0,0 +1,8 @@ +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +{ + public class ViewSelectedCompetenciesFormData + { + public int ID { get; set; } + public bool? TaskStatus { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ViewSelectedCompetenciesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ViewSelectedCompetenciesViewModel.cs new file mode 100644 index 0000000000..dc03de2eba --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ViewSelectedCompetenciesViewModel.cs @@ -0,0 +1,46 @@ +using DigitalLearningSolutions.Data.Models.CompetencyAssessments; +using DigitalLearningSolutions.Web.Helpers; +using System.Collections.Generic; +using System.Linq; + +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +{ + + public class ViewSelectedCompetenciesViewModel : ViewSelectedCompetenciesFormData + { + public ViewSelectedCompetenciesViewModel() { } + public ViewSelectedCompetenciesViewModel(CompetencyAssessmentBase competencyAssessmentBase, IEnumerable competencies, IEnumerable linkedFrameworks, bool? taskStatus) + { + ID = competencyAssessmentBase.ID; + TaskStatus = taskStatus; + CompetencyAssessmentName = competencyAssessmentBase.CompetencyAssessmentName; + UserRole = competencyAssessmentBase.UserRole; + Competencies = competencies; + VocabularySingular = FrameworkVocabularyHelper.VocabularySingular(competencyAssessmentBase.Vocabulary); + VocabularyPlural = FrameworkVocabularyHelper.VocabularyPlural(competencyAssessmentBase.Vocabulary); + var competencyCounts = competencies + .GroupBy(c => c.FrameworkId) + .ToDictionary(g => g.Key, g => g.Count()); + // Populate LinkedFrameworks with the relevant count + foreach (var framework in linkedFrameworks) + { + if (competencyCounts.TryGetValue(framework.ID, out var count)) + { + framework.AssessmentFrameworkCompetencyCount = count; + } + else + { + framework.AssessmentFrameworkCompetencyCount = 0; + } + } + LinkedFrameworks = linkedFrameworks; + } + + public string CompetencyAssessmentName { get; set; } + public int UserRole { get; set; } + public string VocabularySingular { get; set; } + public string VocabularyPlural { get; set; } + public IEnumerable Competencies { get; set; } + public IEnumerable LinkedFrameworks { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetencies.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetencies.cshtml new file mode 100644 index 0000000000..8616052934 --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetencies.cshtml @@ -0,0 +1,119 @@ +@using DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +@model AddCompetenciesViewModel; +@{ + ViewData["Title"] = "Add Competencies to Self Assessment"; + ViewData["Application"] = "Framework Service"; +} + +@section NavMenuItems { + +} + +@section NavBreadcrumbs { + + + + Competency Assessments + Manage Competency Assessment + Select framework sources + + Back to manage competency assessment + + +} + + + + + + + Add @Model.VocabularyPlural.ToLower() to assessment from @Model.FrameworkName + + + + @if (Model.GroupedCompetencies.Count() > 0) + { + @foreach (var competencyGroup in Model.GroupedCompetencies) + { + @if (competencyGroup.FrameworkCompetencies.Count() > 1) + { + + + @competencyGroup.Name + + @if (competencyGroup.FrameworkCompetencies.Count() > 1) + { + + + Select all @Model.VocabularyPlural.ToLower() in group @competencyGroup.Name + Deselect all @Model.VocabularyPlural.ToLower() in group @competencyGroup.Name + + + } + + @foreach (var competency in competencyGroup.FrameworkCompetencies) + { + + + + @foreach (var flag in competency.CompetencyFlags) + { + + + @flag.FlagName + + + } + @competency.Name + + + } + + + } + } + } + + @if (Model.UngroupedCompetencies.Any()) + { + + Ungrouped @Model.VocabularyPlural.ToLower() + + @if (Model.UngroupedCompetencies.Count() > 1) + { + + + Select all ungrouped @Model.VocabularyPlural.ToLower() + Deselect all ungrouped @Model.VocabularyPlural.ToLower() + + + } + @foreach (var competency in Model.UngroupedCompetencies) + { + + + + + @foreach (var flag in competency.CompetencyFlags) + { + + + @flag.FlagName + + + } + + @competency.Name + + + + } + } + + + + Add selected @Model.VocabularyPlural.ToLower() to assessment + +@section scripts { + +} diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetenciesSelectFramework.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetenciesSelectFramework.cshtml new file mode 100644 index 0000000000..1bb44950b3 --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetenciesSelectFramework.cshtml @@ -0,0 +1,54 @@ +@using DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +@model AddCompetenciesSelectFrameworkViewModel; +@{ + ViewData["Title"] = "Select Framework Source"; + ViewData["Application"] = "Framework Service"; +} + +@section NavMenuItems { + +} + +@section NavBreadcrumbs { + + + + Competency Assessments + Manage Competency Assessment + Select @Model.VocabularyPlural.ToLower() to assess + + Back to manage competency assessment + + +} +Select Framework Source + + @if (!ViewData.ModelState.IsValid) + { + + } + + + + + + Select the framework source you would like to use to add @Model.VocabularyPlural.ToLower() to this competency assessment. + + + + @foreach (var framework in Model.LinkedFrameworks) + { + + + + @framework.FrameworkName + + + } + + + + + + Next + diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml index 70b5bbdc71..f13c584c33 100644 --- a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml @@ -88,7 +88,7 @@ - Select assessment vocabulary (@Model.Vocabulary) + Select assessment vocabulary (@Model.VocabularySingular) @@ -120,7 +120,7 @@ @if (Model.CompetencyAssessmentTaskStatus.FrameworkLinksTaskStatus == null) { - Select competencies to assess + Select @Model.VocabularyPlural.ToLower() to assess Cannot start yet @@ -129,8 +129,8 @@ else { - - Select competencies to assess + + Select @Model.VocabularyPlural.ToLower() to assess @@ -143,7 +143,7 @@ @if (Model.CompetencyAssessmentTaskStatus.SelectCompetenciesTaskStatus == null) { - Identify optional competencies + Identify optional @Model.VocabularyPlural.ToLower() Cannot start yet @@ -153,7 +153,7 @@ { - Identify optional competencies + Identify optional @Model.VocabularyPlural.ToLower() @@ -167,7 +167,7 @@ @if (Model.CompetencyAssessmentTaskStatus.SelectCompetenciesTaskStatus == null) { - Set competency attainment requirements + Set @Model.VocabularySingular.ToLower() attainment requirements Cannot start yet @@ -177,7 +177,7 @@ { - Set competency attainment requirements + Set @Model.VocabularySingular.ToLower() attainment requirements diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml index 35496950f2..e3a4efe516 100644 --- a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml @@ -4,7 +4,6 @@ ViewData["Title"] = "Select Framework Sources"; ViewData["Application"] = "Framework Service"; } - @section NavMenuItems { @@ -16,7 +15,7 @@ Competency Assessments Manage Competency Assessment - Introductory text + Select framework sources Back to manage competency assessment @@ -47,7 +46,7 @@ { - Additional framework @i + Additional framework @(i+1) @Model.AdditionalFrameworks.ElementAt(i).FrameworkName diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ViewSelectedCompetencies.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ViewSelectedCompetencies.cshtml new file mode 100644 index 0000000000..b6cd21e538 --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ViewSelectedCompetencies.cshtml @@ -0,0 +1,151 @@ +@using DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +@model ViewSelectedCompetenciesViewModel; +@{ + ViewData["Title"] = "Select Competencies"; + ViewData["Application"] = "Framework Service"; + var groupCount = Model.Competencies + .GroupBy(c => new { c.FrameworkId, c.FrameworkName, c.GroupId, c.GroupName }) + .Count(); +} + +@section NavMenuItems { + +} + +@section NavBreadcrumbs { + + + + Competency Assessments + Manage Competency Assessment + Select @Model.VocabularyPlural.ToLower() to assess + + Back to manage competency assessment + + +} +@Model.VocabularyPlural to assess for @Model.CompetencyAssessmentName +Linked frameworks + + @{ + var i = 0; + } + @foreach (var framework in Model.LinkedFrameworks) + { + + + @(i == 0 ? "Primary framework" : $"Additional framework {i}") + + + @framework.FrameworkName (@framework.AssessmentFrameworkCompetencyCount @Model.VocabularyPlural.ToLower()) + + + + Manage @Model.VocabularyPlural.ToLower() + + + + i++; + } + +@Model.VocabularyPlural +@{ + int groupNum = 1; +} +@foreach (var group in Model.Competencies + .GroupBy(c => new { c.FrameworkId, c.FrameworkName, c.GroupId, c.GroupName })) +{ + + + + + @group.Key.GroupName (@group.Key.FrameworkName) + + @if (Model.UserRole > 1) + { + + + @if (groupNum > 1) + { + Move @group.Key.GroupNameup + } + @if (groupNum < groupCount) + { + Move @group.Key.GroupNamedown + } + Remove @group.Key.GroupName + + + } + + + @if (group.Any()) + { + int competencyNum = 1; + foreach (var competency in group) + { + + + @* *@ + @if (competency.CompetencyDescription != null) + { + + @competency.CompetencyName + + + @(Html.Raw(competency.CompetencyDescription)) + + } + else + { + + @competency.CompetencyName + + } + + + + @if (Model.UserRole > 1) + { + if (competencyNum > 1) + { + Move @competency.CompetencyNameup + } + if (competencyNum < group.Count()) + { + Move @competency.CompetencyNamedown + } + Remove @competency.CompetencyName + } + + + + + competencyNum++; + } + } + else + { + No @ViewData["VocabPlural"].ToString().ToLower() in this group. + } + + + groupNum++; +} + + + + + + + Submit + + + + + + + Cancel + + + diff --git a/DigitalLearningSolutions.Web/Views/Frameworks/Index.cshtml b/DigitalLearningSolutions.Web/Views/Frameworks/Index.cshtml index 300eccb81e..7f50a983a3 100644 --- a/DigitalLearningSolutions.Web/Views/Frameworks/Index.cshtml +++ b/DigitalLearningSolutions.Web/Views/Frameworks/Index.cshtml @@ -78,7 +78,7 @@ else - @Model.DashboardData.CompetencyAssessmentCount Competency Assessments + @Model.DashboardData.CompetencyAssessmentCount Assessments @if (Model.IsWorkforceManager | Model.IsWorkforceContributor)
Back to manage competency assessment
+ @competency.CompetencyName +
+ @(Html.Raw(competency.CompetencyDescription)) +
No @ViewData["VocabPlural"].ToString().ToLower() in this group.
- @Model.DashboardData.CompetencyAssessmentCount Competency Assessments + @Model.DashboardData.CompetencyAssessmentCount Assessments