Add dashboard persons code for Berufsbildner
This commit is contained in:
parent
4b2fcc09ec
commit
61ee85668e
|
|
@ -16,6 +16,7 @@ const props = defineProps<{
|
|||
courseSession: CourseSession;
|
||||
learningContent: LearningContentAssignment | LearningContentEdoniqTest;
|
||||
showTitle: boolean;
|
||||
userSelectionIds?: string[];
|
||||
}>();
|
||||
|
||||
log.debug("AssignmentSubmissionProgress created", stringifyParse(props));
|
||||
|
|
@ -35,7 +36,8 @@ onMounted(async () => {
|
|||
await loadAssignmentCompletionStatusData(
|
||||
props.learningContent.content_assignment.id,
|
||||
props.courseSession.id,
|
||||
props.learningContent.id
|
||||
props.learningContent.id,
|
||||
props.userSelectionIds
|
||||
);
|
||||
|
||||
state.submissionProgressStatusCount = {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ const props = defineProps<{
|
|||
assignmentsCompleted: number;
|
||||
avgPassed: number;
|
||||
courseSlug: string;
|
||||
detailsLink?: string;
|
||||
}>();
|
||||
|
||||
const progress = computed(() => {
|
||||
|
|
@ -20,7 +21,7 @@ const progress = computed(() => {
|
|||
|
||||
<template>
|
||||
<BaseBox
|
||||
:details-link="`/statistic/${courseSlug}/assignment`"
|
||||
:details-link="props.detailsLink || `/statistic/${courseSlug}/assignment`"
|
||||
data-cy="dashboard.stats.assignments"
|
||||
>
|
||||
<template #title>{{ $t("a.Kompetenznachweis-Elemente") }}</template>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, onMounted, type Ref, ref } from "vue";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import {
|
||||
type DashboardRoleKeyType,
|
||||
fetchMentorCompetenceSummary,
|
||||
} from "@/services/dashboard";
|
||||
import type { AssignmentsStatisticsType, BaseStatisticsType } from "@/gql/graphql";
|
||||
import type { BaseStatisticsType } from "@/gql/graphql";
|
||||
import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
|
||||
import AssignmentSummaryBox from "@/components/dashboard/AssignmentSummaryBox.vue";
|
||||
|
||||
|
|
@ -43,6 +43,7 @@ onMounted(async () => {
|
|||
:assignments-completed="assignmentStats.summary.completed_count"
|
||||
:avg-passed="assignmentStats.summary.average_passed"
|
||||
:course-slug="props.courseSlug"
|
||||
:details-link="`/statistic/berufsbildner/${props.courseSlug}/assignment`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export function useCourseSessionDetailQuery(courSessionId?: string) {
|
|||
|
||||
function filterMembers(userSelectionIds: string[] | null = null) {
|
||||
return (courseSessionDetail.value?.users ?? []).filter((u) => {
|
||||
if (userSelectionIds) {
|
||||
if (userSelectionIds && userSelectionIds.length > 0) {
|
||||
return userSelectionIds.includes(u.user_id) && u.role === "MEMBER";
|
||||
}
|
||||
return u.role === "MEMBER";
|
||||
|
|
@ -495,7 +495,7 @@ export function getVvRoleDisplay(role: DashboardPersonRoleType) {
|
|||
switch (role) {
|
||||
case "LEARNING_MENTOR":
|
||||
return t("a.Lernbegleitung");
|
||||
case "LEARNING_MENTEE":
|
||||
case "PARTICIPANT":
|
||||
return t("a.Teilnehmer");
|
||||
case "EXPERT":
|
||||
return t("a.Experte");
|
||||
|
|
@ -512,7 +512,7 @@ export function getUkRoleDisplay(role: DashboardPersonRoleType) {
|
|||
switch (role) {
|
||||
case "LEARNING_MENTOR":
|
||||
return t("a.Praxisbildner");
|
||||
case "LEARNING_MENTEE":
|
||||
case "PARTICIPANT":
|
||||
return t("a.Teilnehmer");
|
||||
case "EXPERT":
|
||||
return t("a.Trainer");
|
||||
|
|
@ -579,7 +579,7 @@ export function useDashboardPersonsDueDates(
|
|||
return refDate >= dayjs().startOf("day");
|
||||
});
|
||||
|
||||
// attach `LEARNING_MENTEE` to due dates for `LEARNING_MENTOR` persons
|
||||
// attach `PARTICIPANT` to due dates for `LEARNING_MENTOR` persons
|
||||
currentDueDates.value.forEach((dueDate) => {
|
||||
if (dueDate.course_session.my_role === "LEARNING_MENTOR") {
|
||||
dueDate.persons = dashboardPersons.value.filter((person) => {
|
||||
|
|
@ -589,7 +589,7 @@ export function useDashboardPersonsDueDates(
|
|||
.includes(dueDate.course_session.id)
|
||||
) {
|
||||
return person.course_sessions.some(
|
||||
(cs) => cs.user_role === "LEARNING_MENTEE"
|
||||
(cs) => cs.user_role === "PARTICIPANT"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const documents = {
|
|||
"\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 dashboardCourseData($courseId: ID!) {\n course_progress(course_id: $courseId) {\n _id\n course_id\n session_to_continue_id\n }\n }\n": types.DashboardCourseDataDocument,
|
||||
"\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 total_passed\n total_failed\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 competence_certificate_title\n competence_certificate_id\n details_url\n deadline\n metrics {\n _id\n passed_count\n failed_count\n unranked_count\n ranking_completed\n average_evaluation_percent\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 mentorCourseStatistics($courseId: ID!, $agentRole: String!) {\n mentor_course_statistics(course_id: $courseId, agent_role: $agentRole) {\n _id\n course_id\n course_title\n course_slug\n course_session_selection_ids\n user_selection_ids\n course_session_properties {\n _id\n sessions {\n id\n name\n }\n generations\n circles {\n id\n name\n }\n }\n assignments {\n _id\n summary {\n _id\n completed_count\n average_passed\n total_passed\n total_failed\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 competence_certificate_id\n competence_certificate_title\n details_url\n deadline\n metrics {\n _id\n passed_count\n failed_count\n unranked_count\n ranking_completed\n average_evaluation_percent\n average_passed\n }\n }\n }\n }\n }\n": types.MentorCourseStatisticsDocument,
|
||||
"\n query mentorCourseStatistics($courseId: ID!, $agentRole: String!) {\n mentor_course_statistics(course_id: $courseId, agent_role: $agentRole) {\n _id\n course_id\n course_title\n course_slug\n course_session_selection_ids\n user_selection_ids\n course_session_properties {\n _id\n sessions {\n id\n name\n }\n generations\n circles {\n id\n name\n }\n }\n assignments {\n _id\n summary {\n _id\n completed_count\n average_passed\n total_passed\n total_failed\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 competence_certificate_id\n competence_certificate_title\n details_url\n learning_content_id\n deadline\n metrics {\n _id\n passed_count\n failed_count\n unranked_count\n ranking_completed\n average_evaluation_percent\n average_passed\n }\n }\n }\n }\n }\n": types.MentorCourseStatisticsDocument,
|
||||
"\n mutation SendFeedbackMutation(\n $courseSessionId: ID!\n $learningContentId: ID!\n $learningContentType: String!\n $data: GenericScalar!\n $submitted: Boolean\n ) {\n send_feedback(\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n learning_content_type: $learningContentType\n data: $data\n submitted: $submitted\n ) {\n feedback_response {\n id\n data\n submitted\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument,
|
||||
};
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ export function graphql(source: "\n query courseStatistics($courseId: ID!) {\n
|
|||
/**
|
||||
* 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 mentorCourseStatistics($courseId: ID!, $agentRole: String!) {\n mentor_course_statistics(course_id: $courseId, agent_role: $agentRole) {\n _id\n course_id\n course_title\n course_slug\n course_session_selection_ids\n user_selection_ids\n course_session_properties {\n _id\n sessions {\n id\n name\n }\n generations\n circles {\n id\n name\n }\n }\n assignments {\n _id\n summary {\n _id\n completed_count\n average_passed\n total_passed\n total_failed\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 competence_certificate_id\n competence_certificate_title\n details_url\n deadline\n metrics {\n _id\n passed_count\n failed_count\n unranked_count\n ranking_completed\n average_evaluation_percent\n average_passed\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query mentorCourseStatistics($courseId: ID!, $agentRole: String!) {\n mentor_course_statistics(course_id: $courseId, agent_role: $agentRole) {\n _id\n course_id\n course_title\n course_slug\n course_session_selection_ids\n user_selection_ids\n course_session_properties {\n _id\n sessions {\n id\n name\n }\n generations\n circles {\n id\n name\n }\n }\n assignments {\n _id\n summary {\n _id\n completed_count\n average_passed\n total_passed\n total_failed\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 competence_certificate_id\n competence_certificate_title\n details_url\n deadline\n metrics {\n _id\n passed_count\n failed_count\n unranked_count\n ranking_completed\n average_evaluation_percent\n average_passed\n }\n }\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n query mentorCourseStatistics($courseId: ID!, $agentRole: String!) {\n mentor_course_statistics(course_id: $courseId, agent_role: $agentRole) {\n _id\n course_id\n course_title\n course_slug\n course_session_selection_ids\n user_selection_ids\n course_session_properties {\n _id\n sessions {\n id\n name\n }\n generations\n circles {\n id\n name\n }\n }\n assignments {\n _id\n summary {\n _id\n completed_count\n average_passed\n total_passed\n total_failed\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 competence_certificate_id\n competence_certificate_title\n details_url\n learning_content_id\n deadline\n metrics {\n _id\n passed_count\n failed_count\n unranked_count\n ranking_completed\n average_evaluation_percent\n average_passed\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query mentorCourseStatistics($courseId: ID!, $agentRole: String!) {\n mentor_course_statistics(course_id: $courseId, agent_role: $agentRole) {\n _id\n course_id\n course_title\n course_slug\n course_session_selection_ids\n user_selection_ids\n course_session_properties {\n _id\n sessions {\n id\n name\n }\n generations\n circles {\n id\n name\n }\n }\n assignments {\n _id\n summary {\n _id\n completed_count\n average_passed\n total_passed\n total_failed\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 competence_certificate_id\n competence_certificate_title\n details_url\n learning_content_id\n deadline\n metrics {\n _id\n passed_count\n failed_count\n unranked_count\n ranking_completed\n average_evaluation_percent\n average_passed\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.
|
||||
*/
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -59,6 +59,7 @@ type AssignmentStatisticsRecordType {
|
|||
competence_certificate_id: ID
|
||||
competence_certificate_title: String
|
||||
metrics: AssignmentCompletionMetricsType!
|
||||
learning_content_id: ID!
|
||||
details_url: String!
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -547,6 +547,7 @@ export const DASHBOARD_MENTOR_COMPETENCE_SUMMARY = graphql(`
|
|||
competence_certificate_id
|
||||
competence_certificate_title
|
||||
details_url
|
||||
learning_content_id
|
||||
deadline
|
||||
metrics {
|
||||
_id
|
||||
|
|
|
|||
|
|
@ -19,10 +19,13 @@ import { useTranslation } from "i18next-vue";
|
|||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const props = defineProps<{
|
||||
export interface Props {
|
||||
courseSession: CourseSession;
|
||||
learningContent: LearningContentAssignment | LearningContentEdoniqTest;
|
||||
}>();
|
||||
userSelectionIds?: string[];
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
log.debug("AssignmentDetails created", stringifyParse(props));
|
||||
|
||||
|
|
@ -45,11 +48,13 @@ const isPraxisAssignment = computed(() => {
|
|||
});
|
||||
|
||||
onMounted(async () => {
|
||||
log.debug("AssignmentDetails mounted", props.learningContent, props.userSelectionIds);
|
||||
const { gradedUsers, assignmentSubmittedUsers } =
|
||||
await loadAssignmentCompletionStatusData(
|
||||
props.learningContent.content_assignment.id,
|
||||
props.courseSession.id,
|
||||
props.learningContent.id
|
||||
props.learningContent.id,
|
||||
props.userSelectionIds ?? []
|
||||
);
|
||||
state.gradedUsers = gradedUsers;
|
||||
state.assignmentSubmittedUsers = assignmentSubmittedUsers;
|
||||
|
|
@ -111,13 +116,14 @@ function findUserPointsHtml(userId: string) {
|
|||
:course-session="courseSession"
|
||||
:learning-content="learningContent"
|
||||
:show-title="false"
|
||||
:user-selection-ids="props.userSelectionIds"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="courseSessionDetailResult.filterMembers().length" class="mt-6">
|
||||
<ul>
|
||||
<ItPersonRow
|
||||
v-for="csu in courseSessionDetailResult.filterMembers()"
|
||||
v-for="csu in courseSessionDetailResult.filterMembers(props.userSelectionIds)"
|
||||
:key="csu.user_id"
|
||||
:name="`${csu.first_name} ${csu.last_name}`"
|
||||
:avatar-url="csu.avatar_url"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import * as log from "loglevel";
|
|||
import { computed, onMounted } from "vue";
|
||||
import type { LearningContentAssignment, LearningContentEdoniqTest } from "@/types";
|
||||
import { useExpertCockpitPageData } from "@/pages/cockpit/cockpitPage/composables";
|
||||
import { getPreviousRoute } from "@/router/history";
|
||||
|
||||
const props = defineProps<{
|
||||
courseSlug: string;
|
||||
|
|
@ -25,16 +26,22 @@ const lpQueryResult = useCourseData(props.courseSlug);
|
|||
const learningContentAssignment = computed(() => {
|
||||
return lpQueryResult.findLearningContent(props.assignmentId);
|
||||
});
|
||||
|
||||
const previousRoute = getPreviousRoute();
|
||||
|
||||
const backRoute = computed(() => {
|
||||
if (previousRoute?.path.endsWith("/assignment")) {
|
||||
return previousRoute;
|
||||
}
|
||||
return `/course/${props.courseSlug}/cockpit`;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!loading" class="bg-gray-200">
|
||||
<div class="container-large">
|
||||
<nav class="py-4 pb-4">
|
||||
<router-link
|
||||
class="btn-text inline-flex items-center pl-0"
|
||||
:to="`/course/${props.courseSlug}/cockpit`"
|
||||
>
|
||||
<router-link class="btn-text inline-flex items-center pl-0" :to="backRoute">
|
||||
<it-icon-arrow-left />
|
||||
<span>{{ $t("general.back") }}</span>
|
||||
</router-link>
|
||||
|
|
|
|||
|
|
@ -365,7 +365,7 @@ watch(selectedRegion, () => {
|
|||
(['SUPERVISOR', 'EXPERT'].includes(cs.my_role) &&
|
||||
cs.user_role === 'MEMBER') ||
|
||||
(cs.my_role === 'LEARNING_MENTOR' &&
|
||||
cs.user_role === 'LEARNING_MENTEE')
|
||||
cs.user_role === 'PARTICIPANT')
|
||||
"
|
||||
>
|
||||
<router-link
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<script setup lang="ts">
|
||||
import { useCourseData, useCurrentCourseSession } from "@/composables";
|
||||
import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue";
|
||||
import * as log from "loglevel";
|
||||
import { computed } from "vue";
|
||||
import type { LearningContentAssignment, LearningContentEdoniqTest } from "@/types";
|
||||
import { useExpertCockpitPageData } from "@/pages/cockpit/cockpitPage/composables";
|
||||
import { getPreviousRoute } from "@/router/history";
|
||||
|
||||
const props = defineProps<{
|
||||
courseSlug: string;
|
||||
assignmentId: string;
|
||||
agentRole: string;
|
||||
participantUserIds: string[];
|
||||
}>();
|
||||
|
||||
log.debug("AgentAssignmentDetail created", props.courseSlug, props.agentRole);
|
||||
|
||||
const courseSession = useCurrentCourseSession();
|
||||
const { loading } = useExpertCockpitPageData(
|
||||
props.courseSlug,
|
||||
props.participantUserIds
|
||||
);
|
||||
|
||||
const lpQueryResult = useCourseData(props.courseSlug);
|
||||
|
||||
const learningContentAssignment = computed(() => {
|
||||
return lpQueryResult.findLearningContent(props.assignmentId);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!loading" class="bg-gray-200">
|
||||
<div class="container-large">
|
||||
<nav class="py-4 pb-4">
|
||||
<router-link
|
||||
class="btn-text inline-flex items-center pl-0"
|
||||
:to="`/statistic/${props.agentRole}/${props.courseSlug}/assignment`"
|
||||
>
|
||||
<it-icon-arrow-left />
|
||||
<span>{{ $t("general.back") }}</span>
|
||||
</router-link>
|
||||
</nav>
|
||||
<main>
|
||||
<div class="bg-white p-6">
|
||||
<!-- prettier-ignore -->
|
||||
<AssignmentDetails
|
||||
v-if="learningContentAssignment"
|
||||
:course-session="courseSession"
|
||||
:learning-content="learningContentAssignment as (LearningContentAssignment | LearningContentEdoniqTest)"
|
||||
:user-selection-ids="participantUserIds"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
@ -1,56 +1,45 @@
|
|||
<script setup lang="ts">
|
||||
import { useCourseData, useCurrentCourseSession } from "@/composables";
|
||||
import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
import * as log from "loglevel";
|
||||
import { computed, onMounted } from "vue";
|
||||
import type { LearningContentAssignment, LearningContentEdoniqTest } from "@/types";
|
||||
import { useExpertCockpitPageData } from "@/pages/cockpit/cockpitPage/composables";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { fetchDashboardPersons } from "@/services/dashboard";
|
||||
import AgentAssignmentDetail from "@/pages/dashboard/agentAssignment/AgentAssignmentDetail.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
courseSlug: string;
|
||||
assignmentId: string;
|
||||
agentRole: string;
|
||||
}>();
|
||||
|
||||
log.debug("AgentAssignmentDetailPage created", props.courseSlug);
|
||||
log.debug("AgentAssignmentDetailPage created", props.courseSlug, props.agentRole);
|
||||
|
||||
const courseSession = useCurrentCourseSession();
|
||||
const { loading } = useExpertCockpitPageData(props.courseSlug);
|
||||
|
||||
const loading = ref(true);
|
||||
const participantUserIds = ref<string[]>([]);
|
||||
|
||||
onMounted(async () => {
|
||||
log.debug("AgentAssignmentDetailPage mounted");
|
||||
});
|
||||
log.debug("AgentAssignmentDetailPage mounted", courseSession);
|
||||
|
||||
const lpQueryResult = useCourseData(props.courseSlug);
|
||||
|
||||
const learningContentAssignment = computed(() => {
|
||||
return lpQueryResult.findLearningContent(props.assignmentId);
|
||||
const personData = await fetchDashboardPersons("default");
|
||||
const participants = personData?.filter((p) => {
|
||||
return p.course_sessions.find(
|
||||
(cs) => cs.id === courseSession.value.id && cs.my_role === "BERUFSBILDNER"
|
||||
);
|
||||
});
|
||||
participantUserIds.value = participants?.map((p) => p.user_id);
|
||||
loading.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!loading" class="bg-gray-200">
|
||||
<div class="container-large">
|
||||
<nav class="py-4 pb-4">
|
||||
<router-link
|
||||
class="btn-text inline-flex items-center pl-0"
|
||||
:to="`/course/${props.courseSlug}/cockpit`"
|
||||
>
|
||||
<it-icon-arrow-left />
|
||||
<span>{{ $t("general.back") }}</span>
|
||||
</router-link>
|
||||
</nav>
|
||||
<main>
|
||||
<div class="bg-white p-6">
|
||||
<!-- prettier-ignore -->
|
||||
<AssignmentDetails
|
||||
v-if="learningContentAssignment"
|
||||
:course-session="courseSession"
|
||||
:learning-content="learningContentAssignment as (LearningContentAssignment | LearningContentEdoniqTest)"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<AgentAssignmentDetail
|
||||
v-if="participantUserIds.length"
|
||||
:assignment-id="props.assignmentId"
|
||||
:agent-role="props.agentRole"
|
||||
:course-slug="props.courseSlug"
|
||||
:participant-user-ids="participantUserIds"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ onMounted(async () => {
|
|||
:course-statistics="agentAssignmentData"
|
||||
:course-session-name="courseSessionName"
|
||||
:circle-meta="circleMeta"
|
||||
:detail-base-url="`/statistic/${props.agentRole}/${props.courseSlug}/assignment/`"
|
||||
></AssignmentList>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const props = defineProps<{
|
|||
courseStatistics: BaseStatisticsType;
|
||||
courseSessionName: (sessionId: string) => string;
|
||||
circleMeta: (circleId: string) => StatisticsCircleDataType;
|
||||
detailBaseUrl?: string;
|
||||
}>();
|
||||
|
||||
const statisticFilter: Ref<typeof StatisticFilterList | null> = ref(null);
|
||||
|
|
@ -51,6 +52,14 @@ async function exportData() {
|
|||
const filteredItems = statisticFilter.value.getFilteredItems();
|
||||
await exportDataAsXls(filteredItems, exportCompetenceElements, userStore.language);
|
||||
}
|
||||
|
||||
const itemDetailUrl = (item: AssignmentStatisticsRecordType) => {
|
||||
if (props.detailBaseUrl) {
|
||||
return `${props.detailBaseUrl}${item.learning_content_id}?courseSessionId=${item.course_session_id}`;
|
||||
}
|
||||
return item.details_url;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -114,8 +123,7 @@ async function exportData() {
|
|||
></ItProgress>
|
||||
<router-link
|
||||
class="underline"
|
||||
target="_blank"
|
||||
:to="(item as AssignmentStatisticsRecordType).details_url"
|
||||
:to="itemDetailUrl(item as AssignmentStatisticsRecordType)"
|
||||
>
|
||||
{{ $t("a.Details anschauen") }}
|
||||
</router-link>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useCourseSessionDetailQuery } from "@/composables";
|
||||
import { itGet } from "@/fetchHelpers";
|
||||
import { itGet, itPost } from "@/fetchHelpers";
|
||||
import type {
|
||||
Assignment,
|
||||
AssignmentCompletion,
|
||||
|
|
@ -19,12 +19,16 @@ export interface GradedUser {
|
|||
export async function loadAssignmentCompletionStatusData(
|
||||
assignmentId: string,
|
||||
courseSessionId: string,
|
||||
learningContentId: string
|
||||
learningContentId: string,
|
||||
userSelectionIds: string[] | undefined = undefined
|
||||
) {
|
||||
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||
|
||||
const assignmentCompletionData = (await itGet(
|
||||
`/api/assignment/${assignmentId}/${courseSessionId}/status/`
|
||||
const assignmentCompletionData = (await itPost(
|
||||
`/api/assignment/${assignmentId}/${courseSessionId}/status/`,
|
||||
{
|
||||
user_selection_ids: userSelectionIds ?? [],
|
||||
}
|
||||
)) as UserAssignmentCompletionStatus[];
|
||||
|
||||
const members = courseSessionDetailResult.filterMembers();
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ export type DashboardPersonRoleType =
|
|||
| "EXPERT"
|
||||
| "MEMBER"
|
||||
| "LEARNING_MENTOR"
|
||||
| "LEARNING_MENTEE";
|
||||
| "BERUFSBILDNER"
|
||||
| "PARTICIPANT";
|
||||
|
||||
export type DashboardRoleKeyType =
|
||||
| "Supervisor"
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
|
|||
):
|
||||
if not can_evaluate_assignments(
|
||||
evaluation_user=info.context.user,
|
||||
assignment_user_id=assignment_user_id,
|
||||
assignment_user_ids=[assignment_user_id],
|
||||
course_session_id=course_session_id,
|
||||
):
|
||||
raise PermissionDenied()
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ def resolve_assignment_completion(
|
|||
|
||||
if str(assignment_user_id) == str(info.context.user.id) or can_evaluate_assignments(
|
||||
evaluation_user=info.context.user,
|
||||
assignment_user_id=assignment_user_id,
|
||||
assignment_user_ids=[assignment_user_id],
|
||||
course_session_id=course_session_id,
|
||||
):
|
||||
course_id = CourseSession.objects.get(id=course_session_id).course_id
|
||||
|
|
|
|||
|
|
@ -9,14 +9,23 @@ from vbv_lernwelt.iam.permissions import can_evaluate_assignments
|
|||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
@api_view(["GET"])
|
||||
@api_view(["GET", "POST"])
|
||||
def request_assignment_completion_status(request, assignment_id, course_session_id):
|
||||
# TODO quickfix before GraphQL...
|
||||
if can_evaluate_assignments(request.user, course_session_id):
|
||||
|
||||
user_selection_ids = request.data.get("user_selection_ids", [])
|
||||
|
||||
if can_evaluate_assignments(
|
||||
request.user, course_session_id, assignment_user_ids=user_selection_ids
|
||||
):
|
||||
qs = AssignmentCompletion.objects.filter(
|
||||
course_session_id=course_session_id,
|
||||
assignment_id=assignment_id,
|
||||
).values(
|
||||
)
|
||||
if len(user_selection_ids) > 0:
|
||||
qs = qs.filter(assignment_user_id__in=user_selection_ids)
|
||||
|
||||
values = qs.values(
|
||||
"id",
|
||||
"assignment_user_id",
|
||||
"completion_status",
|
||||
|
|
@ -28,7 +37,7 @@ def request_assignment_completion_status(request, assignment_id, course_session_
|
|||
)
|
||||
|
||||
# Convert the learning_content_page_id to a string
|
||||
data = list(qs) # Evaluate the queryset
|
||||
data = list(values) # Evaluate the queryset
|
||||
for item in data:
|
||||
if item["evaluation_points"] is not None:
|
||||
# only `evaluation_points_final` is relevant for the frontend
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class AssignmentStatisticsRecordType(graphene.ObjectType):
|
|||
competence_certificate_id = graphene.ID()
|
||||
competence_certificate_title = graphene.String()
|
||||
metrics = graphene.Field(AssignmentCompletionMetricsType, required=True)
|
||||
learning_content_id = graphene.ID(required=True)
|
||||
details_url = graphene.String(required=True)
|
||||
|
||||
|
||||
|
|
@ -101,13 +102,14 @@ def get_assignment_completion_metrics(
|
|||
user_selection_ids: List[str] | None,
|
||||
urql_id_postfix: str = "",
|
||||
) -> AssignmentCompletionMetricsType:
|
||||
csu_qs = CourseSessionUser.objects.filter(
|
||||
course_session_id=course_session.id, role=CourseSessionUser.Role.MEMBER
|
||||
)
|
||||
|
||||
if user_selection_ids:
|
||||
course_session_users = user_selection_ids
|
||||
else:
|
||||
course_session_users = CourseSessionUser.objects.filter(
|
||||
course_session=course_session,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
).values_list("user", flat=True)
|
||||
csu_qs = csu_qs.filter(user_id__in=user_selection_ids)
|
||||
|
||||
course_session_users = csu_qs.values_list("user", flat=True)
|
||||
|
||||
assignment_completions = AssignmentCompletion.objects.filter(
|
||||
completion_status=AssignmentCompletionStatus.EVALUATION_SUBMITTED.value,
|
||||
|
|
@ -165,17 +167,16 @@ def create_record(
|
|||
|
||||
return AssignmentStatisticsRecordType(
|
||||
# make sure it's unique, across all types of assignments!
|
||||
_id=f"{course_session_assignment._meta.model_name}#{course_session_assignment.id}@{urql_id_postfix}",
|
||||
# noqa
|
||||
_id=f"{course_session_assignment._meta.model_name}#{course_session_assignment.id}@{urql_id_postfix}", # noqa
|
||||
course_session_id=str(course_session_assignment.course_session.id), # noqa
|
||||
circle_id=learning_content.get_circle().id, # noqa
|
||||
course_session_assignment_id=str(course_session_assignment.id), # noqa
|
||||
generation=course_session_assignment.course_session.generation, # noqa
|
||||
assignment_type_translation_key=due_date.assignment_type_translation_key,
|
||||
assignment_type_translation_key=due_date.assignment_type_translation_key, # noqa
|
||||
competence_certificate_id=str(competence_certificate.id), # noqa
|
||||
competence_certificate_title=competence_certificate.title, # noqa
|
||||
# noqa
|
||||
assignment_title=learning_content.content_assignment.title, # noqa
|
||||
learning_content_id=str(learning_content.id), # noqa
|
||||
metrics=get_assignment_completion_metrics( # noqa
|
||||
course_session=course_session_assignment.course_session, # noqa
|
||||
assignment=learning_content.content_assignment, # noqa
|
||||
|
|
|
|||
|
|
@ -200,28 +200,34 @@ def _create_person_list_with_roles(user):
|
|||
|
||||
# add persons where request.user is mentor
|
||||
for cs in course_sessions:
|
||||
|
||||
def _add_agent_relation(my_role, user_role):
|
||||
course_session_entry = _create_course_session_dict(cs, my_role, user_role)
|
||||
participant_user = relation.participant.user
|
||||
|
||||
if participant_user.id not in result_persons:
|
||||
person_data = create_user_dict(participant_user)
|
||||
person_data["course_sessions"] = [course_session_entry]
|
||||
result_persons[participant_user] = person_data
|
||||
else:
|
||||
# user is already in result_persons
|
||||
result_persons[participant_user]["course_sessions"].append(
|
||||
course_session_entry
|
||||
)
|
||||
|
||||
if "LEARNING_MENTOR" in cs.roles:
|
||||
for relation in AgentParticipantRelation.objects.filter(
|
||||
agent=user, participant__course_session_id=cs.id
|
||||
agent=user, participant__course_session_id=cs.id, role="LEARNING_MENTOR"
|
||||
):
|
||||
course_session_entry = _create_course_session_dict(
|
||||
cs,
|
||||
"LEARNING_MENTOR",
|
||||
"LEARNING_MENTEE",
|
||||
)
|
||||
participant_user = relation.participant.user
|
||||
_add_agent_relation("LEARNING_MENTOR", "PARTICIPANT")
|
||||
|
||||
if participant_user.id not in result_persons:
|
||||
person_data = create_user_dict(participant_user)
|
||||
person_data["course_sessions"] = [course_session_entry]
|
||||
result_persons[participant_user] = person_data
|
||||
else:
|
||||
# user is already in result_persons
|
||||
result_persons[participant_user]["course_sessions"].append(
|
||||
course_session_entry
|
||||
)
|
||||
if "BERUFSBILDNER" in cs.roles:
|
||||
for relation in AgentParticipantRelation.objects.filter(
|
||||
agent=user, participant__course_session_id=cs.id, role="BERUFSBILDNER"
|
||||
):
|
||||
_add_agent_relation("BERUFSBILDNER", "PARTICIPANT")
|
||||
|
||||
# add persons where request.user is mentee
|
||||
# add persons where request.user is lerning mentee
|
||||
mentor_relation_qs = AgentParticipantRelation.objects.filter(
|
||||
participant__user=user,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
|
|
@ -230,7 +236,7 @@ def _create_person_list_with_roles(user):
|
|||
cs = mentor_relation.participant.course_session
|
||||
course_session_entry = _create_course_session_dict(
|
||||
cs,
|
||||
"LEARNING_MENTEE",
|
||||
"PARTICIPANT",
|
||||
"LEARNING_MENTOR",
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ def is_agent_for_user(
|
|||
qs = AgentParticipantRelation.objects.filter(
|
||||
agent=agent,
|
||||
participant=csu,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
if roles and len(roles) > 0:
|
||||
|
|
@ -159,7 +158,9 @@ def is_course_session_member(user, course_session_id: int | None = None):
|
|||
|
||||
|
||||
def can_evaluate_assignments(
|
||||
evaluation_user: User, course_session_id: int, assignment_user_id: str | None = None
|
||||
evaluation_user: User,
|
||||
course_session_id: int,
|
||||
assignment_user_ids: list[str] | None = None,
|
||||
):
|
||||
if evaluation_user.is_superuser:
|
||||
return True
|
||||
|
|
@ -167,20 +168,28 @@ def can_evaluate_assignments(
|
|||
is_supervisor = CourseSessionGroup.objects.filter(
|
||||
supervisor=evaluation_user, course_session__id=course_session_id
|
||||
).exists()
|
||||
if is_supervisor:
|
||||
return True
|
||||
|
||||
is_expert = CourseSessionUser.objects.filter(
|
||||
course_session_id=course_session_id,
|
||||
user=evaluation_user,
|
||||
role=CourseSessionUser.Role.EXPERT,
|
||||
).exists()
|
||||
if is_expert:
|
||||
return True
|
||||
|
||||
is_mentor = is_learning_mentor_for_user(
|
||||
mentor=evaluation_user,
|
||||
participant_user_id=assignment_user_id,
|
||||
course_session_id=course_session_id,
|
||||
)
|
||||
|
||||
return is_supervisor or is_expert or is_mentor
|
||||
if assignment_user_ids and len(assignment_user_ids) > 0:
|
||||
is_agent_array = []
|
||||
for assignment_user_id in assignment_user_ids:
|
||||
is_agent_array.append(
|
||||
is_agent_for_user(
|
||||
agent=evaluation_user,
|
||||
participant_user_id=assignment_user_id,
|
||||
course_session_id=course_session_id,
|
||||
)
|
||||
)
|
||||
return all(is_agent_array)
|
||||
|
||||
|
||||
def course_sessions_for_user_qs(user):
|
||||
|
|
|
|||
Loading…
Reference in New Issue