Skip to content

Commit

Permalink
Merge pull request #12919 from ozer550/fix-csv-exports
Browse files Browse the repository at this point in the history
Fix broken CSV export features in COACH tabs
  • Loading branch information
marcellamaki authored Jan 7, 2025
2 parents 52f5ab4 + 71226bd commit 13d05c3
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
:to="classLearnersListRoute"
/>
<KIconButton
v-if="!disablePrint"
ref="printButton"
icon="print"
:aria-label="coachString('printReportAction')"
Expand Down Expand Up @@ -68,6 +69,10 @@
type: Boolean,
default: false,
},
disablePrint: {
type: Boolean,
default: false,
},
},
computed: {
exportDisabled() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
:text="$tr('back')"
/>
</p>
<ReportsControls />
<ReportsControls :disableExport="true" />
</div>
<h1>
<KLabeledIcon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@
:layout4="{ span: 2 }"
>
<KPageContainer class="content-spacing">
<h2>{{ coachString('lessonsAssignedLabel') }}</h2>
<div style="display: flex; justify-content: space-between">
<h2>{{ coachString('lessonsAssignedLabel') }}</h2>
<ReportsControls
:disablePrint="true"
@export="exportCSVLessons"
/>
</div>
<CoreTable :emptyMessage="coachString('lessonListEmptyState')">
<template #headers>
<th>{{ coachString('titleLabel') }}</th>
Expand Down Expand Up @@ -59,7 +65,13 @@
:layout4="{ span: 2 }"
>
<KPageContainer class="content-spacing">
<h2>{{ coachString('quizzesAssignedLabel') }}</h2>
<div style="display: flex; justify-content: space-between">
<h2>{{ coachString('quizzesAssignedLabel') }}</h2>
<ReportsControls
:disablePrint="true"
@export="exportCSVQuizzes"
/>
</div>
<CoreTable :emptyMessage="coachString('quizListEmptyState')">
<template #headers>
<th>{{ coachString('titleLabel') }}</th>
Expand Down Expand Up @@ -112,13 +124,17 @@
import commonCoach from '../../common';
import CoachAppBarPage from '../../CoachAppBarPage';
import { PageNames } from '../../../constants';
import ReportsControls from '../../common/ReportsControls';
import CSVExporter from '../../../csv/exporter';
import * as csvFields from '../../../csv/fields';
import LearnerHeader from './LearnerHeader';
export default {
name: 'LearnerSummaryPage',
components: {
CoachAppBarPage,
LearnerHeader,
ReportsControls,
},
mixins: [commonCoach, commonCoreStrings],
data() {
Expand Down Expand Up @@ -176,6 +192,50 @@
quizLink(quizId) {
return this.classRoute(PageNames.REPORTS_LEARNER_REPORT_QUIZ_PAGE_ROOT, { quizId });
},
exportCSVLessons() {
const filteredLessons = this.lessons
.filter(lesson => this.getLearnersForLesson(lesson).includes(this.learner.id))
.map(lesson => ({
...lesson,
status: this.getLessonStatusStringForLearner(lesson.id, this.learner.id),
}));
const LessonColumn = [...csvFields.title(), ...csvFields.learnerProgress()];
const LessonfileName = this.$tr('printLabel', { className: this.className });
const LessonExporter = new CSVExporter(LessonColumn, LessonfileName);
LessonExporter.addNames({
learner: this.learner.name,
report: 'Lesson',
});
LessonExporter.export(filteredLessons);
},
exportCSVQuizzes() {
const filteredExams = this.exams
.filter(exam => this.getLearnersForExam(exam).includes(this.learner.id))
.map(exam => ({
...exam,
statusObj: this.getExamStatusObjForLearner(exam.id, this.learner.id),
}));
const ExamColumn = [
...csvFields.title(),
...csvFields.learnerProgress('statusObj.status'),
...csvFields.score(),
];
const ExamfileName = this.$tr('printLabel', { className: this.className });
const ExamExporter = new CSVExporter(ExamColumn, ExamfileName);
ExamExporter.addNames({
learner: this.learner.name,
report: 'Quizzes',
});
ExamExporter.export(filteredExams);
},
loadMoreLessonTable() {
if (this.lessonLimit > 20) {
this.lessonLimit = this.getLessons.length;
Expand All @@ -192,6 +252,13 @@
this.quizLimit += 10;
},
},
$trs: {
printLabel: {
message: '{className} Learners',
context:
"Title that displays on a printed copy of the 'Learners' > 'Learner' page. This shows if the user uses the 'Print' option by clicking on the printer icon.",
},
},
};
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
/>
<div class="filter">
<KSelect
v-model="filterSelection"
v-model="recipientSelected"
:label="coachString('recipientsLabel')"
:options="filterOptions"
:options="recipientsOptions"
:inline="true"
/>
</div>
Expand Down Expand Up @@ -67,13 +67,15 @@
import sortBy from 'lodash/sortBy';
import ElapsedTime from 'kolibri-common/components/ElapsedTime';
import commonCoreStrings from 'kolibri/uiText/commonCoreStrings';
import { ref } from 'vue';
import commonCoach from '../common';
import CoachAppBarPage from '../CoachAppBarPage';
import CSVExporter from '../../csv/exporter';
import * as csvFields from '../../csv/fields';
import CoachHeader from '../common/CoachHeader';
import ReportsControls from '../common/ReportsControls';
import { PageNames } from '../../constants';
import { coachStrings } from '../common/commonCoachStrings';
export default {
name: 'LearnersRootPage',
Expand All @@ -84,22 +86,25 @@
CoachHeader,
},
mixins: [commonCoach, commonCoreStrings],
data() {
setup() {
const { entireClassLabel$ } = coachStrings;
const recipientSelected = ref({
label: entireClassLabel$(),
value: entireClassLabel$(),
});
return {
filterOptions: [
{
label: this.coreString('allLabel'),
value: this.coreString('allLabel'),
},
],
filterSelection: { label: this.coreString('allLabel'), value: this.coreString('allLabel') },
entireClassLabel$,
recipientSelected,
PageNames,
};
},
computed: {
table() {
const sorted = sortBy(this.learners, ['name']);
return sorted.map(learner => {
let augmentedTable = sorted.map(learner => {
const groupNames = this.getGroupNames(
this._.map(
this.groups.filter(group => group.member_ids.includes(learner.id)),
Expand All @@ -121,6 +126,37 @@
Object.assign(augmentedObj, learner);
return augmentedObj;
});
const recipientsFilter = this.recipientSelected.value;
if (recipientsFilter !== this.entireClassLabel$()) {
augmentedTable = augmentedTable.filter(entry => {
return entry.groups.includes(recipientsFilter) || entry.id === recipientsFilter;
});
}
return augmentedTable;
},
recipientsOptions() {
const groupOptions = this.groups.map(group => ({
label: group.name,
value: group.name,
}));
const learnerOptions = this.learners.map(learner => ({
label: learner.name,
value: learner.id,
}));
return [
{
label: this.entireClassLabel$(),
value: this.entireClassLabel$(),
},
...groupOptions,
...learnerOptions,
];
},
},
methods: {
Expand Down
13 changes: 10 additions & 3 deletions kolibri/plugins/coach/assets/src/views/quizzes/ExamsRootPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@
'getExamStatusTally',
'getLearnersForExam',
'getRecipientNamesForExam',
'getGroupNames',
]),
...mapState('classSummary', { className: 'name' }),
practiceQuizzesExist() {
Expand Down Expand Up @@ -447,11 +448,14 @@
exam.groups.includes(recipientsFilter) || exam.learner_ids.includes(recipientsFilter),
);
}
return selectedExams.map(quiz => {
const learnersForQuiz = this.getLearnersForExam(quiz);
quiz.tally = this.getExamStatusTally(quiz.id, learnersForQuiz);
quiz.avgScore = this.getExamAvgScore(quiz.id, learnersForQuiz);
quiz.totalLearners = this.getLearnersForExam(quiz).length;
quiz.recipientNames = this.getRecipientNamesForExam(quiz);
quiz.hasAssignments = quiz.assignments.length > 0;
quiz.groupNames = this.getGroupNames(quiz.groups);
return quiz;
});
},
Expand Down Expand Up @@ -526,8 +530,11 @@
const columns = [
...csvFields.title(),
...csvFields.recipients(this.className),
...csvFields.avgScore(),
...csvFields.allLearners('totalLearners'),
...csvFields.tally(),
];
const fileName = this.$tr('printLabel', { className: this.className });
new CSVExporter(columns, fileName).export(this.filteredExams);
},
Expand Down Expand Up @@ -592,9 +599,9 @@
'Descriptive text at the top of the table that displays the calculated file size of all quiz resources (i.e. 120 MB)',
},
printLabel: {
message: '{className} Lessons',
message: '{className} Quizzes',
context:
"Title that displays on a printed copy of the 'Reports' > 'Lessons' page. This shows if the user uses the 'Print' option by clicking on the printer icon.",
"Title that displays on a printed copy of the 'Coach' > 'Quizzes' page. This shows if the user uses the 'Print' option by clicking on the printer icon.",
},
adminLink: {
message: 'Import channels to your device',
Expand Down

0 comments on commit 13d05c3

Please sign in to comment.