diff --git a/client/src/components/dashboard/BerufsbildnerStatistics.vue b/client/src/components/dashboard/BerufsbildnerStatistics.vue new file mode 100644 index 00000000..5fc5cad4 --- /dev/null +++ b/client/src/components/dashboard/BerufsbildnerStatistics.vue @@ -0,0 +1,49 @@ + + + diff --git a/client/src/components/dashboard/CoursePanel.vue b/client/src/components/dashboard/CoursePanel.vue index 241ec339..d97a6d02 100644 --- a/client/src/components/dashboard/CoursePanel.vue +++ b/client/src/components/dashboard/CoursePanel.vue @@ -9,6 +9,7 @@ import MentorMenteeCount from "@/components/dashboard/MentorMenteeCount.vue"; import MentorCompetenceSummary from "@/components/dashboard/MentorCompetenceSummary.vue"; import { getCockpitUrl, getLearningMentorUrl, getLearningPathUrl } from "@/utils/utils"; import UkStatistics from "@/components/dashboard/UkStatistics.vue"; +import BerufsbildnerStatistics from "@/components/dashboard/BerufsbildnerStatistics.vue"; const mentorWidgets = [ "MentorTasksWidget", @@ -112,6 +113,7 @@ function hasActionButton(): boolean {

+
+
+
+ +
+ +
+
-import type { Ref } from "vue"; -import { onMounted, ref } from "vue"; +import { computed, onMounted, ref } from "vue"; import { type DashboardRoleKeyType, fetchMentorCompetenceSummary, } from "@/services/dashboard"; -import type { AssignmentsStatisticsType } from "@/gql/graphql"; +import type { BaseStatisticsType } from "@/gql/graphql"; import BaseBox from "@/components/dashboard/BaseBox.vue"; const props = defineProps<{ @@ -13,11 +12,17 @@ const props = defineProps<{ agentRole: DashboardRoleKeyType; }>(); -const summary: Ref = ref(null); +const mentorAssignmentData = ref(null); + +const summary = computed(() => { + return mentorAssignmentData.value?.assignments ?? null; +}); onMounted(async () => { - summary.value = await fetchMentorCompetenceSummary(props.courseId, props.agentRole); - console.log(summary.value); + mentorAssignmentData.value = await fetchMentorCompetenceSummary( + props.courseId, + props.agentRole + ); }); diff --git a/client/src/gql/graphql.ts b/client/src/gql/graphql.ts index 571f0d96..a21a54a7 100644 --- a/client/src/gql/graphql.ts +++ b/client/src/gql/graphql.ts @@ -250,6 +250,7 @@ export type BaseStatisticsType = { _id: Scalars['ID']['output']; assignments: AssignmentsStatisticsType; course_id: Scalars['ID']['output']; + course_session_properties: StatisticsCourseSessionPropertiesType; course_session_selection_ids: Array>; course_slug: Scalars['String']['output']; course_title: Scalars['String']['output']; diff --git a/client/src/gql/schema.graphql b/client/src/gql/schema.graphql index 8158c73e..701273cc 100644 --- a/client/src/gql/schema.graphql +++ b/client/src/gql/schema.graphql @@ -189,6 +189,7 @@ type BaseStatisticsType { course_session_selection_ids: [ID]! user_selection_ids: [ID] assignments: AssignmentsStatisticsType! + course_session_properties: StatisticsCourseSessionPropertiesType! } type CourseProgressType { diff --git a/client/src/pages/dashboard/statistic/AgentStatisticParentPage.vue b/client/src/pages/dashboard/statistic/AgentStatisticParentPage.vue new file mode 100644 index 00000000..29f2dd4c --- /dev/null +++ b/client/src/pages/dashboard/statistic/AgentStatisticParentPage.vue @@ -0,0 +1,30 @@ + + + diff --git a/client/src/services/dashboard.ts b/client/src/services/dashboard.ts index b6c427a9..5a93ab0c 100644 --- a/client/src/services/dashboard.ts +++ b/client/src/services/dashboard.ts @@ -8,10 +8,10 @@ import { import { itGetCached, itPost } from "@/fetchHelpers"; import type { - AssignmentsStatisticsType, + AssignmentsStatisticsType, BaseStatisticsType, CourseProgressType, CourseStatisticsType, - DashboardConfigType, + DashboardConfigType } from "@/gql/graphql"; import type { DashboardPersonsPageMode, @@ -42,7 +42,8 @@ export type WidgetType = | "MentorPersonWidget" | "MentorCompetenceWidget" | "CompetenceCertificateWidget" - | "UKStatisticsWidget"; + | "UKStatisticsWidget" + | "UKBerufsbildnerStatisticsWidget"; export type DashboardPersonCourseSessionType = { id: string; @@ -152,7 +153,7 @@ export const fetchDashboardConfig = async (): Promise => { +): Promise => { let agentRole = ""; if (["MentorUK", "MentorVV"].includes(roleKey)) { agentRole = "LEARNING_MENTOR"; @@ -174,7 +175,7 @@ export const fetchMentorCompetenceSummary = async ( if (res.error) { console.error("Error fetching data for course ID:", courseId, res.error); } - return res.data?.mentor_course_statistics?.assignments || null; + return res.data?.mentor_course_statistics || null; } catch (error) { console.error(`Error fetching data for course ID: ${courseId}`, error); return null; diff --git a/scripts/create_berufsbilnder_mobi.py b/scripts/create_berufsbilnder_mobi.py index c784eed5..85eaeccd 100644 --- a/scripts/create_berufsbilnder_mobi.py +++ b/scripts/create_berufsbilnder_mobi.py @@ -33,6 +33,7 @@ def main(): for csu in ( CourseSessionUser.objects.filter(user__username__contains="@mobi") .filter(course_session__course__configuration__is_uk=True) + .filter(role=CourseSessionUser.Role.MEMBER.value) .exclude(course_session_id__in=[4, 5, 6]) ): AgentParticipantRelation.objects.get_or_create( diff --git a/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py b/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py index d5701eb8..24544451 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py @@ -96,6 +96,10 @@ class BaseStatisticsType(graphene.ObjectType): user_selection_ids = graphene.List(graphene.ID, required=False) assignments = graphene.Field(AssignmentsStatisticsType, required=True) + course_session_properties = graphene.Field( + StatisticsCourseSessionPropertiesType, required=True + ) + def resolve_assignments(root, _info) -> AssignmentsStatisticsType: user_selection_ids = ( [str(user) for user in root.user_selection_ids] @@ -110,92 +114,6 @@ class BaseStatisticsType(graphene.ObjectType): urql_id=str(root._id), ) - def get_circle_ids(self, info): - return getattr(info.context, "circle_ids", None) - - -class CourseStatisticsType(BaseStatisticsType): - course_session_properties = graphene.Field( - StatisticsCourseSessionPropertiesType, required=True - ) - course_session_selection_metrics = graphene.Field( - StatisticsCourseSessionsSelectionMetricType, required=True - ) - attendance_day_presences = graphene.Field( - AttendanceDayPresencesStatisticsType, required=True - ) - feedback_responses = graphene.Field(FeedbackStatisticsResponsesType, required=True) - competences = graphene.Field(CompetencesStatisticsType, required=True) - - def resolve_attendance_day_presences( - root, info - ) -> AttendanceDayPresencesStatisticsType: - return attendance_day_presences( - course_id=root.course_id, - course_session_selection_ids=root.course_session_selection_ids, - circle_ids=root.get_circle_ids(info), - urql_id=str(root._id), - ) - - def resolve_feedback_responses(root, info) -> FeedbackStatisticsResponsesType: - return feedback_responses( - course_session_selection_ids=root.course_session_selection_ids, - course_id=root.course_id, - course_slug=root.course_slug, - circle_ids=root.get_circle_ids(info), - urql_id=str(root._id), - ) - - def resolve_competences(root, info) -> CompetencesStatisticsType: - user_selection_ids = ( - [str(user) for user in root.user_selection_ids] - if root.user_selection_ids - else None - ) # noqa - records, success_total, fail_total = competences( - course_slug=str(root.course_slug), - course_session_selection_ids=[ - str(cs) for cs in root.course_session_selection_ids # noqa - ], - user_selection_ids=user_selection_ids, # noqa - circle_ids=root.get_circle_ids(info), # noqa - urql_id_postfix=str(root._id), # noqa - ) - return CompetencesStatisticsType( - _id=root._id, # noqa - records=records, # noqa - summary=CompetencePerformanceStatisticsSummaryType( # noqa - _id=root._id, # noqa - success_total=success_total, # noqa - fail_total=fail_total, # noqa - ), - ) - - def resolve_course_session_selection_metrics( - root, info - ) -> StatisticsCourseSessionsSelectionMetricType: - course_session_count = CourseSession.objects.filter( - id__in=root.course_session_selection_ids, - course_id=root.course_id, - ).count() - - expert_count = CourseSessionUser.objects.filter( - course_session_id__in=root.course_session_selection_ids, - role=CourseSessionUser.Role.EXPERT, - ).count() - - participant_count = CourseSessionUser.objects.filter( - course_session_id__in=root.course_session_selection_ids, - role=CourseSessionUser.Role.MEMBER, - ).count() - - return StatisticsCourseSessionsSelectionMetricType( - _id=root._id, # noqa - session_count=course_session_count, # noqa - participant_count=participant_count, # noqa - expert_count=expert_count, # noqa - ) - def resolve_course_session_properties(root, info): course_session_data = [] circle_data = [] @@ -238,3 +156,87 @@ class CourseStatisticsType(BaseStatisticsType): generations=list(generations), # noqa circles=circle_data, # noqa ) + + def get_circle_ids(self, info): + return getattr(info.context, "circle_ids", None) + + +class CourseStatisticsType(BaseStatisticsType): + course_session_selection_metrics = graphene.Field( + StatisticsCourseSessionsSelectionMetricType, required=True + ) + attendance_day_presences = graphene.Field( + AttendanceDayPresencesStatisticsType, required=True + ) + feedback_responses = graphene.Field(FeedbackStatisticsResponsesType, required=True) + competences = graphene.Field(CompetencesStatisticsType, required=True) + + def resolve_attendance_day_presences( + root, info + ) -> AttendanceDayPresencesStatisticsType: + return attendance_day_presences( + course_id=root.course_id, + course_session_selection_ids=root.course_session_selection_ids, + circle_ids=root.get_circle_ids(info), + urql_id=str(root._id), + ) + + def resolve_feedback_responses(root, info) -> FeedbackStatisticsResponsesType: + return feedback_responses( + course_session_selection_ids=root.course_session_selection_ids, + course_id=root.course_id, + course_slug=root.course_slug, + circle_ids=root.get_circle_ids(info), + urql_id=str(root._id), + ) + + def resolve_competences(root, info) -> CompetencesStatisticsType: + user_selection_ids = ( + [str(user) for user in root.user_selection_ids] + if root.user_selection_ids + else None + ) # noqa + records, success_total, fail_total = competences( + course_slug=str(root.course_slug), + course_session_selection_ids=[ + str(cs) + for cs in root.course_session_selection_ids # noqa + ], + user_selection_ids=user_selection_ids, # noqa + circle_ids=root.get_circle_ids(info), # noqa + urql_id_postfix=str(root._id), # noqa + ) + return CompetencesStatisticsType( + _id=root._id, # noqa + records=records, # noqa + summary=CompetencePerformanceStatisticsSummaryType( # noqa + _id=root._id, # noqa + success_total=success_total, # noqa + fail_total=fail_total, # noqa + ), + ) + + def resolve_course_session_selection_metrics( + root, info + ) -> StatisticsCourseSessionsSelectionMetricType: + course_session_count = CourseSession.objects.filter( + id__in=root.course_session_selection_ids, + course_id=root.course_id, + ).count() + + expert_count = CourseSessionUser.objects.filter( + course_session_id__in=root.course_session_selection_ids, + role=CourseSessionUser.Role.EXPERT, + ).count() + + participant_count = CourseSessionUser.objects.filter( + course_session_id__in=root.course_session_selection_ids, + role=CourseSessionUser.Role.MEMBER, + ).count() + + return StatisticsCourseSessionsSelectionMetricType( + _id=root._id, # noqa + session_count=course_session_count, # noqa + participant_count=participant_count, # noqa + expert_count=expert_count, # noqa + ) diff --git a/server/vbv_lernwelt/dashboard/views.py b/server/vbv_lernwelt/dashboard/views.py index bf19fe4a..20b5a8ce 100644 --- a/server/vbv_lernwelt/dashboard/views.py +++ b/server/vbv_lernwelt/dashboard/views.py @@ -58,6 +58,7 @@ class WidgetType(Enum): MENTOR_COMPETENCE_WIDGET = "MentorCompetenceWidget" COMPETENCE_CERTIFICATE_WIDGET = "CompetenceCertificateWidget" UK_STATISTICS_WIDGET = "UKStatisticsWidget" + UK_BERUFSBILDNER_STATISTICS_WIDGET = "UKBerufsbildnerStatisticsWidget" class RoleKeyType(Enum): @@ -379,7 +380,7 @@ def get_widgets_for_course( widgets.append(WidgetType.MENTOR_TASKS_WIDGET.value) if role_key in [RoleKeyType.BERUFSBILDNER]: - widgets.append(WidgetType.MENTOR_COMPETENCE_WIDGET.value) + widgets.append(WidgetType.UK_BERUFSBILDNER_STATISTICS_WIDGET.value) return widgets