Merged in feature/VBV-585-cockpit-edoniq-tests (pull request #229)
Feature/VBV-585 cockpit edoniq tests Approved-by: Christian Cueni
This commit is contained in:
commit
f99e58ee88
|
|
@ -2,13 +2,13 @@
|
||||||
<li
|
<li
|
||||||
class="flex flex-col justify-between gap-2 border-t border-gray-500 py-4 leading-[45px] lg:flex-row lg:gap-4"
|
class="flex flex-col justify-between gap-2 border-t border-gray-500 py-4 leading-[45px] lg:flex-row lg:gap-4"
|
||||||
>
|
>
|
||||||
<div class="flex flex-row items-center lg:w-1/3">
|
<div class="flex flex-row items-center lg:w-1/4">
|
||||||
<slot name="firstRow"></slot>
|
<slot name="firstRow"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 lg:items-center">
|
<div class="flex flex-1 lg:items-center">
|
||||||
<slot name="center"></slot>
|
<slot name="center"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center lg:w-1/4">
|
<div class="flex items-center">
|
||||||
<slot name="link"></slot>
|
<slot name="link"></slot>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ const documents = {
|
||||||
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n needs_expert_evaluation\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_points\n evaluation_max_points\n evaluation_passed\n edoniq_extended_time_flag\n completion_data\n task_completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
|
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n needs_expert_evaluation\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_points\n evaluation_max_points\n evaluation_passed\n edoniq_extended_time_flag\n completion_data\n task_completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
|
||||||
"\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument,
|
"\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument,
|
||||||
"\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n": types.CourseSessionDetailDocument,
|
"\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n": types.CourseSessionDetailDocument,
|
||||||
"\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.CourseQueryDocument,
|
"\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.CourseQueryDocument,
|
||||||
"\n query dashboardConfig {\n dashboard_config {\n id\n slug\n name\n dashboard_type\n }\n }\n": types.DashboardConfigDocument,
|
"\n query dashboardConfig {\n dashboard_config {\n id\n slug\n name\n dashboard_type\n }\n }\n": types.DashboardConfigDocument,
|
||||||
"\n query dashboardProgress($courseId: ID!) {\n course_progress(course_id: $courseId) {\n _id\n course_id\n session_to_continue_id\n competence {\n _id\n total_count\n success_count\n fail_count\n }\n assignment {\n _id\n total_count\n points_max_count\n points_achieved_count\n }\n }\n }\n": types.DashboardProgressDocument,
|
"\n query dashboardProgress($courseId: ID!) {\n course_progress(course_id: $courseId) {\n _id\n course_id\n session_to_continue_id\n competence {\n _id\n total_count\n success_count\n fail_count\n }\n assignment {\n _id\n total_count\n points_max_count\n points_achieved_count\n }\n }\n }\n": types.DashboardProgressDocument,
|
||||||
"\n query courseStatistics($courseId: ID!) {\n course_statistics(course_id: $courseId) {\n _id\n course_id\n course_title\n course_slug\n course_session_properties {\n _id\n sessions {\n id\n name\n }\n generations\n circles {\n id\n name\n }\n }\n course_session_selection_ids\n course_session_selection_metrics {\n _id\n session_count\n participant_count\n expert_count\n }\n attendance_day_presences {\n _id\n records {\n _id\n course_session_id\n generation\n circle_id\n due_date\n participants_present\n participants_total\n details_url\n }\n summary {\n _id\n days_completed\n participants_present\n }\n }\n feedback_responses {\n _id\n records {\n _id\n course_session_id\n generation\n circle_id\n experts\n satisfaction_average\n satisfaction_max\n details_url\n }\n summary {\n _id\n satisfaction_average\n satisfaction_max\n total_responses\n }\n }\n assignments {\n _id\n summary {\n _id\n completed_count\n average_passed\n }\n records {\n _id\n course_session_id\n course_session_assignment_id\n circle_id\n generation\n assignment_title\n assignment_type_translation_key\n details_url\n deadline\n metrics {\n _id\n passed_count\n failed_count\n unranked_count\n ranking_completed\n average_passed\n }\n }\n }\n competences {\n _id\n summary {\n _id\n success_total\n fail_total\n }\n records {\n _id\n course_session_id\n generation\n circle_id\n title\n success_count\n fail_count\n details_url\n }\n }\n }\n }\n": types.CourseStatisticsDocument,
|
"\n query courseStatistics($courseId: ID!) {\n course_statistics(course_id: $courseId) {\n _id\n course_id\n course_title\n course_slug\n course_session_properties {\n _id\n sessions {\n id\n name\n }\n generations\n circles {\n id\n name\n }\n }\n course_session_selection_ids\n course_session_selection_metrics {\n _id\n session_count\n participant_count\n expert_count\n }\n attendance_day_presences {\n _id\n records {\n _id\n course_session_id\n generation\n circle_id\n due_date\n participants_present\n participants_total\n details_url\n }\n summary {\n _id\n days_completed\n participants_present\n }\n }\n feedback_responses {\n _id\n records {\n _id\n course_session_id\n generation\n circle_id\n experts\n satisfaction_average\n satisfaction_max\n details_url\n }\n summary {\n _id\n satisfaction_average\n satisfaction_max\n total_responses\n }\n }\n assignments {\n _id\n summary {\n _id\n completed_count\n average_passed\n }\n records {\n _id\n course_session_id\n course_session_assignment_id\n circle_id\n generation\n assignment_title\n assignment_type_translation_key\n details_url\n deadline\n metrics {\n _id\n passed_count\n failed_count\n unranked_count\n ranking_completed\n average_passed\n }\n }\n }\n competences {\n _id\n summary {\n _id\n success_total\n fail_total\n }\n records {\n _id\n course_session_id\n generation\n circle_id\n title\n success_count\n fail_count\n details_url\n }\n }\n }\n }\n": types.CourseStatisticsDocument,
|
||||||
|
|
@ -72,7 +72,7 @@ export function graphql(source: "\n query courseSessionDetail($courseSessionId:
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(source: "\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"];
|
export function graphql(source: "\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n assignment_type\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -241,6 +241,7 @@ export const COURSE_QUERY = graphql(`
|
||||||
assignment_type
|
assignment_type
|
||||||
content_assignment {
|
content_assignment {
|
||||||
id
|
id
|
||||||
|
assignment_type
|
||||||
}
|
}
|
||||||
competence_certificate {
|
competence_certificate {
|
||||||
...CoursePageFields
|
...CoursePageFields
|
||||||
|
|
@ -251,6 +252,7 @@ export const COURSE_QUERY = graphql(`
|
||||||
has_extended_time_test
|
has_extended_time_test
|
||||||
content_assignment {
|
content_assignment {
|
||||||
id
|
id
|
||||||
|
assignment_type
|
||||||
}
|
}
|
||||||
competence_certificate {
|
competence_certificate {
|
||||||
...CoursePageFields
|
...CoursePageFields
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import type {
|
||||||
CourseSession,
|
CourseSession,
|
||||||
CourseSessionUser,
|
CourseSessionUser,
|
||||||
LearningContentAssignment,
|
LearningContentAssignment,
|
||||||
|
LearningContentEdoniqTest,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed, onMounted, reactive } from "vue";
|
import { computed, onMounted, reactive } from "vue";
|
||||||
|
|
@ -14,10 +15,13 @@ import AssignmentSubmissionProgress from "@/pages/cockpit/cockpitPage/Assignment
|
||||||
import { useCourseSessionDetailQuery } from "@/composables";
|
import { useCourseSessionDetailQuery } from "@/composables";
|
||||||
import { formatDueDate } from "../../../components/dueDates/dueDatesUtils";
|
import { formatDueDate } from "../../../components/dueDates/dueDatesUtils";
|
||||||
import { stringifyParse } from "@/utils/utils";
|
import { stringifyParse } from "@/utils/utils";
|
||||||
|
import { useTranslation } from "i18next-vue";
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSession: CourseSession;
|
courseSession: CourseSession;
|
||||||
learningContentAssignment: LearningContentAssignment;
|
learningContent: LearningContentAssignment | LearningContentEdoniqTest;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
log.debug("AssignmentDetails created", stringifyParse(props));
|
log.debug("AssignmentDetails created", stringifyParse(props));
|
||||||
|
|
@ -31,28 +35,54 @@ const state = reactive({
|
||||||
});
|
});
|
||||||
|
|
||||||
const assignmentDetail = computed(() => {
|
const assignmentDetail = computed(() => {
|
||||||
return courseSessionDetailResult.findAssignment(props.learningContentAssignment.id);
|
return courseSessionDetailResult.findAssignment(props.learningContent.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const { gradedUsers, assignmentSubmittedUsers } =
|
const { gradedUsers, assignmentSubmittedUsers } =
|
||||||
await loadAssignmentCompletionStatusData(
|
await loadAssignmentCompletionStatusData(
|
||||||
props.learningContentAssignment.content_assignment.id,
|
props.learningContent.content_assignment.id,
|
||||||
props.courseSession.id,
|
props.courseSession.id,
|
||||||
props.learningContentAssignment.id
|
props.learningContent.id
|
||||||
);
|
);
|
||||||
state.gradedUsers = gradedUsers;
|
state.gradedUsers = gradedUsers;
|
||||||
state.assignmentSubmittedUsers = assignmentSubmittedUsers;
|
state.assignmentSubmittedUsers = assignmentSubmittedUsers;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function findGradedUser(userId: string) {
|
||||||
|
return state.gradedUsers.find((gu) => gu.user.user_id === userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findUserPointsHtml(userId: string) {
|
||||||
|
let result = "";
|
||||||
|
const gradedUser = findGradedUser(userId);
|
||||||
|
if (gradedUser) {
|
||||||
|
result = `${gradedUser.points} ${t("assignment.von x Punkten", {
|
||||||
|
x: gradedUser.maxPoints,
|
||||||
|
})}`;
|
||||||
|
|
||||||
|
result +=
|
||||||
|
" (" +
|
||||||
|
(((gradedUser.points ?? 0) / (gradedUser.maxPoints ?? 1)) * 100).toFixed(0) +
|
||||||
|
"%)";
|
||||||
|
|
||||||
|
if (!gradedUser.passed) {
|
||||||
|
result += ` <span class="my-2 rounded-md bg-error-red-200 px-2.5 py-0.5">${t(
|
||||||
|
"a.Nicht bestanden"
|
||||||
|
)}</span>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="heading-2 font-bold">
|
<h2 class="heading-2 font-bold">
|
||||||
{{ learningContentAssignment.title }}
|
{{ learningContent.title }}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="pt-1 underline">
|
<div class="pt-1 underline">
|
||||||
{{ $t("a.Circle") }} «{{ learningContentAssignment.circle?.title }}»
|
{{ $t("a.Circle") }} «{{ learningContent.circle?.title }}»
|
||||||
</div>
|
</div>
|
||||||
<div v-if="assignmentDetail">
|
<div v-if="assignmentDetail">
|
||||||
<span v-if="assignmentDetail.submission_deadline?.start">
|
<span v-if="assignmentDetail.submission_deadline?.start">
|
||||||
|
|
@ -73,7 +103,7 @@ onMounted(async () => {
|
||||||
<!-- how to determine assignment-type? how to get AssignmentLearningContent? -->
|
<!-- how to determine assignment-type? how to get AssignmentLearningContent? -->
|
||||||
<AssignmentSubmissionProgress
|
<AssignmentSubmissionProgress
|
||||||
:course-session="courseSession"
|
:course-session="courseSession"
|
||||||
:learning-content-assignment="learningContentAssignment"
|
:learning-content="learningContent"
|
||||||
:show-title="false"
|
:show-title="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -88,7 +118,7 @@ onMounted(async () => {
|
||||||
:data-cy="csu.last_name"
|
:data-cy="csu.last_name"
|
||||||
>
|
>
|
||||||
<template #center>
|
<template #center>
|
||||||
<section class="flex w-full justify-between">
|
<section class="flex w-full flex-col justify-between lg:flex-row lg:gap-8">
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
state.gradedUsers.map((gradedUser) => gradedUser.user).includes(csu)
|
state.gradedUsers.map((gradedUser) => gradedUser.user).includes(csu)
|
||||||
|
|
@ -114,27 +144,28 @@ onMounted(async () => {
|
||||||
<div class="ml-2">{{ $t("a.Ergebnisse abgegeben") }}</div>
|
<div class="ml-2">{{ $t("a.Ergebnisse abgegeben") }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="findGradedUser(csu.user_id)"
|
||||||
state.gradedUsers.map((gradedUser) => gradedUser.user).includes(csu)
|
v-html="findUserPointsHtml(csu.user_id)"
|
||||||
"
|
></div>
|
||||||
>
|
|
||||||
{{
|
|
||||||
state.gradedUsers.find((u) => u.user.user_id === csu.user_id)?.points
|
|
||||||
}}
|
|
||||||
{{ $t("a.Punkte") }}
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<template #link>
|
<template #link>
|
||||||
|
<div class="lg:ml-4">
|
||||||
<router-link
|
<router-link
|
||||||
v-if="state.assignmentSubmittedUsers.includes(csu)"
|
v-if="
|
||||||
:to="`/course/${props.courseSession.course.slug}/cockpit/assignment/${learningContentAssignment.content_assignment.id}/${csu.user_id}`"
|
state.assignmentSubmittedUsers.includes(csu) &&
|
||||||
|
props.learningContent.content_type !==
|
||||||
|
'learnpath.LearningContentEdoniqTest'
|
||||||
|
"
|
||||||
|
:to="`/course/${props.courseSession.course.slug}/cockpit/assignment/${learningContent.content_assignment.id}/${csu.user_id}`"
|
||||||
class="link lg:w-full lg:text-right"
|
class="link lg:w-full lg:text-right"
|
||||||
data-cy="show-results"
|
data-cy="show-results"
|
||||||
>
|
>
|
||||||
{{ $t("a.Ergebnisse anschauen") }}
|
{{ $t("a.Ergebnisse anschauen") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ItPersonRow>
|
</ItPersonRow>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCurrentCourseSession, useCourseData } from "@/composables";
|
import { useCourseData, useCurrentCourseSession } from "@/composables";
|
||||||
import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue";
|
import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { computed, onMounted } from "vue";
|
import { computed, onMounted } from "vue";
|
||||||
import type { LearningContentAssignment } from "@/types";
|
import type { LearningContentAssignment, LearningContentEdoniqTest } from "@/types";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSlug: string;
|
courseSlug: string;
|
||||||
|
|
@ -42,7 +42,7 @@ const learningContentAssignment = computed(() => {
|
||||||
<AssignmentDetails
|
<AssignmentDetails
|
||||||
v-if="learningContentAssignment"
|
v-if="learningContentAssignment"
|
||||||
:course-session="courseSession"
|
:course-session="courseSession"
|
||||||
:learning-content-assignment="learningContentAssignment as LearningContentAssignment"
|
:learning-content="learningContentAssignment as (LearningContentAssignment | LearningContentEdoniqTest)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,15 @@ import type {
|
||||||
AssignmentCompletionStatus,
|
AssignmentCompletionStatus,
|
||||||
CourseSession,
|
CourseSession,
|
||||||
LearningContentAssignment,
|
LearningContentAssignment,
|
||||||
|
LearningContentEdoniqTest,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { onMounted, reactive } from "vue";
|
import { computed, onMounted, reactive } from "vue";
|
||||||
import { stringifyParse } from "@/utils/utils";
|
import { stringifyParse } from "@/utils/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSession: CourseSession;
|
courseSession: CourseSession;
|
||||||
learningContentAssignment: LearningContentAssignment;
|
learningContent: LearningContentAssignment | LearningContentEdoniqTest;
|
||||||
showTitle: boolean;
|
showTitle: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
@ -32,9 +33,9 @@ const state = reactive({
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const { assignmentSubmittedUsers, gradedUsers, total } =
|
const { assignmentSubmittedUsers, gradedUsers, total } =
|
||||||
await loadAssignmentCompletionStatusData(
|
await loadAssignmentCompletionStatusData(
|
||||||
props.learningContentAssignment.content_assignment.id,
|
props.learningContent.content_assignment.id,
|
||||||
props.courseSession.id,
|
props.courseSession.id,
|
||||||
props.learningContentAssignment.id
|
props.learningContent.id
|
||||||
);
|
);
|
||||||
|
|
||||||
state.submissionProgressStatusCount = {
|
state.submissionProgressStatusCount = {
|
||||||
|
|
@ -56,16 +57,31 @@ const doneCount = (status: StatusCount) => {
|
||||||
const totalCount = (status: StatusCount) => {
|
const totalCount = (status: StatusCount) => {
|
||||||
return doneCount(status) + status.UNKNOWN || 0;
|
return doneCount(status) + status.UNKNOWN || 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const showEvaluationStatus = computed(() => {
|
||||||
|
return (
|
||||||
|
props.learningContent.content_assignment.assignment_type === "CASEWORK" ||
|
||||||
|
props.learningContent.content_assignment.assignment_type === "EDONIQ_TEST"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const showSubmissionStatus = computed(() => {
|
||||||
|
return (
|
||||||
|
props.learningContent.content_assignment.assignment_type === "PREP_ASSIGNMENT" ||
|
||||||
|
props.learningContent.content_assignment.assignment_type === "REFLECTION" ||
|
||||||
|
props.learningContent.content_assignment.assignment_type === "CONDITION_ACCEPTANCE"
|
||||||
|
);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="showTitle">
|
<div v-if="showTitle">
|
||||||
{{ props.learningContentAssignment.title }}
|
{{ props.learningContent.title }}
|
||||||
</div>
|
</div>
|
||||||
<ItProgress :status-count="state.submissionProgressStatusCount" />
|
<ItProgress :status-count="state.submissionProgressStatusCount" />
|
||||||
<div class="text-gray-900">
|
<div class="text-gray-900">
|
||||||
<div v-if="props.learningContentAssignment.assignment_type === 'CASEWORK'">
|
<div v-if="showEvaluationStatus">
|
||||||
{{
|
{{
|
||||||
$t("x von y Ergebnisse abgegeben", {
|
$t("x von y Ergebnisse abgegeben", {
|
||||||
x: doneCount(state.submissionProgressStatusCount),
|
x: doneCount(state.submissionProgressStatusCount),
|
||||||
|
|
@ -80,13 +96,7 @@ const totalCount = (status: StatusCount) => {
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-else-if="showSubmissionStatus">
|
||||||
v-else-if="
|
|
||||||
props.learningContentAssignment.assignment_type === 'PREP_ASSIGNMENT' ||
|
|
||||||
props.learningContentAssignment.assignment_type === 'CONDITION_ACCEPTANCE' ||
|
|
||||||
props.learningContentAssignment.assignment_type === 'REFLECTION'
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{
|
{{
|
||||||
$t("x von y abgeschlossen", {
|
$t("x von y abgeschlossen", {
|
||||||
x: doneCount(state.submissionProgressStatusCount),
|
x: doneCount(state.submissionProgressStatusCount),
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
>
|
>
|
||||||
<template #center>
|
<template #center>
|
||||||
<div
|
<div
|
||||||
class="mt-2 flex w-full flex-col items-center justify-between lg:mt-0 lg:flex-row"
|
class="mt-2 flex w-full flex-col items-center justify-start lg:mt-0 lg:flex-row"
|
||||||
>
|
>
|
||||||
<LearningPathDiagram
|
<LearningPathDiagram
|
||||||
:course-session-id="courseSession.id"
|
:course-session-id="courseSession.id"
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import type {
|
||||||
CourseSession,
|
CourseSession,
|
||||||
LearningContent,
|
LearningContent,
|
||||||
LearningContentAssignment,
|
LearningContentAssignment,
|
||||||
|
LearningContentEdoniqTest,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
@ -12,8 +13,8 @@ import { useTranslation } from "i18next-vue";
|
||||||
import FeedbackSubmissionProgress from "@/pages/cockpit/cockpitPage/FeedbackSubmissionProgress.vue";
|
import FeedbackSubmissionProgress from "@/pages/cockpit/cockpitPage/FeedbackSubmissionProgress.vue";
|
||||||
import { learningContentTypeData } from "@/utils/typeMaps";
|
import { learningContentTypeData } from "@/utils/typeMaps";
|
||||||
import {
|
import {
|
||||||
useCourseSessionDetailQuery,
|
|
||||||
useCourseDataWithCompletion,
|
useCourseDataWithCompletion,
|
||||||
|
useCourseSessionDetailQuery,
|
||||||
} from "@/composables";
|
} from "@/composables";
|
||||||
import { circleFlatLearningContents } from "@/services/circle";
|
import { circleFlatLearningContents } from "@/services/circle";
|
||||||
|
|
||||||
|
|
@ -51,7 +52,8 @@ const submittables = computed(() => {
|
||||||
const learningContents = circleFlatLearningContents(circle).filter(
|
const learningContents = circleFlatLearningContents(circle).filter(
|
||||||
(lc) =>
|
(lc) =>
|
||||||
lc.content_type === "learnpath.LearningContentAssignment" ||
|
lc.content_type === "learnpath.LearningContentAssignment" ||
|
||||||
lc.content_type === "learnpath.LearningContentFeedback"
|
lc.content_type === "learnpath.LearningContentFeedback" ||
|
||||||
|
lc.content_type === "learnpath.LearningContentEdoniqTest"
|
||||||
);
|
);
|
||||||
|
|
||||||
return learningContents.map((lc) => {
|
return learningContents.map((lc) => {
|
||||||
|
|
@ -77,6 +79,10 @@ const isAssignment = (lc: LearningContent) => {
|
||||||
return lc.content_type === "learnpath.LearningContentAssignment";
|
return lc.content_type === "learnpath.LearningContentAssignment";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isEdoniqTest = (lc: LearningContent) => {
|
||||||
|
return lc.content_type === "learnpath.LearningContentEdoniqTest";
|
||||||
|
};
|
||||||
|
|
||||||
const getLearningContentType = (lc: LearningContent) => {
|
const getLearningContentType = (lc: LearningContent) => {
|
||||||
if (isAssignment(lc)) {
|
if (isAssignment(lc)) {
|
||||||
const lcTypeData = learningContentTypeData(lc);
|
const lcTypeData = learningContentTypeData(lc);
|
||||||
|
|
@ -84,8 +90,12 @@ const getLearningContentType = (lc: LearningContent) => {
|
||||||
return lcTypeData.title;
|
return lcTypeData.title;
|
||||||
}
|
}
|
||||||
return `${lcTypeData.title}: ${lc.title}`;
|
return `${lcTypeData.title}: ${lc.title}`;
|
||||||
}
|
} else if (isEdoniqTest(lc)) {
|
||||||
|
return lc.title;
|
||||||
|
} else if (isFeedback(lc)) {
|
||||||
return t("Feedback: Feedback zum Lehrgang");
|
return t("Feedback: Feedback zum Lehrgang");
|
||||||
|
}
|
||||||
|
return "!!unknown!!";
|
||||||
};
|
};
|
||||||
|
|
||||||
const getShowDetailsText = (lc: LearningContent) => {
|
const getShowDetailsText = (lc: LearningContent) => {
|
||||||
|
|
@ -99,15 +109,21 @@ const getShowDetailsText = (lc: LearningContent) => {
|
||||||
) {
|
) {
|
||||||
return t("Status anschauen");
|
return t("Status anschauen");
|
||||||
}
|
}
|
||||||
}
|
} else if (isEdoniqTest(lc)) {
|
||||||
|
return t("a.Ergebnisse anschauen");
|
||||||
|
} else if (isFeedback(lc)) {
|
||||||
return t("Feedback anschauen");
|
return t("Feedback anschauen");
|
||||||
|
}
|
||||||
|
return "!!unknown!!";
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDetailsLink = (lc: LearningContent, circleId: string) => {
|
const getDetailsLink = (lc: LearningContent, circleId: string) => {
|
||||||
if (isFeedback(lc)) {
|
if (isFeedback(lc)) {
|
||||||
return `cockpit/feedback/${circleId}`;
|
return `cockpit/feedback/${circleId}`;
|
||||||
}
|
} else if (isAssignment(lc) || isEdoniqTest(lc)) {
|
||||||
return `cockpit/assignment/${lc.id}`;
|
return `cockpit/assignment/${lc.id}`;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
const getIconName = (lc: LearningContent) => {
|
const getIconName = (lc: LearningContent) => {
|
||||||
|
|
@ -153,9 +169,9 @@ const getIconName = (lc: LearningContent) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AssignmentSubmissionProgress
|
<AssignmentSubmissionProgress
|
||||||
v-if="isAssignment(submittable.content)"
|
v-if="isAssignment(submittable.content) || isEdoniqTest(submittable.content)"
|
||||||
:course-session="props.courseSession"
|
:course-session="props.courseSession"
|
||||||
:learning-content-assignment="submittable.content as LearningContentAssignment"
|
:learning-content="submittable.content as (LearningContentAssignment | LearningContentEdoniqTest)"
|
||||||
:show-title="false"
|
:show-title="false"
|
||||||
class="grow pr-8"
|
class="grow pr-8"
|
||||||
/>
|
/>
|
||||||
|
|
@ -166,7 +182,7 @@ const getIconName = (lc: LearningContent) => {
|
||||||
class="grow pr-8"
|
class="grow pr-8"
|
||||||
></FeedbackSubmissionProgress>
|
></FeedbackSubmissionProgress>
|
||||||
<div class="flex items-center lg:w-1/4 lg:justify-end">
|
<div class="flex items-center lg:w-1/4 lg:justify-end">
|
||||||
<button class="btn-primary">
|
<button v-if="submittable.detailsLink" class="btn-primary">
|
||||||
<router-link
|
<router-link
|
||||||
:to="submittable.detailsLink"
|
:to="submittable.detailsLink"
|
||||||
:data-cy="
|
:data-cy="
|
||||||
|
|
|
||||||
|
|
@ -38,14 +38,14 @@ const assignmentStats = (metrics: AssignmentCompletionMetricsType) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const total = (metrics: AssignmentCompletionMetricsType) => {
|
const total = (metrics: AssignmentCompletionMetricsType) => {
|
||||||
return metrics.passed_count + metrics.failed_count;
|
return metrics.passed_count + metrics.failed_count + metrics.unranked_count;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main v-if="statistics">
|
<main v-if="statistics">
|
||||||
<div class="mb-10 flex items-center justify-between">
|
<div class="mb-10 flex items-center justify-between">
|
||||||
<h3>{{ $t("a.Arbeiten") }}</h3>
|
<h3>{{ $t("a.Kompetenznachweis-Elemente") }}</h3>
|
||||||
<ItDropdownSelect
|
<ItDropdownSelect
|
||||||
:model-value="dashboardStore.currentDashboardConfig"
|
:model-value="dashboardStore.currentDashboardConfig"
|
||||||
class="mt-4 w-full lg:mt-0 lg:w-96"
|
class="mt-4 w-full lg:mt-0 lg:w-96"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ import pick from "lodash/pick";
|
||||||
export interface GradedUser {
|
export interface GradedUser {
|
||||||
user: CourseSessionUser;
|
user: CourseSessionUser;
|
||||||
points: number;
|
points: number;
|
||||||
|
maxPoints: number;
|
||||||
|
passed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadAssignmentCompletionStatusData(
|
export async function loadAssignmentCompletionStatusData(
|
||||||
|
|
@ -46,6 +48,8 @@ export async function loadAssignmentCompletionStatusData(
|
||||||
gradedUsers.push({
|
gradedUsers.push({
|
||||||
user: csu,
|
user: csu,
|
||||||
points: userAssignmentStatus.evaluation_points ?? 0,
|
points: userAssignmentStatus.evaluation_points ?? 0,
|
||||||
|
maxPoints: userAssignmentStatus.evaluation_max_points ?? 0,
|
||||||
|
passed: userAssignmentStatus.evaluation_passed ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -531,6 +531,8 @@ export interface UserAssignmentCompletionStatus {
|
||||||
assignment_user_id: string;
|
assignment_user_id: string;
|
||||||
completion_status: AssignmentCompletionStatus;
|
completion_status: AssignmentCompletionStatus;
|
||||||
evaluation_points: number | null;
|
evaluation_points: number | null;
|
||||||
|
evaluation_max_points: number | null;
|
||||||
|
evaluation_passed: boolean;
|
||||||
learning_content_page_id: string;
|
learning_content_page_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ describe("assignmentTrainer.cy.js", () => {
|
||||||
).click();
|
).click();
|
||||||
|
|
||||||
cy.get('[data-cy="Student1"]').should("contain", "Bewertung freigegeben");
|
cy.get('[data-cy="Student1"]').should("contain", "Bewertung freigegeben");
|
||||||
cy.get('[data-cy="Student1"]').should("contain", "17 Punkte");
|
cy.get('[data-cy="Student1"]').should("contain", "17 von 24 Punkte");
|
||||||
|
|
||||||
// clicking on results page will go to last step
|
// clicking on results page will go to last step
|
||||||
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import {login} from "../helpers";
|
import { login } from "../helpers";
|
||||||
|
|
||||||
|
// ignore automatic import mess-up...
|
||||||
|
|
||||||
const getDashboardStatistics = (what) => {
|
const getDashboardStatistics = (what) => {
|
||||||
return cy.get(`[data-cy="dashboard.stats.${what}"]`);
|
return cy.get(`[data-cy="dashboard.stats.${what}"]`);
|
||||||
|
|
@ -7,12 +9,14 @@ const getDashboardStatistics = (what) => {
|
||||||
const clickOnDetailsLink = (within) => {
|
const clickOnDetailsLink = (within) => {
|
||||||
cy.get(`[data-cy="dashboard.stats.${within}"]`).within(() => {
|
cy.get(`[data-cy="dashboard.stats.${within}"]`).within(() => {
|
||||||
cy.get('[data-cy="basebox.detailsLink"]').click();
|
cy.get('[data-cy="basebox.detailsLink"]').click();
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("dashboardSupervisor.cy.js", () => {
|
describe("dashboardSupervisor.cy.js", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.manageCommand("cypress_reset --create-assignment-evaluation --create-feedback-responses --create-course-completion-performance-criteria --create-attendance-days");
|
cy.manageCommand(
|
||||||
|
"cypress_reset --create-assignment-evaluation --create-feedback-responses --create-course-completion-performance-criteria --create-attendance-days"
|
||||||
|
);
|
||||||
login("test-supervisor1@example.com", "test");
|
login("test-supervisor1@example.com", "test");
|
||||||
cy.visit("/");
|
cy.visit("/");
|
||||||
});
|
});
|
||||||
|
|
@ -21,8 +25,8 @@ describe("dashboardSupervisor.cy.js", () => {
|
||||||
it("contains correct numbers", () => {
|
it("contains correct numbers", () => {
|
||||||
// we have no completed assignments, but some are in progress
|
// we have no completed assignments, but some are in progress
|
||||||
// -> makes sure that the numbers are correct
|
// -> makes sure that the numbers are correct
|
||||||
getDashboardStatistics("assignments.completed").should("have.text", "0");
|
getDashboardStatistics("assignments.completed").should("have.text", "1");
|
||||||
getDashboardStatistics("assignments.passed").should("have.text", "0%");
|
getDashboardStatistics("assignments.passed").should("have.text", "34%");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("contains correct details link", () => {
|
it("contains correct details link", () => {
|
||||||
|
|
@ -31,15 +35,21 @@ describe("dashboardSupervisor.cy.js", () => {
|
||||||
// might be improved: roughly check
|
// might be improved: roughly check
|
||||||
// that the correct data is displayed
|
// that the correct data is displayed
|
||||||
cy.contains("Noch nicht bestätigt");
|
cy.contains("Noch nicht bestätigt");
|
||||||
cy.contains("Fahrzeug - Mein erstes Auto");
|
cy.contains("Überprüfen einer Motorfahrzeugs-Versicherungspolice");
|
||||||
cy.contains("Test Bern 2022 a");
|
cy.contains("Test Bern 2022 a");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("attendance day summary box", () => {
|
describe("attendance day summary box", () => {
|
||||||
it("contains correct numbers", () => {
|
it("contains correct numbers", () => {
|
||||||
getDashboardStatistics("attendance.dayCompleted").should("have.text", "1");
|
getDashboardStatistics("attendance.dayCompleted").should(
|
||||||
getDashboardStatistics("attendance.participantsPresent").should("have.text", "34%");
|
"have.text",
|
||||||
|
"1"
|
||||||
|
);
|
||||||
|
getDashboardStatistics("attendance.participantsPresent").should(
|
||||||
|
"have.text",
|
||||||
|
"34%"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it("contains correct details link", () => {
|
it("contains correct details link", () => {
|
||||||
clickOnDetailsLink("attendance");
|
clickOnDetailsLink("attendance");
|
||||||
|
|
@ -53,7 +63,6 @@ describe("dashboardSupervisor.cy.js", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe("overall summary box", () => {
|
describe("overall summary box", () => {
|
||||||
it("contains correct numbers (members, experts etc.)", () => {
|
it("contains correct numbers (members, experts etc.)", () => {
|
||||||
getDashboardStatistics("participant.count").should("have.text", "4");
|
getDashboardStatistics("participant.count").should("have.text", "4");
|
||||||
|
|
@ -66,7 +75,6 @@ describe("dashboardSupervisor.cy.js", () => {
|
||||||
it("contains correct numbers", () => {
|
it("contains correct numbers", () => {
|
||||||
getDashboardStatistics("feedback.average").should("have.text", "3.3");
|
getDashboardStatistics("feedback.average").should("have.text", "3.3");
|
||||||
getDashboardStatistics("feedback.count").should("have.text", "3");
|
getDashboardStatistics("feedback.count").should("have.text", "3");
|
||||||
|
|
||||||
});
|
});
|
||||||
it("contains correct details link", () => {
|
it("contains correct details link", () => {
|
||||||
clickOnDetailsLink("feedback");
|
clickOnDetailsLink("feedback");
|
||||||
|
|
@ -76,8 +84,8 @@ describe("dashboardSupervisor.cy.js", () => {
|
||||||
// that the correct data is displayed
|
// that the correct data is displayed
|
||||||
cy.contains("3.3 von 4");
|
cy.contains("3.3 von 4");
|
||||||
cy.contains("Test Trainer1");
|
cy.contains("Test Trainer1");
|
||||||
cy.contains("Durchführung «Test Bern 2022 a»")
|
cy.contains("Durchführung «Test Bern 2022 a»");
|
||||||
cy.contains("Circle «Fahrzeug»")
|
cy.contains("Circle «Fahrzeug»");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -94,8 +102,7 @@ describe("dashboardSupervisor.cy.js", () => {
|
||||||
// that the correct data is displayed
|
// that the correct data is displayed
|
||||||
cy.contains("Selbsteinschätzung: Vorbereitung");
|
cy.contains("Selbsteinschätzung: Vorbereitung");
|
||||||
cy.contains("Durchführung «Test Bern 2022 a»");
|
cy.contains("Durchführung «Test Bern 2022 a»");
|
||||||
cy.contains("Circle «Fahrzeug»")
|
cy.contains("Circle «Fahrzeug»");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ def request_assignment_completion_status(request, assignment_id, course_session_
|
||||||
"assignment_user_id",
|
"assignment_user_id",
|
||||||
"completion_status",
|
"completion_status",
|
||||||
"evaluation_points",
|
"evaluation_points",
|
||||||
|
"evaluation_max_points",
|
||||||
"evaluation_passed",
|
"evaluation_passed",
|
||||||
"learning_content_page_id",
|
"learning_content_page_id",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,12 @@ from vbv_lernwelt.assignment.tests.assignment_factories import (
|
||||||
from vbv_lernwelt.competence.factories import (
|
from vbv_lernwelt.competence.factories import (
|
||||||
ActionCompetenceFactory,
|
ActionCompetenceFactory,
|
||||||
ActionCompetenceListPageFactory,
|
ActionCompetenceListPageFactory,
|
||||||
|
CompetenceCertificateFactory,
|
||||||
|
CompetenceCertificateListFactory,
|
||||||
CompetenceNaviPageFactory,
|
CompetenceNaviPageFactory,
|
||||||
PerformanceCriteriaFactory,
|
PerformanceCriteriaFactory,
|
||||||
)
|
)
|
||||||
from vbv_lernwelt.competence.models import PerformanceCriteria
|
from vbv_lernwelt.competence.models import CompetenceCertificate, PerformanceCriteria
|
||||||
from vbv_lernwelt.core.models import User
|
from vbv_lernwelt.core.models import User
|
||||||
from vbv_lernwelt.course.factories import CoursePageFactory
|
from vbv_lernwelt.course.factories import CoursePageFactory
|
||||||
from vbv_lernwelt.course.models import (
|
from vbv_lernwelt.course.models import (
|
||||||
|
|
@ -160,6 +162,12 @@ def create_attendance_course(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_competence_certificate(course: Course) -> CompetenceCertificate:
|
||||||
|
navi = CompetenceNaviPageFactory(parent=course.coursepage)
|
||||||
|
certificate_list = CompetenceCertificateListFactory(parent=navi)
|
||||||
|
return CompetenceCertificateFactory(parent=certificate_list)
|
||||||
|
|
||||||
|
|
||||||
def create_assignment(
|
def create_assignment(
|
||||||
course: Course,
|
course: Course,
|
||||||
assignment_type: AssignmentType,
|
assignment_type: AssignmentType,
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ class CourseSessionEdoniqTest(models.Model):
|
||||||
self.deadline.url = self.learning_content.get_frontend_url(
|
self.deadline.url = self.learning_content.get_frontend_url(
|
||||||
course_session_id=self.course_session.id
|
course_session_id=self.course_session.id
|
||||||
)
|
)
|
||||||
self.deadline.url_expert = f"/course/{self.course_session.course.slug}/cockpit?courseSessionId={self.course_session.id}"
|
self.deadline.url_expert = f"/course/{self.course_session.course.slug}/cockpit/assignment/{self.learning_content_id}?courseSessionId={self.course_session.id}"
|
||||||
self.deadline.title = self.learning_content.title
|
self.deadline.title = self.learning_content.title
|
||||||
self.deadline.page = self.learning_content.page_ptr
|
self.deadline.page = self.learning_content.page_ptr
|
||||||
self.deadline.assignment_type_translation_key = (
|
self.deadline.assignment_type_translation_key = (
|
||||||
|
|
|
||||||
|
|
@ -100,11 +100,11 @@ def get_assignment_completion_metrics(
|
||||||
average_passed = math.ceil(passed_count / participants_count * 100)
|
average_passed = math.ceil(passed_count / participants_count * 100)
|
||||||
|
|
||||||
return AssignmentCompletionMetricsType(
|
return AssignmentCompletionMetricsType(
|
||||||
_id=assignment.id, # noqa
|
_id=f"{course_session.id}-{assignment.id}", # noqa
|
||||||
passed_count=passed_count, # noqa
|
passed_count=passed_count, # noqa
|
||||||
failed_count=failed_count, # noqa
|
failed_count=failed_count, # noqa
|
||||||
unranked_count=unranked_count, # noqa
|
unranked_count=unranked_count, # noqa
|
||||||
ranking_completed=unranked_count == 0, # noqa
|
ranking_completed=(passed_count > 0 or failed_count > 0), # noqa
|
||||||
average_passed=average_passed, # noqa
|
average_passed=average_passed, # noqa
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -121,12 +121,14 @@ def create_record(
|
||||||
|
|
||||||
return AssignmentStatisticsRecordType(
|
return AssignmentStatisticsRecordType(
|
||||||
# make sure it's unique, across all types of assignments!
|
# make sure it's unique, across all types of assignments!
|
||||||
_id=f"{course_session_assignment._meta.model_name}#{course_session_assignment.id}", # noqa
|
_id=f"{course_session_assignment._meta.model_name}#{course_session_assignment.id}",
|
||||||
|
# noqa
|
||||||
course_session_id=str(course_session_assignment.course_session.id), # noqa
|
course_session_id=str(course_session_assignment.course_session.id), # noqa
|
||||||
circle_id=learning_content.get_circle().id, # noqa
|
circle_id=learning_content.get_circle().id, # noqa
|
||||||
course_session_assignment_id=str(course_session_assignment.id), # noqa
|
course_session_assignment_id=str(course_session_assignment.id), # noqa
|
||||||
generation=course_session_assignment.course_session.generation, # noqa
|
generation=course_session_assignment.course_session.generation, # noqa
|
||||||
assignment_type_translation_key=due_date.assignment_type_translation_key, # noqa
|
assignment_type_translation_key=due_date.assignment_type_translation_key,
|
||||||
|
# noqa
|
||||||
assignment_title=learning_content.content_assignment.title, # noqa
|
assignment_title=learning_content.content_assignment.title, # noqa
|
||||||
metrics=get_assignment_completion_metrics( # noqa
|
metrics=get_assignment_completion_metrics( # noqa
|
||||||
course_session=course_session_assignment.course_session, # noqa
|
course_session=course_session_assignment.course_session, # noqa
|
||||||
|
|
@ -149,16 +151,17 @@ def assignments(
|
||||||
for course_session in course_sessions:
|
for course_session in course_sessions:
|
||||||
for csa in CourseSessionAssignment.objects.filter(
|
for csa in CourseSessionAssignment.objects.filter(
|
||||||
course_session=course_session,
|
course_session=course_session,
|
||||||
learning_content__assignment_type__in=[
|
learning_content__content_assignment__assignment_type__in=[
|
||||||
AssignmentType.CASEWORK.value,
|
AssignmentType.CASEWORK.value,
|
||||||
AssignmentType.PREP_ASSIGNMENT.value,
|
|
||||||
],
|
],
|
||||||
|
learning_content__content_assignment__competence_certificate__isnull=False,
|
||||||
):
|
):
|
||||||
record = create_record(course_session_assignment=csa)
|
record = create_record(course_session_assignment=csa)
|
||||||
records.append(record)
|
records.append(record)
|
||||||
|
|
||||||
for cset in CourseSessionEdoniqTest.objects.filter(
|
for cset in CourseSessionEdoniqTest.objects.filter(
|
||||||
course_session=course_session
|
course_session=course_session,
|
||||||
|
learning_content__content_assignment__competence_certificate__isnull=False,
|
||||||
):
|
):
|
||||||
record = create_record(course_session_assignment=cset)
|
record = create_record(course_session_assignment=cset)
|
||||||
records.append(record)
|
records.append(record)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ from vbv_lernwelt.course.creators.test_utils import (
|
||||||
create_assignment_completion,
|
create_assignment_completion,
|
||||||
create_assignment_learning_content,
|
create_assignment_learning_content,
|
||||||
create_circle,
|
create_circle,
|
||||||
|
create_competence_certificate,
|
||||||
create_course,
|
create_course,
|
||||||
create_course_session,
|
create_course_session,
|
||||||
create_course_session_assignment,
|
create_course_session_assignment,
|
||||||
|
|
@ -101,11 +102,6 @@ class AssignmentTestCase(GraphQLTestCase):
|
||||||
assignment_type=AssignmentType.CASEWORK
|
assignment_type=AssignmentType.CASEWORK
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_dashboard_contains_prep_assignments(self):
|
|
||||||
self._test_assignment_type_dashboard_details(
|
|
||||||
assignment_type=AssignmentType.PREP_ASSIGNMENT
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_dashboard_contains_edoniq_tests(self):
|
def test_dashboard_contains_edoniq_tests(self):
|
||||||
self._test_assignment_type_dashboard_details(
|
self._test_assignment_type_dashboard_details(
|
||||||
assignment_type=AssignmentType.EDONIQ_TEST
|
assignment_type=AssignmentType.EDONIQ_TEST
|
||||||
|
|
@ -120,7 +116,6 @@ class AssignmentTestCase(GraphQLTestCase):
|
||||||
|
|
||||||
irrelevant_types_for_dashboard = set(AssignmentType) - {
|
irrelevant_types_for_dashboard = set(AssignmentType) - {
|
||||||
AssignmentType.CASEWORK,
|
AssignmentType.CASEWORK,
|
||||||
AssignmentType.PREP_ASSIGNMENT,
|
|
||||||
AssignmentType.EDONIQ_TEST,
|
AssignmentType.EDONIQ_TEST,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,6 +129,7 @@ class AssignmentTestCase(GraphQLTestCase):
|
||||||
deadline_at=datetime(2000, 4, 1),
|
deadline_at=datetime(2000, 4, 1),
|
||||||
course_session=self.course_session,
|
course_session=self.course_session,
|
||||||
circle=self.circle,
|
circle=self.circle,
|
||||||
|
add_competence_certificate=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
create_assignment_completion(
|
create_assignment_completion(
|
||||||
|
|
@ -203,6 +199,7 @@ class AssignmentTestCase(GraphQLTestCase):
|
||||||
assignment_type=AssignmentType.CASEWORK,
|
assignment_type=AssignmentType.CASEWORK,
|
||||||
course_session=self.course_session,
|
course_session=self.course_session,
|
||||||
circle=self.circle,
|
circle=self.circle,
|
||||||
|
add_competence_certificate=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
assignment_2, _ = mix_assignment_cocktail(
|
assignment_2, _ = mix_assignment_cocktail(
|
||||||
|
|
@ -210,13 +207,15 @@ class AssignmentTestCase(GraphQLTestCase):
|
||||||
assignment_type=AssignmentType.EDONIQ_TEST,
|
assignment_type=AssignmentType.EDONIQ_TEST,
|
||||||
course_session=self.course_session,
|
course_session=self.course_session,
|
||||||
circle=self.circle,
|
circle=self.circle,
|
||||||
|
add_competence_certificate=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
assignment_3, _ = mix_assignment_cocktail(
|
assignment_3, _ = mix_assignment_cocktail(
|
||||||
deadline_at=datetime(2010, 4, 1),
|
deadline_at=datetime(2010, 4, 1),
|
||||||
assignment_type=AssignmentType.PREP_ASSIGNMENT,
|
assignment_type=AssignmentType.CASEWORK,
|
||||||
course_session=self.course_session,
|
course_session=self.course_session,
|
||||||
circle=self.circle,
|
circle=self.circle,
|
||||||
|
add_competence_certificate=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# no completions for this assignment yet
|
# no completions for this assignment yet
|
||||||
|
|
@ -225,6 +224,7 @@ class AssignmentTestCase(GraphQLTestCase):
|
||||||
assignment_type=AssignmentType.EDONIQ_TEST,
|
assignment_type=AssignmentType.EDONIQ_TEST,
|
||||||
course_session=self.course_session,
|
course_session=self.course_session,
|
||||||
circle=self.circle,
|
circle=self.circle,
|
||||||
|
add_competence_certificate=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# assignment 1
|
# assignment 1
|
||||||
|
|
@ -284,21 +284,21 @@ class AssignmentTestCase(GraphQLTestCase):
|
||||||
|
|
||||||
# 1 -> incomplete (not counted for average)
|
# 1 -> incomplete (not counted for average)
|
||||||
# 2 -> complete 66% passed ...
|
# 2 -> complete 66% passed ...
|
||||||
# 3 -> complete 100% passed --> 83.5%
|
# 3 -> complete 100% passed --> 67%
|
||||||
# 4 -> incomplete (not counted for average)
|
# 4 -> not included in certificate
|
||||||
summary = dashboard["assignments"]["summary"]
|
summary = dashboard["assignments"]["summary"]
|
||||||
self.assertEqual(summary["completed_count"], 2)
|
self.assertEqual(summary["completed_count"], 3)
|
||||||
self.assertEqual(summary["average_passed"], 83.5)
|
self.assertEqual(summary["average_passed"], 67.0)
|
||||||
|
|
||||||
records = dashboard["assignments"]["records"]
|
records = dashboard["assignments"]["records"]
|
||||||
self.assertEqual(len(records), 4)
|
self.assertEqual(len(records), 3)
|
||||||
|
|
||||||
# 1 -> assigment_1_results (oldest)
|
# 1 -> assigment_1_results (oldest)
|
||||||
assignment_1_metrics = records[0]["metrics"]
|
assignment_1_metrics = records[0]["metrics"]
|
||||||
self.assertEqual(assignment_1_metrics["passed_count"], 1)
|
self.assertEqual(assignment_1_metrics["passed_count"], 1)
|
||||||
self.assertEqual(assignment_1_metrics["failed_count"], 1)
|
self.assertEqual(assignment_1_metrics["failed_count"], 1)
|
||||||
self.assertEqual(assignment_1_metrics["unranked_count"], 1)
|
self.assertEqual(assignment_1_metrics["unranked_count"], 1)
|
||||||
self.assertEqual(assignment_1_metrics["ranking_completed"], False)
|
self.assertEqual(assignment_1_metrics["ranking_completed"], True)
|
||||||
self.assertEqual(assignment_1_metrics["average_passed"], 34)
|
self.assertEqual(assignment_1_metrics["average_passed"], 34)
|
||||||
|
|
||||||
# 2 -> assignment_2_results
|
# 2 -> assignment_2_results
|
||||||
|
|
@ -317,19 +317,12 @@ class AssignmentTestCase(GraphQLTestCase):
|
||||||
self.assertEqual(assignment_3_metrics["ranking_completed"], True)
|
self.assertEqual(assignment_3_metrics["ranking_completed"], True)
|
||||||
self.assertEqual(assignment_3_metrics["average_passed"], 100)
|
self.assertEqual(assignment_3_metrics["average_passed"], 100)
|
||||||
|
|
||||||
# 4 -> no completions (newest)
|
|
||||||
assignment_4_metrics = records[3]["metrics"]
|
|
||||||
self.assertEqual(assignment_4_metrics["passed_count"], 0)
|
|
||||||
self.assertEqual(assignment_4_metrics["failed_count"], 0)
|
|
||||||
self.assertEqual(assignment_4_metrics["unranked_count"], 3)
|
|
||||||
self.assertEqual(assignment_4_metrics["ranking_completed"], False)
|
|
||||||
self.assertEqual(assignment_4_metrics["average_passed"], 0)
|
|
||||||
|
|
||||||
|
|
||||||
def mix_assignment_cocktail(
|
def mix_assignment_cocktail(
|
||||||
assignment_type: AssignmentType,
|
assignment_type: AssignmentType,
|
||||||
course_session: CourseSession,
|
course_session: CourseSession,
|
||||||
circle: Circle,
|
circle: Circle,
|
||||||
|
add_competence_certificate: bool = False,
|
||||||
deadline_at: datetime | None = None,
|
deadline_at: datetime | None = None,
|
||||||
) -> Tuple[Assignment, CourseSessionAssignment | CourseSessionEdoniqTest]:
|
) -> Tuple[Assignment, CourseSessionAssignment | CourseSessionEdoniqTest]:
|
||||||
"""
|
"""
|
||||||
|
|
@ -338,9 +331,15 @@ def mix_assignment_cocktail(
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assignment = create_assignment(
|
assignment = create_assignment(
|
||||||
course=course_session.course, assignment_type=assignment_type
|
course=course_session.course,
|
||||||
|
assignment_type=assignment_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if add_competence_certificate:
|
||||||
|
certificate = create_competence_certificate(course=course_session.course)
|
||||||
|
assignment.competence_certificate = certificate
|
||||||
|
assignment.save()
|
||||||
|
|
||||||
if assignment_type == AssignmentType.EDONIQ_TEST:
|
if assignment_type == AssignmentType.EDONIQ_TEST:
|
||||||
cset = create_course_session_edoniq_test(
|
cset = create_course_session_edoniq_test(
|
||||||
deadline_at=deadline_at,
|
deadline_at=deadline_at,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Generated by Django 3.2.20 on 2023-11-08 06:47
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def set_url_expert_course_session_edoniq_test(apps, schema_editor):
|
||||||
|
# need to load concrete model, so that wagtail page has `specific` instance method...
|
||||||
|
from vbv_lernwelt.course_session.models import CourseSessionEdoniqTest
|
||||||
|
|
||||||
|
for edoniq_test in CourseSessionEdoniqTest.objects.all():
|
||||||
|
# trigger save to update due_date foreign key fields
|
||||||
|
edoniq_test.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("duedate", "0007_auto_20231010_1505"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
set_url_expert_course_session_edoniq_test, migrations.RunPython.noop
|
||||||
|
),
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue