Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Competence Document KPI table #201

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Epsilon.Host.WebApi/Controllers/DocumentController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ public async Task<ActionResult<PageComponent>> UpdateOrCreatePage(int courseId,
[HttpGet("download/word")]
public async Task<IActionResult> DownloadWord(string userId, DateTime from, DateTime to)
{
var document = await _competenceDocumentService.GetDocument(userId, from, to);
var document = _competenceDocumentService.GetDocument(userId, from, to);

using var stream = new MemoryStream();
await _competenceDocumentService.WriteDocument(stream, document);
await _competenceDocumentService.WriteDocument(stream, await document);

return File(
stream.ToArray(),
Expand Down
137 changes: 137 additions & 0 deletions Epsilon/Components/KpiTableComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Epsilon.Abstractions;
using Epsilon.Abstractions.Components;
using System.Globalization;

namespace Epsilon.Components;

public class KpiTableComponent : AbstractCompetenceComponent
{
public override async Task<Body?> AddToWordDocument(MainDocumentPart mainDocumentPart)
{
var body = mainDocumentPart.Document.Body;

// Create a table to display outcomes, assignments, and grades
var table = new Table();

// Define table properties
var tblProp = new TableProperties(
new TableWidth(),
new TableBorders(
new BottomBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 3, },
new RightBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 3, },
new InsideHorizontalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 3, },
new InsideVerticalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 3, }
)
);
table.AppendChild<TableProperties>(tblProp);

// Define table grid
var tblGrid = new TableGrid();
table.AppendChild(tblGrid);

// Define column header texts
var columnsHeaders = new Dictionary<string, string> { { "KPI", "3000" }, { "Assignments", "5000" }, { "Grades", "1000" }, };

// Create the table header row
var headerRow = new TableRow();

// Create the header cells
foreach (var columnHeader in columnsHeaders)
{
headerRow.AppendChild(CreateTableCell(columnHeader.Value, new Paragraph(new Run(new Text(columnHeader.Key)))));
}

// Add the header row to the table
table.AppendChild(headerRow);

// Get allOutcomes
var allOutcomes = Submissions
.SelectMany(static e => e.Results
.Select(static result => result.Outcome)
.ToAsyncEnumerable());

await foreach (var outcome in allOutcomes
.OrderBy(static e => e.Value.Order)
.Distinct())
{
var tableRow = new TableRow();

// Outcome (KPI) column
tableRow.AppendChild(CreateTableCell("3000", new Paragraph(new Run(new Text(outcome.Name)))));

// Assignments column
var assignmentsParagraph = new Paragraph();

var gradesParagraph = new Paragraph();
var gradesRun = gradesParagraph.AppendChild(new Run());

await foreach (var submission in Submissions.Select(static e => e))
{
foreach (var result in submission.Results.Select(static e => e))
{
if (result.Outcome.Id == outcome.Id)
{
var rel = mainDocumentPart.AddHyperlinkRelationship(new Uri(submission.AssignmentUrl!.ToString()), true);
var relationshipId = rel.Id;

var hyperlink = new Hyperlink(new Run(new RunProperties(new Underline { Val = UnderlineValues.Single, }), new Text(submission.Assignment!))) { Id = relationshipId, };

assignmentsParagraph.AppendChild(hyperlink);
assignmentsParagraph.AppendChild(new Run(new Break()));

var submissionGrade = result.Grade!.Value.ToString(CultureInfo.InvariantCulture);

gradesRun.AppendChild(new Text(submissionGrade));
gradesRun.AppendChild(new Break());
}
}
}

tableRow.AppendChild(CreateTableCell("5000", assignmentsParagraph));
tableRow.AppendChild(CreateTableCell("1000", gradesParagraph));

// Add the row to the table
table.AppendChild(tableRow);
}

// Newline to separate the table from the rest of the document
body?.Append(new Paragraph(new Run(new Text(""))));

// Add the table to the document
body?.AppendChild(table);

return body;
}

private static TableCell CreateTableCell(string? width, params OpenXmlElement[] elements)
{
var cell = new TableCell();
var cellProperties = new TableCellProperties();

foreach (var element in elements)
{
cell.Append(element);
}

if (width != null)
{
cellProperties.Append(new TableCellWidth
{
Type = TableWidthUnitValues.Dxa,
Width = width,
});
}

cell.PrependChild(cellProperties);

return cell;
}

public KpiTableComponent(IAsyncEnumerable<LearningDomainSubmission> submissions, IEnumerable<LearningDomain?> domains)
: base(submissions, domains)
{
}
}
2 changes: 2 additions & 0 deletions Epsilon/Services/CompetenceDocumentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
public async Task<CompetenceDocument> GetDocument(string userId, DateTime? from = null, DateTime? to = null)
{
var submissions = _canvasResultService.GetSubmissions(userId);
submissions = submissions.Where(static s => s.Criteria.Any());
if (from != null && to != null)
{
submissions = submissions.Where(s => s.SubmittedAt >= from && s.SubmittedAt <= to);
Expand Down Expand Up @@ -52,8 +53,9 @@
return wordDocument;
}

public static async IAsyncEnumerable<AbstractCompetenceComponent> FetchComponents(IAsyncEnumerable<LearningDomainSubmission> submissions, IEnumerable<LearningDomain?> domains)

Check warning on line 56 in Epsilon/Services/CompetenceDocumentService.cs

View workflow job for this annotation

GitHub Actions / Build .NET solution

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 56 in Epsilon/Services/CompetenceDocumentService.cs

View workflow job for this annotation

GitHub Actions / Build .NET solution

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 56 in Epsilon/Services/CompetenceDocumentService.cs

View workflow job for this annotation

GitHub Actions / Unit testing

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 56 in Epsilon/Services/CompetenceDocumentService.cs

View workflow job for this annotation

GitHub Actions / Unit testing

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
yield return new CompetenceProfileComponent(submissions, domains);
yield return new KpiTableComponent(submissions, domains);
}
}
Loading