-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add course class model and filter students by class in progress dashb…
…oard (#87) * Add course class model and filter students by class in progress dashboard (+ some CSS stuff) * Update table when user changes class * Fix dataSchema only showing the columns of the first student --------- Co-authored-by: zMendes <[email protected]>
- Loading branch information
1 parent
aec7657
commit 297332d
Showing
7 changed files
with
189 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,13 @@ | ||
from django.contrib import admin | ||
from django.contrib.auth.admin import UserAdmin | ||
|
||
from .models import Student, Instructor, Course, Exercise, ExerciseTag, TelemetryData | ||
from .models import Student, Instructor, Course, CourseClass, Exercise, ExerciseTag, TelemetryData | ||
|
||
|
||
admin.site.register(Student, UserAdmin) | ||
admin.site.register(Instructor, UserAdmin) | ||
admin.site.register(Course) | ||
admin.site.register(CourseClass) | ||
admin.site.register(Exercise) | ||
admin.site.register(ExerciseTag) | ||
admin.site.register(TelemetryData) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Generated by Django 4.2.4 on 2023-08-10 19:54 | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('core', '0005_course_end_date_course_start_date'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='CourseClass', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('name', models.CharField(blank=True, max_length=30, null=True)), | ||
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.course')), | ||
('students', models.ManyToManyField(to=settings.AUTH_USER_MODEL)), | ||
], | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,154 +1,183 @@ | ||
|
||
function createHandsontable(data, columns_list) { | ||
|
||
var container = document.getElementById('table'); | ||
Handsontable.renderers.registerRenderer('colorFormattingRenderer', function ( | ||
instance, | ||
td, | ||
row, | ||
col, | ||
prop, | ||
value, | ||
cellProperties | ||
) { | ||
cellProperties.editor = false; | ||
Handsontable.renderers.TextRenderer.apply(this, arguments); | ||
td.style.color = 'black'; | ||
var cell_value = parseFloat(value); | ||
if (cell_value == 1) { | ||
td.style.background = 'green'; | ||
} | ||
else if (cell_value == 0) { | ||
td.style.background = 'red'; | ||
} | ||
else if ((cell_value > 0) && (cell_value < 1)) { | ||
td.style.background = '#ffae00' | ||
data = filterStudentsInClass(data); | ||
|
||
const container = document.getElementById("table"); | ||
let dataSchema = getDataSchema(columns_list); | ||
Handsontable.renderers.registerRenderer( | ||
"colorFormattingRenderer", | ||
function (instance, td, row, col, prop, value, cellProperties) { | ||
cellProperties.editor = false; | ||
Handsontable.renderers.TextRenderer.apply(this, arguments); | ||
td.style.color = "black"; | ||
const cell_value = parseFloat(value); | ||
if (cell_value == 1) { | ||
td.style.background = "green"; | ||
} else if (cell_value == 0) { | ||
td.style.background = "red"; | ||
} else if (cell_value > 0 && cell_value < 1) { | ||
td.style.background = "#ffae00"; | ||
} | ||
} | ||
}); | ||
); | ||
|
||
hot = new Handsontable(container, { | ||
data: data, | ||
dataSchema: dataSchema, | ||
colHeaders: columns_list, | ||
columns: function (column) { | ||
columnMeta = {}; | ||
columnMeta.data = columns_list[column] | ||
columnMeta.data = columns_list[column]; | ||
return columnMeta; | ||
}, | ||
colWidths: [100].concat(Array(columns_list.length - 1).fill(30)), | ||
fixedColumnsStart: 1, | ||
cells: function (row, col, prop) { | ||
var cellProperties = {}; | ||
cellProperties.renderer = 'colorFormattingRenderer'; | ||
const cellProperties = {}; | ||
cellProperties.renderer = "colorFormattingRenderer"; | ||
return cellProperties; | ||
}, | ||
licenseKey: 'non-commercial-and-evaluation', // for non-commercial use only | ||
|
||
licenseKey: "non-commercial-and-evaluation", // for non-commercial use only | ||
}); | ||
} | ||
|
||
function updateHandsontable(data, columns_list) { | ||
data = filterStudentsInClass(data); | ||
|
||
let dataSchema = getDataSchema(columns_list); | ||
hot.updateSettings({ | ||
data: data, | ||
dataSchema: dataSchema, | ||
colHeaders: columns_list, | ||
columns: function (column) { | ||
columnMeta = {}; | ||
columnMeta.data = columns_list[column] | ||
columnMeta.data = columns_list[column]; | ||
return columnMeta; | ||
}, colWidths: [100].concat(Array(columns_list.length - 1).fill(30)), | ||
}, | ||
colWidths: [100].concat(Array(columns_list.length - 1).fill(30)), | ||
}); | ||
} | ||
|
||
function updateFilter() { | ||
function getDataSchema(columns_list) { | ||
var dataSchema = { name: null }; | ||
for (var i=0;i<columns_list.length;i++){ | ||
dataSchema[columns_list[i]] = null | ||
} | ||
return dataSchema; | ||
|
||
} | ||
|
||
function getTagSelect() { | ||
return document.getElementById("select-tag"); | ||
} | ||
|
||
function getClassSelect() { | ||
return document.getElementById("select-class"); | ||
} | ||
|
||
function getCurrentStudents() { | ||
const classSelect = getClassSelect(); | ||
const selectedClass = courseClasses[classSelect.selectedIndex]; | ||
return selectedClass.students; | ||
} | ||
|
||
var select = document.getElementById("select-tag"); | ||
var newValue = select.value; | ||
function filterStudentsInClass(data) { | ||
const currentStudents = getCurrentStudents(); | ||
return data.filter((row) => currentStudents.has(row.Name)); | ||
} | ||
|
||
function updateFilter() { | ||
const select = getTagSelect(); | ||
const newValue = select.value; | ||
select.value = ""; | ||
|
||
if (!Object.keys(tagsObj).includes(newValue)) | ||
return; | ||
if (!Object.keys(tagsObj).includes(newValue)) return; | ||
tags.add(newValue); | ||
generateTagView(); | ||
updateTableContent(); | ||
} | ||
|
||
function updateTableContent() { | ||
const clonedData = structuredClone(data); | ||
const clonedColumns = structuredClone(columns); | ||
|
||
var clonedData = structuredClone(data); | ||
var clonedColumns = structuredClone(columns); | ||
|
||
var filteredColumns = ["Name"] | ||
exerciseList = [] | ||
let filteredColumns = ["Name"]; | ||
exerciseList = []; | ||
if (tags.size == 0) { | ||
updateHandsontable(clonedData, clonedColumns); | ||
return; | ||
} | ||
tags.forEach(tag => { | ||
tags.forEach((tag) => { | ||
exerciseList = exerciseList.concat(tagsObj[tag]); | ||
}); | ||
for (var i = 0; i < exerciseList.length; i++) { | ||
var column_index = clonedColumns.indexOf(exerciseList[i]); | ||
const column_index = clonedColumns.indexOf(exerciseList[i]); | ||
if (column_index != -1) | ||
filteredColumns = filteredColumns.concat(clonedColumns.splice(column_index,1)); | ||
filteredColumns = filteredColumns.concat( | ||
clonedColumns.splice(column_index, 1) | ||
); | ||
} | ||
|
||
updateHandsontable(clonedData, filteredColumns); | ||
} | ||
|
||
function removeTag(ev) { | ||
tags.delete(ev.target.id); | ||
generateTagView(); | ||
updateTableContent() | ||
updateTableContent(); | ||
} | ||
|
||
function generateTagView() { | ||
var tagsDiv = document.getElementById("tags-list"); | ||
const tagsDiv = document.getElementById("tags-list"); | ||
tagsDiv.innerHTML = ""; | ||
tags.forEach(element => { | ||
var tagDiv = document.createElement("div"); | ||
tags.forEach((element) => { | ||
const tagDiv = document.createElement("div"); | ||
tagDiv.className = "tag"; | ||
var remove = document.createElement("button") | ||
remove.className = "btn btn-secondary" | ||
const remove = document.createElement("button"); | ||
remove.className = "btn btn-secondary"; | ||
remove.onclick = removeTag; | ||
remove.innerText = element | ||
remove.innerText = element; | ||
remove.id = element; | ||
tagDiv.appendChild(remove); | ||
tagsDiv.appendChild(tagDiv); | ||
|
||
}); | ||
} | ||
|
||
|
||
var tags = new Set(); | ||
var table; | ||
var columns; | ||
var data; | ||
var courseClasses; | ||
var tags; | ||
var hot; | ||
|
||
document.addEventListener('DOMContentLoaded', function () { | ||
|
||
table = document.getElementById('table'); | ||
columns = table.getAttribute('data-columns'); | ||
data = table.getAttribute('data-data'); | ||
tagsObj = table.getAttribute('data-tags') | ||
document.addEventListener("DOMContentLoaded", function () { | ||
table = document.getElementById("table"); | ||
columns = table.getAttribute("data-columns"); | ||
data = table.getAttribute("data-data"); | ||
tagsObj = table.getAttribute("data-tags"); | ||
courseClasses = table.getAttribute("data-classes"); | ||
|
||
//cleaning | ||
data = data.replace(/'/g, '"'); | ||
columns = columns.replace(/'/g, '"'); | ||
courseClasses = courseClasses.replace(/'/g, '"'); | ||
tagsObj = tagsObj.replace(/'/g, '"').replace(/(\w+):/g, '"$1":'); | ||
|
||
|
||
|
||
data = JSON.parse(data); | ||
columns = JSON.parse(columns) | ||
columns = JSON.parse(columns); | ||
courseClasses = JSON.parse(courseClasses); | ||
tagsObj = JSON.parse(tagsObj); | ||
|
||
courseClasses.forEach((courseClass) => { | ||
courseClass.students = new Set(courseClass.students); | ||
}); | ||
|
||
var select = document.getElementById("select-tag") | ||
select.onchange = updateFilter; | ||
const tagSelect = getTagSelect(); | ||
tagSelect.onchange = updateFilter; | ||
|
||
const classSelect = getClassSelect(); | ||
classSelect.onchange = updateTableContent; | ||
tableData = structuredClone(data); | ||
|
||
createHandsontable(tableData, columns); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.