Skip to content
This repository has been archived by the owner on Sep 4, 2023. It is now read-only.

Add KPI table component #108

Open
wants to merge 23 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
93e456b
Remove unused imports
Jun 16, 2023
1fd27fc
Add KPI table data model & component fetcher
Jun 16, 2023
27e8512
Add legenda data and frontend component
Jun 20, 2023
18d8ce3
Add support for kpi table background color based on kpi level
HansenSven Jun 20, 2023
9015ee5
Add kpi level indicator to kpi table & cleanup code
HansenSven Jun 21, 2023
91858c3
Cleanup kpi table component
HansenSven Jun 21, 2023
eb9ed93
Add hyperlink to assignmentName in KpiTable Word Export & Cleanup Kpi…
Jun 23, 2023
fc40e1b
Add support for personal development kpi's to KPI Table
Jun 23, 2023
d39e859
Move assessmentRating points to grade logic to model
HansenSven Jun 26, 2023
c02e970
Remove commented code
HansenSven Jun 26, 2023
22268f9
Use existing records to determine order, color and name & word export…
HansenSven Jun 26, 2023
81832ae
Merge branch 'develop' into feat/kpi-table
HansenSven Jun 26, 2023
8c01c63
Fix lint issues
HansenSven Jun 27, 2023
bb6f823
Merge branch 'develop' into feat/kpi-table
HansenSven Jun 27, 2023
96c5206
Fix lint issues
HansenSven Jun 27, 2023
9003e4e
Implemented Select
NealGeilen Jun 29, 2023
72ed003
Set equal order as KPI Matrix
NealGeilen Jun 29, 2023
ca0a5ce
Implementation of a dictionary
NealGeilen Jun 29, 2023
6ef160f
Changes in naming grades
NealGeilen Jun 29, 2023
410748d
Merge branch 'develop' into feat/kpi-table
NealGeilen Jun 29, 2023
338ec5b
Bugfix
NealGeilen Jun 29, 2023
ff0d3e5
Bug
NealGeilen Jun 29, 2023
b96a277
Removed unused code
NealGeilen Jun 29, 2023
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
1 change: 0 additions & 1 deletion Epsilon.Abstractions/Component/CompetenceProfile.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Epsilon.Abstractions.Model;
using Epsilon.Canvas.Abstractions.Model;

namespace Epsilon.Abstractions.Component;

Expand Down
170 changes: 170 additions & 0 deletions Epsilon.Abstractions/Component/KpiTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Epsilon.Canvas.Abstractions.Model;

namespace Epsilon.Abstractions.Component;

public record KpiTable(
IEnumerable<KpiTableEntry> Entries,
IDictionary<OutcomeGradeLevel, KpiTableEntryLevel> GradeStatus
) : IWordCompetenceComponent
{
public static readonly IDictionary<OutcomeGradeLevel, KpiTableEntryLevel> DefaultGradeStatus = new Dictionary<OutcomeGradeLevel, KpiTableEntryLevel>
{
{
OutcomeGradeLevel.One, new KpiTableEntryLevel("One", "CBF5DD")
},
{
OutcomeGradeLevel.Two, new KpiTableEntryLevel("Two", "64E3A1")
},
{
OutcomeGradeLevel.Three, new KpiTableEntryLevel("Three", "27A567")
},
{
OutcomeGradeLevel.Four, new KpiTableEntryLevel("Four", "198450")
HansenSven marked this conversation as resolved.
Show resolved Hide resolved
},
};

public void AddToWordDocument(MainDocumentPart mainDocumentPart)
{
var body = new Body();

// Create a table, with columns for the outcomes and corresponding assignments and grades
var table = new Table();

// Columns header texts
var columnsHeaders = new List<string> { "KPI", "Assignments", "Grades", };

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

// Create the header cells
foreach (var columnHeader in columnsHeaders)
{
headerRow.AppendChild(CreateTableCellWithBorders("3000", new Paragraph(new Run(new Text(columnHeader)))));
}

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

// Create the table body rows and cells in which the first cell is the outcome and the rest are the assignments and grades
foreach (var entry in Entries)
{
var tableRow = new TableRow();

// KPI column
tableRow.AppendChild(CreateTableCellWithBorders("3000", new Paragraph(new Run(new Text(entry.Kpi)))));

// Assignments column
var aParagraph = new Paragraph();
var aRun = aParagraph.AppendChild(new Run());

foreach (var assignment in entry.Assignments)
{
var rel = mainDocumentPart.AddHyperlinkRelationship(assignment.Link, true);
var relationshipId = rel.Id;

var runProperties = new RunProperties(
new Underline { Val = UnderlineValues.Single, });

aRun.AppendChild(new Hyperlink(new Run(runProperties, new Text(assignment.Name)))
{
History = OnOffValue.FromBoolean(true), Id = relationshipId,
});

aRun.AppendChild(new Break());
}

tableRow.AppendChild(CreateTableCellWithBorders("3000", aParagraph));

// Grades column
var grades = entry.Assignments.Select(static a => a.Grade);
var gParagraph = new Paragraph();
var gRun = gParagraph.AppendChild(new Run());

foreach (var grade in grades)
{
gRun.AppendChild(new Text(grade));
gRun.AppendChild(new Break());
}

tableRow.AppendChild(CreateTableCellWithBorders("3000", gParagraph));

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

// body.AppendChild(GetLegend());
body.Append(new Paragraph(new Run(new Text(""))));
body.AppendChild(table);

mainDocumentPart.Document.AppendChild(body);
}

// private OpenXmlElement GetLegend()
// {
// var table = new Table();
//
// foreach (var status in GradeStatus)
// {
// var row = new TableRow();
// var cellName = CreateTableCellWithBorders("200");
// cellName.Append(new Paragraph(new Run(new Text(status.Value.Level))));
//
// var cellValue = CreateTableCellWithBorders("200");
// cellValue.Append(new Paragraph(new Run(new Text(""))));
// cellValue.FirstChild?.Append(new Shading
// {
// Fill = status.Value.Color,
// });
// row.AppendChild(cellName);
// row.AppendChild(cellValue);
// table.AppendChild(row);
// }
//
// return table;
// }
HansenSven marked this conversation as resolved.
Show resolved Hide resolved

private static TableCell CreateTableCellWithBorders(string? width, params OpenXmlElement[] elements)
{
var cell = new TableCell();
var cellProperties = new TableCellProperties();
var borders = new TableCellBorders(
new LeftBorder
{
Val = BorderValues.Single,
},
new RightBorder
{
Val = BorderValues.Single,
},
new TopBorder
{
Val = BorderValues.Single,
},
new BottomBorder
{
Val = BorderValues.Single,
});

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

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

cellProperties.Append(borders);
cell.PrependChild(cellProperties);

return cell;
}
}
7 changes: 7 additions & 0 deletions Epsilon.Abstractions/Component/KpiTableEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Epsilon.Abstractions.Component;

public record KpiTableEntry(
string Kpi,
KpiTableEntryLevel Level,
IEnumerable<KpiTableEntryAssignment> Assignments
);
7 changes: 7 additions & 0 deletions Epsilon.Abstractions/Component/KpiTableEntryAssignment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Epsilon.Abstractions.Component;

public record KpiTableEntryAssignment(
string Name,
string Grade,
Uri Link
);
6 changes: 6 additions & 0 deletions Epsilon.Abstractions/Component/KpiTableEntryLevel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Epsilon.Abstractions.Component;

public record KpiTableEntryLevel(
string Level,
string Color
);
1 change: 0 additions & 1 deletion Epsilon.Abstractions/Service/IFilterService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Epsilon.Abstractions.Component;
using Epsilon.Canvas.Abstractions.Model;

namespace Epsilon.Abstractions.Service;
Expand Down
1 change: 1 addition & 0 deletions Epsilon.Canvas.Abstractions/Model/GraphQl/Assignment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Epsilon.Canvas.Abstractions.Model.GraphQl;

public record Assignment(
[property: JsonPropertyName("name")] string? Name,
[property: JsonPropertyName("htmlUrl")] Uri? HtmlUrl,
[property: JsonPropertyName("modules")] IEnumerable<Module>? Modules ,
[property: JsonPropertyName("rubric")] Rubric? Rubric
);
9 changes: 9 additions & 0 deletions Epsilon.Canvas.Abstractions/Model/OutcomeGradeLevel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Epsilon.Canvas.Abstractions.Model;

public enum OutcomeGradeLevel
{
One,
Two,
Three,
Four,
}
67 changes: 67 additions & 0 deletions Epsilon.Host.Frontend/src/components/KpiTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<script lang="ts" setup>
import { Api } from "../logic/Api"
import { Ref, ref } from "vue"

const api = new Api()
const today = new Date()
const otherMonth = new Date()
otherMonth.setMonth(otherMonth.getMonth() - 3)

const data: Ref<unknown> = ref<unknown>()
const Kpis: Ref<unknown> = ref<unknown>([])

api.component
.componentDetail("kpi_table", {
startDate: formatDate(otherMonth),
endDate: formatDate(today),
})
.then((result) => {
data.value = result.data
Kpis.value = result.data.entries
})

function formatDate(date: Date): string {
const year = date.getFullYear()
const month = `${date.getMonth() + 1}`.padStart(2, "0")
const day = date.getDate()
return `${year}-${month}-${day}`
}
</script>

<template>
<table v-if="data">
<tr>
<th>KPI</th>
<th>Assignments</th>
<th>Grades</th>
</tr>
<tr v-for="KPI of Kpis" :key="KPI">
<td :style="{
border: '3px solid #' + KPI.level.color,
}">
{{ KPI.kpi }}
</td>
<td>
<div
v-for="assignment of KPI.assignments"
:style="{ textAlign: 'start' }"
>
<a :href="assignment.link">{{ assignment.name }}</a>
</div>
</td>
<td>
<div v-for="assignment of KPI.assignments">
{{ assignment.grade }}
</div>
</td>
</tr>
</table>
</template>

<style scoped>
td,
th {
border: 2px solid;
padding: 1rem;
}
</style>
6 changes: 4 additions & 2 deletions Epsilon.Host.Frontend/src/views/PerformanceDashboard.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div v-if="data" class="performance-dashboard">
<!-- <div v-if="data" class="performance-dashboard">
<EnrollmentTermButtons
:terms="terms"
@on-term-selected="setTermFilter" />
Expand All @@ -15,7 +15,8 @@
:data="filteredProfessionalSkillOutcomes"
:domain="data?.hboIDomain"></PersonalDevelopmentGraph>
</div>
<RoundLoader v-else />
<RoundLoader v-else /> -->
<KpiTable />
</template>

<script lang="ts" setup>
Expand All @@ -32,6 +33,7 @@ import { computed, onMounted, Ref, ref } from "vue"
import RoundLoader from "@/components/RoundLoader.vue"
import EnrollmentTermButtons from "@/components/EnrollmentTermButtons.vue"
import PersonalDevelopmentGraph from "@/components/PersonalDevelopmentGraph.vue"
import KpiTable from "@/components/KpiTable.vue"

const data: Ref<CompetenceProfile | undefined> = ref(undefined)
const terms: Ref<EnrollmentTerm[]> = ref([])
Expand Down
4 changes: 3 additions & 1 deletion Epsilon.Host.WebApi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
});

builder.Services.AddControllers();

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
Expand All @@ -33,12 +34,14 @@
{ "persona_page", services.GetRequiredService<ICompetenceComponentFetcher<PersonaPage>>() },
{ "competence_profile", services.GetRequiredService<ICompetenceComponentFetcher<CompetenceProfile>>() },
{ "kpi_matrix", services.GetRequiredService<ICompetenceComponentFetcher<KpiMatrixCollection>>() },
{ "kpi_table", services.GetRequiredService<ICompetenceComponentFetcher<KpiTable>>() },
}
));

builder.Services.AddScoped<ICompetenceComponentFetcher<PersonaPage>, PersonaPageComponentFetcher>();
builder.Services.AddScoped<ICompetenceComponentFetcher<CompetenceProfile>, CompetenceProfileComponentFetcher>();
builder.Services.AddScoped<ICompetenceComponentFetcher<KpiMatrixCollection>, KpiMatrixComponentFetcher>();
builder.Services.AddScoped<ICompetenceComponentFetcher<KpiTable>, KpiTableComponentFetcher>();

var app = builder.Build();

Expand All @@ -50,7 +53,6 @@

app.UseSwagger();


app.UseHttpsRedirection();

app.UseCors();
Expand Down
Loading