Improve course session loading
This commit is contained in:
parent
bb50cc60e9
commit
778dde12d7
|
|
@ -2,7 +2,7 @@
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
import { useRouteLookups } from "@/utils/route";
|
import { useRouteLookups } from "@/utils/route";
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import { getCompetenceBaseUrl } from "@/utils/utils";
|
import { getCompetenceNaviUrl, getLearningPathUrl } from "@/utils/utils";
|
||||||
|
|
||||||
const { inCompetenceProfile, inLearningPath } = useRouteLookups();
|
const { inCompetenceProfile, inLearningPath } = useRouteLookups();
|
||||||
const courseSession = useCurrentCourseSession();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
@ -24,7 +24,7 @@ const { t } = useTranslation();
|
||||||
<div class="flex space-x-8">
|
<div class="flex space-x-8">
|
||||||
<router-link
|
<router-link
|
||||||
data-cy="preview-learn-path-link"
|
data-cy="preview-learn-path-link"
|
||||||
:to="courseSession.learning_path_url"
|
:to="getLearningPathUrl(courseSession)"
|
||||||
class="preview-nav-item"
|
class="preview-nav-item"
|
||||||
:class="{ 'preview-nav-item--active': inLearningPath() }"
|
:class="{ 'preview-nav-item--active': inLearningPath() }"
|
||||||
>
|
>
|
||||||
|
|
@ -33,7 +33,7 @@ const { t } = useTranslation();
|
||||||
|
|
||||||
<router-link
|
<router-link
|
||||||
data-cy="preview-competence-profile-link"
|
data-cy="preview-competence-profile-link"
|
||||||
:to="getCompetenceBaseUrl(courseSession)"
|
:to="getCompetenceNaviUrl(courseSession)"
|
||||||
class="preview-nav-item"
|
class="preview-nav-item"
|
||||||
:class="{ 'preview-nav-item--active': inCompetenceProfile() }"
|
:class="{ 'preview-nav-item--active': inCompetenceProfile() }"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,11 @@ import { breakpointsTailwind, useBreakpoints } from "@vueuse/core";
|
||||||
import { computed, onMounted, reactive } from "vue";
|
import { computed, onMounted, reactive } from "vue";
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
import CoursePreviewBar from "@/components/header/CoursePreviewBar.vue";
|
import CoursePreviewBar from "@/components/header/CoursePreviewBar.vue";
|
||||||
import { getCompetenceBaseUrl } from "@/utils/utils";
|
import {
|
||||||
|
getCompetenceNaviUrl,
|
||||||
|
getLearningPathUrl,
|
||||||
|
getMediaCenterUrl,
|
||||||
|
} from "@/utils/utils";
|
||||||
|
|
||||||
log.debug("MainNavigationBar created");
|
log.debug("MainNavigationBar created");
|
||||||
|
|
||||||
|
|
@ -71,7 +75,7 @@ onMounted(() => {
|
||||||
v-if="userStore.loggedIn"
|
v-if="userStore.loggedIn"
|
||||||
:show="state.showMobileNavigationMenu"
|
:show="state.showMobileNavigationMenu"
|
||||||
:course-session="courseSessionsStore.currentCourseSession"
|
:course-session="courseSessionsStore.currentCourseSession"
|
||||||
:media-url="courseSessionsStore.currentCourseSession?.media_library_url"
|
:media-url="getMediaCenterUrl(courseSessionsStore.currentCourseSession)"
|
||||||
:user="userStore"
|
:user="userStore"
|
||||||
@closemodal="state.showMobileNavigationMenu = false"
|
@closemodal="state.showMobileNavigationMenu = false"
|
||||||
@logout="userStore.handleLogout()"
|
@logout="userStore.handleLogout()"
|
||||||
|
|
@ -138,7 +142,7 @@ onMounted(() => {
|
||||||
|
|
||||||
<router-link
|
<router-link
|
||||||
data-cy="navigation-preview-link"
|
data-cy="navigation-preview-link"
|
||||||
:to="courseSessionsStore.currentCourseSession.learning_path_url"
|
:to="getLearningPathUrl(courseSessionsStore.currentCourseSession)"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="nav-item"
|
class="nav-item"
|
||||||
>
|
>
|
||||||
|
|
@ -151,7 +155,7 @@ onMounted(() => {
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<router-link
|
<router-link
|
||||||
data-cy="navigation-learning-path-link"
|
data-cy="navigation-learning-path-link"
|
||||||
:to="courseSessionsStore.currentCourseSession.learning_path_url"
|
:to="getLearningPathUrl(courseSessionsStore.currentCourseSession)"
|
||||||
class="nav-item"
|
class="nav-item"
|
||||||
:class="{ 'nav-item--active': inLearningPath() }"
|
:class="{ 'nav-item--active': inLearningPath() }"
|
||||||
>
|
>
|
||||||
|
|
@ -161,7 +165,7 @@ onMounted(() => {
|
||||||
<router-link
|
<router-link
|
||||||
data-cy="navigation-competence-profile-link"
|
data-cy="navigation-competence-profile-link"
|
||||||
:to="
|
:to="
|
||||||
getCompetenceBaseUrl(courseSessionsStore.currentCourseSession)
|
getCompetenceNaviUrl(courseSessionsStore.currentCourseSession)
|
||||||
"
|
"
|
||||||
class="nav-item"
|
class="nav-item"
|
||||||
:class="{ 'nav-item--active': inCompetenceProfile() }"
|
:class="{ 'nav-item--active': inCompetenceProfile() }"
|
||||||
|
|
@ -176,7 +180,7 @@ onMounted(() => {
|
||||||
<div class="flex items-stretch justify-start space-x-8">
|
<div class="flex items-stretch justify-start space-x-8">
|
||||||
<router-link
|
<router-link
|
||||||
v-if="inCourse() && courseSessionsStore.currentCourseSession"
|
v-if="inCourse() && courseSessionsStore.currentCourseSession"
|
||||||
:to="courseSessionsStore.currentCourseSession.media_library_url"
|
:to="getMediaCenterUrl(courseSessionsStore.currentCourseSession)"
|
||||||
data-cy="medialibrary-link"
|
data-cy="medialibrary-link"
|
||||||
class="nav-item-no-mobile"
|
class="nav-item-no-mobile"
|
||||||
:class="{ 'nav-item--active': inMediaLibrary() }"
|
:class="{ 'nav-item--active': inMediaLibrary() }"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||||
import type { UserState } from "@/stores/user";
|
import type { UserState } from "@/stores/user";
|
||||||
import type { CourseSession } from "@/types";
|
import type { CourseSession } from "@/types";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { getCompetenceBaseUrl } from "@/utils/utils";
|
import {
|
||||||
|
getCompetenceNaviUrl,
|
||||||
|
getLearningPathUrl,
|
||||||
|
getMediaCenterUrl,
|
||||||
|
} from "@/utils/utils";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
@ -68,7 +72,7 @@ const courseSessionsStore = useCourseSessionsStore();
|
||||||
<li class="mb-6">
|
<li class="mb-6">
|
||||||
<button
|
<button
|
||||||
data-cy="navigation-mobile-preview-link"
|
data-cy="navigation-mobile-preview-link"
|
||||||
@click="clickLink(courseSession.learning_path_url)"
|
@click="clickLink(getLearningPathUrl(courseSession))"
|
||||||
>
|
>
|
||||||
{{ $t("a.VorschauTeilnehmer") }}
|
{{ $t("a.VorschauTeilnehmer") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -78,7 +82,7 @@ const courseSessionsStore = useCourseSessionsStore();
|
||||||
<li class="mb-6">
|
<li class="mb-6">
|
||||||
<button
|
<button
|
||||||
data-cy="navigation-mobile-learning-path-link"
|
data-cy="navigation-mobile-learning-path-link"
|
||||||
@click="clickLink(courseSession.learning_path_url)"
|
@click="clickLink(getLearningPathUrl(courseSession))"
|
||||||
>
|
>
|
||||||
{{ $t("general.learningPath") }}
|
{{ $t("general.learningPath") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -86,7 +90,7 @@ const courseSessionsStore = useCourseSessionsStore();
|
||||||
<li class="mb-6">
|
<li class="mb-6">
|
||||||
<button
|
<button
|
||||||
data-cy="navigation-mobile-competence-profile-link"
|
data-cy="navigation-mobile-competence-profile-link"
|
||||||
@click="clickLink(getCompetenceBaseUrl(courseSession))"
|
@click="clickLink(getCompetenceNaviUrl(courseSession))"
|
||||||
>
|
>
|
||||||
{{ $t("competences.title") }}
|
{{ $t("competences.title") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -95,7 +99,7 @@ const courseSessionsStore = useCourseSessionsStore();
|
||||||
<li class="mb-6">
|
<li class="mb-6">
|
||||||
<button
|
<button
|
||||||
data-cy="medialibrary-link"
|
data-cy="medialibrary-link"
|
||||||
@click="clickLink(`${courseSession?.media_library_url}`)"
|
@click="clickLink(getMediaCenterUrl(courseSession))"
|
||||||
>
|
>
|
||||||
{{ $t("a.Mediathek") }}
|
{{ $t("a.Mediathek") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
||||||
import type { CourseSession } from "@/types";
|
import type { CourseSession, CourseSessionDetail } from "@/types";
|
||||||
|
import { useQuery } from "@urql/vue";
|
||||||
|
|
||||||
|
import { COURSE_SESSION_DETAIL_QUERY } from "@/graphql/queries";
|
||||||
|
import { useUserStore } from "@/stores/user";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import type { ComputedRef } from "vue";
|
import type { ComputedRef } from "vue";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
@ -28,3 +32,52 @@ export function useCurrentCourseSession() {
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useCourseSessionDetailQuery(courSessionId?: string | number) {
|
||||||
|
if (!courSessionId) {
|
||||||
|
courSessionId = useCurrentCourseSession().value.id;
|
||||||
|
}
|
||||||
|
const queryResult = useQuery({
|
||||||
|
query: COURSE_SESSION_DETAIL_QUERY,
|
||||||
|
variables: {
|
||||||
|
courseSessionId: courSessionId.toString(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const courseSessionDetail = computed(() => {
|
||||||
|
return queryResult.data.value?.course_session as CourseSessionDetail | undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
function findAssignmentDetail(assignmentId: string) {
|
||||||
|
return (courseSessionDetail.value?.assignments ?? []).find((a) => {
|
||||||
|
return a.learning_content?.content_assignment?.id === assignmentId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function findUser(userId: string) {
|
||||||
|
return (courseSessionDetail.value?.users ?? []).find((u) => {
|
||||||
|
return u.user_id === userId;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function findCurrentUser() {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const userId = userStore.id;
|
||||||
|
return findUser(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterMembers() {
|
||||||
|
return (courseSessionDetail.value?.users ?? []).filter((u) => {
|
||||||
|
return u.role === "MEMBER";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...queryResult,
|
||||||
|
courseSessionDetail,
|
||||||
|
findAssignmentDetail,
|
||||||
|
findUser,
|
||||||
|
findCurrentUser,
|
||||||
|
filterMembers,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,12 @@ type Query {
|
||||||
learning_content_learning_module: LearningContentLearningModuleObjectType
|
learning_content_learning_module: LearningContentLearningModuleObjectType
|
||||||
learning_content_placeholder: LearningContentPlaceholderObjectType
|
learning_content_placeholder: LearningContentPlaceholderObjectType
|
||||||
learning_content_rich_text: LearningContentRichTextObjectType
|
learning_content_rich_text: LearningContentRichTextObjectType
|
||||||
learning_content_test: LearningContentTestObjectType
|
learning_content_test: LearningContentEdoniqTestObjectType
|
||||||
learning_content_video: LearningContentVideoObjectType
|
learning_content_video: LearningContentVideoObjectType
|
||||||
learning_content_document_list: LearningContentDocumentListObjectType
|
learning_content_document_list: LearningContentDocumentListObjectType
|
||||||
course_session_attendance_course(id: ID!, assignment_user_id: ID): CourseSessionAttendanceCourseType
|
course_session_attendance_course(id: ID!, assignment_user_id: ID): CourseSessionAttendanceCourseObjectType
|
||||||
course(id: Int): CourseObjectType
|
course(id: ID): CourseObjectType
|
||||||
|
course_session(id: ID): CourseSessionObjectType
|
||||||
competence_certificate(id: ID, slug: String): CompetenceCertificateObjectType
|
competence_certificate(id: ID, slug: String): CompetenceCertificateObjectType
|
||||||
competence_certificate_list(id: ID, slug: String, course_id: ID, course_slug: String): CompetenceCertificateListObjectType
|
competence_certificate_list(id: ID, slug: String, course_id: ID, course_slug: String): CompetenceCertificateListObjectType
|
||||||
assignment(id: ID, slug: String): AssignmentObjectType
|
assignment(id: ID, slug: String): AssignmentObjectType
|
||||||
|
|
@ -307,12 +308,155 @@ type AssignmentCompletionObjectType {
|
||||||
edoniq_extended_time_flag: Boolean!
|
edoniq_extended_time_flag: Boolean!
|
||||||
assignment_user: UserType!
|
assignment_user: UserType!
|
||||||
assignment: AssignmentObjectType!
|
assignment: AssignmentObjectType!
|
||||||
|
course_session: CourseSessionObjectType!
|
||||||
completion_status: AssignmentAssignmentCompletionCompletionStatusChoices!
|
completion_status: AssignmentAssignmentCompletionCompletionStatusChoices!
|
||||||
completion_data: GenericScalar
|
completion_data: GenericScalar
|
||||||
additional_json_data: JSONString!
|
additional_json_data: JSONString!
|
||||||
learning_content_page_id: ID
|
learning_content_page_id: ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CourseSessionObjectType {
|
||||||
|
id: ID!
|
||||||
|
created_at: DateTime!
|
||||||
|
updated_at: DateTime!
|
||||||
|
course: CourseObjectType!
|
||||||
|
title: String!
|
||||||
|
start_date: Date
|
||||||
|
end_date: Date
|
||||||
|
attendance_courses: [CourseSessionAttendanceCourseObjectType]
|
||||||
|
assignments: [CourseSessionAssignmentObjectType]
|
||||||
|
edoniq_tests: [CourseSessionEdoniqTestObjectType]
|
||||||
|
users: [CourseSessionUserObjectsType]
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
The `Date` scalar type represents a Date
|
||||||
|
value as specified by
|
||||||
|
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
|
||||||
|
"""
|
||||||
|
scalar Date
|
||||||
|
|
||||||
|
type CourseSessionAttendanceCourseObjectType {
|
||||||
|
id: ID!
|
||||||
|
learning_content: LearningContentAttendanceCourseObjectType
|
||||||
|
due_date: DueDateObjectType
|
||||||
|
location: String!
|
||||||
|
trainer: String!
|
||||||
|
course_session_id: ID
|
||||||
|
learning_content_id: ID
|
||||||
|
attendance_user_list: [AttendanceUserObjectType]
|
||||||
|
}
|
||||||
|
|
||||||
|
type LearningContentAttendanceCourseObjectType implements LearningContentInterface {
|
||||||
|
id: ID
|
||||||
|
title: String
|
||||||
|
slug: String
|
||||||
|
content_type: String
|
||||||
|
live: Boolean
|
||||||
|
translation_key: String
|
||||||
|
frontend_url: String
|
||||||
|
circle: CircleObjectType
|
||||||
|
course: CourseObjectType
|
||||||
|
minutes: Int
|
||||||
|
description: String
|
||||||
|
content: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type DueDateObjectType {
|
||||||
|
id: ID!
|
||||||
|
|
||||||
|
"""Startdatum ist Pflicht"""
|
||||||
|
start: DateTime
|
||||||
|
|
||||||
|
"""Enddatum ist optional"""
|
||||||
|
end: DateTime
|
||||||
|
|
||||||
|
"""Nur aktivieren, wenn man die Felder manuell überschreiben will"""
|
||||||
|
manual_override_fields: Boolean!
|
||||||
|
|
||||||
|
"""Title wird standarmässig vom LearningContent übernommen"""
|
||||||
|
title: String!
|
||||||
|
|
||||||
|
"""Translation Key aus dem Frontend"""
|
||||||
|
assignment_type_translation_key: String!
|
||||||
|
|
||||||
|
"""Translation Key aus dem Frontend"""
|
||||||
|
date_type_translation_key: String!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Überschreibt den Untertitel bei `assignment_type_translation_key` und `date_type_translation_key`
|
||||||
|
"""
|
||||||
|
subtitle: String!
|
||||||
|
|
||||||
|
"""URL wird vom LearningContent übernommen"""
|
||||||
|
url: String!
|
||||||
|
course_session: CourseSessionObjectType!
|
||||||
|
}
|
||||||
|
|
||||||
|
type AttendanceUserObjectType {
|
||||||
|
user_id: UUID!
|
||||||
|
status: AttendanceUserStatus!
|
||||||
|
first_name: String
|
||||||
|
last_name: String
|
||||||
|
email: String
|
||||||
|
}
|
||||||
|
|
||||||
|
"""An enumeration."""
|
||||||
|
enum AttendanceUserStatus {
|
||||||
|
PRESENT
|
||||||
|
ABSENT
|
||||||
|
}
|
||||||
|
|
||||||
|
type CourseSessionAssignmentObjectType {
|
||||||
|
id: ID!
|
||||||
|
learning_content: LearningContentAssignmentObjectType
|
||||||
|
submission_deadline: DueDateObjectType
|
||||||
|
evaluation_deadline: DueDateObjectType
|
||||||
|
course_session_id: ID
|
||||||
|
learning_content_id: ID
|
||||||
|
}
|
||||||
|
|
||||||
|
type CourseSessionEdoniqTestObjectType {
|
||||||
|
id: ID!
|
||||||
|
learning_content: LearningContentEdoniqTestObjectType
|
||||||
|
course_session_id: ID
|
||||||
|
learning_content_id: ID
|
||||||
|
deadline: DueDateObjectType
|
||||||
|
}
|
||||||
|
|
||||||
|
type LearningContentEdoniqTestObjectType implements LearningContentInterface {
|
||||||
|
content_assignment: AssignmentObjectType
|
||||||
|
id: ID
|
||||||
|
title: String
|
||||||
|
slug: String
|
||||||
|
content_type: String
|
||||||
|
live: Boolean
|
||||||
|
translation_key: String
|
||||||
|
frontend_url: String
|
||||||
|
circle: CircleObjectType
|
||||||
|
course: CourseObjectType
|
||||||
|
minutes: Int
|
||||||
|
description: String
|
||||||
|
content: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type CourseSessionUserObjectsType {
|
||||||
|
id: UUID!
|
||||||
|
role: String
|
||||||
|
user_id: UUID
|
||||||
|
first_name: String
|
||||||
|
last_name: String
|
||||||
|
email: String
|
||||||
|
avatar_url: String
|
||||||
|
circles: [CourseSessionUserExpertCircleType]
|
||||||
|
}
|
||||||
|
|
||||||
|
type CourseSessionUserExpertCircleType {
|
||||||
|
id: ID
|
||||||
|
title: String
|
||||||
|
slug: String
|
||||||
|
}
|
||||||
|
|
||||||
"""An enumeration."""
|
"""An enumeration."""
|
||||||
enum AssignmentAssignmentCompletionCompletionStatusChoices {
|
enum AssignmentAssignmentCompletionCompletionStatusChoices {
|
||||||
"""IN_PROGRESS"""
|
"""IN_PROGRESS"""
|
||||||
|
|
@ -361,21 +505,6 @@ enum LearnpathLearningContentAssignmentAssignmentTypeChoices {
|
||||||
EDONIQ_TEST
|
EDONIQ_TEST
|
||||||
}
|
}
|
||||||
|
|
||||||
type LearningContentAttendanceCourseObjectType implements LearningContentInterface {
|
|
||||||
id: ID
|
|
||||||
title: String
|
|
||||||
slug: String
|
|
||||||
content_type: String
|
|
||||||
live: Boolean
|
|
||||||
translation_key: String
|
|
||||||
frontend_url: String
|
|
||||||
circle: CircleObjectType
|
|
||||||
course: CourseObjectType
|
|
||||||
minutes: Int
|
|
||||||
description: String
|
|
||||||
content: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type LearningContentFeedbackObjectType implements LearningContentInterface {
|
type LearningContentFeedbackObjectType implements LearningContentInterface {
|
||||||
id: ID
|
id: ID
|
||||||
title: String
|
title: String
|
||||||
|
|
@ -436,22 +565,6 @@ type LearningContentRichTextObjectType implements LearningContentInterface {
|
||||||
content: String
|
content: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type LearningContentTestObjectType implements LearningContentInterface {
|
|
||||||
content_assignment: AssignmentObjectType
|
|
||||||
id: ID
|
|
||||||
title: String
|
|
||||||
slug: String
|
|
||||||
content_type: String
|
|
||||||
live: Boolean
|
|
||||||
translation_key: String
|
|
||||||
frontend_url: String
|
|
||||||
circle: CircleObjectType
|
|
||||||
course: CourseObjectType
|
|
||||||
minutes: Int
|
|
||||||
description: String
|
|
||||||
content: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type LearningContentVideoObjectType implements LearningContentInterface {
|
type LearningContentVideoObjectType implements LearningContentInterface {
|
||||||
id: ID
|
id: ID
|
||||||
title: String
|
title: String
|
||||||
|
|
@ -482,32 +595,6 @@ type LearningContentDocumentListObjectType implements LearningContentInterface {
|
||||||
content: String
|
content: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type CourseSessionAttendanceCourseType {
|
|
||||||
id: ID!
|
|
||||||
location: String!
|
|
||||||
trainer: String!
|
|
||||||
course_session_id: ID
|
|
||||||
learning_content_id: ID
|
|
||||||
due_date_id: ID
|
|
||||||
end: DateTime
|
|
||||||
start: DateTime
|
|
||||||
attendance_user_list: [AttendanceUserType]
|
|
||||||
}
|
|
||||||
|
|
||||||
type AttendanceUserType {
|
|
||||||
user_id: UUID!
|
|
||||||
status: AttendanceUserStatus!
|
|
||||||
first_name: String
|
|
||||||
last_name: String
|
|
||||||
email: String
|
|
||||||
}
|
|
||||||
|
|
||||||
"""An enumeration."""
|
|
||||||
enum AttendanceUserStatus {
|
|
||||||
PRESENT
|
|
||||||
ABSENT
|
|
||||||
}
|
|
||||||
|
|
||||||
type CompetenceCertificateListObjectType implements CoursePageInterface {
|
type CompetenceCertificateListObjectType implements CoursePageInterface {
|
||||||
id: ID
|
id: ID
|
||||||
path: String!
|
path: String!
|
||||||
|
|
@ -577,7 +664,7 @@ type ErrorType {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AttendanceCourseUserMutation {
|
type AttendanceCourseUserMutation {
|
||||||
course_session_attendance_course: CourseSessionAttendanceCourseType
|
course_session_attendance_course: CourseSessionAttendanceCourseObjectType
|
||||||
}
|
}
|
||||||
|
|
||||||
input AttendanceUserInputType {
|
input AttendanceUserInputType {
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ export const AssignmentCompletionStatus = "AssignmentCompletionStatus";
|
||||||
export const AssignmentObjectType = "AssignmentObjectType";
|
export const AssignmentObjectType = "AssignmentObjectType";
|
||||||
export const AttendanceCourseUserMutation = "AttendanceCourseUserMutation";
|
export const AttendanceCourseUserMutation = "AttendanceCourseUserMutation";
|
||||||
export const AttendanceUserInputType = "AttendanceUserInputType";
|
export const AttendanceUserInputType = "AttendanceUserInputType";
|
||||||
|
export const AttendanceUserObjectType = "AttendanceUserObjectType";
|
||||||
export const AttendanceUserStatus = "AttendanceUserStatus";
|
export const AttendanceUserStatus = "AttendanceUserStatus";
|
||||||
export const AttendanceUserType = "AttendanceUserType";
|
|
||||||
export const Boolean = "Boolean";
|
export const Boolean = "Boolean";
|
||||||
export const CircleObjectType = "CircleObjectType";
|
export const CircleObjectType = "CircleObjectType";
|
||||||
export const CompetenceCertificateListObjectType = "CompetenceCertificateListObjectType";
|
export const CompetenceCertificateListObjectType = "CompetenceCertificateListObjectType";
|
||||||
|
|
@ -15,8 +15,15 @@ export const CompetenceCertificateObjectType = "CompetenceCertificateObjectType"
|
||||||
export const CoreUserLanguageChoices = "CoreUserLanguageChoices";
|
export const CoreUserLanguageChoices = "CoreUserLanguageChoices";
|
||||||
export const CourseObjectType = "CourseObjectType";
|
export const CourseObjectType = "CourseObjectType";
|
||||||
export const CoursePageInterface = "CoursePageInterface";
|
export const CoursePageInterface = "CoursePageInterface";
|
||||||
export const CourseSessionAttendanceCourseType = "CourseSessionAttendanceCourseType";
|
export const CourseSessionAssignmentObjectType = "CourseSessionAssignmentObjectType";
|
||||||
|
export const CourseSessionAttendanceCourseObjectType = "CourseSessionAttendanceCourseObjectType";
|
||||||
|
export const CourseSessionEdoniqTestObjectType = "CourseSessionEdoniqTestObjectType";
|
||||||
|
export const CourseSessionObjectType = "CourseSessionObjectType";
|
||||||
|
export const CourseSessionUserExpertCircleType = "CourseSessionUserExpertCircleType";
|
||||||
|
export const CourseSessionUserObjectsType = "CourseSessionUserObjectsType";
|
||||||
|
export const Date = "Date";
|
||||||
export const DateTime = "DateTime";
|
export const DateTime = "DateTime";
|
||||||
|
export const DueDateObjectType = "DueDateObjectType";
|
||||||
export const ErrorType = "ErrorType";
|
export const ErrorType = "ErrorType";
|
||||||
export const FeedbackResponseObjectType = "FeedbackResponseObjectType";
|
export const FeedbackResponseObjectType = "FeedbackResponseObjectType";
|
||||||
export const Float = "Float";
|
export const Float = "Float";
|
||||||
|
|
@ -28,13 +35,13 @@ export const JSONString = "JSONString";
|
||||||
export const LearningContentAssignmentObjectType = "LearningContentAssignmentObjectType";
|
export const LearningContentAssignmentObjectType = "LearningContentAssignmentObjectType";
|
||||||
export const LearningContentAttendanceCourseObjectType = "LearningContentAttendanceCourseObjectType";
|
export const LearningContentAttendanceCourseObjectType = "LearningContentAttendanceCourseObjectType";
|
||||||
export const LearningContentDocumentListObjectType = "LearningContentDocumentListObjectType";
|
export const LearningContentDocumentListObjectType = "LearningContentDocumentListObjectType";
|
||||||
|
export const LearningContentEdoniqTestObjectType = "LearningContentEdoniqTestObjectType";
|
||||||
export const LearningContentFeedbackObjectType = "LearningContentFeedbackObjectType";
|
export const LearningContentFeedbackObjectType = "LearningContentFeedbackObjectType";
|
||||||
export const LearningContentInterface = "LearningContentInterface";
|
export const LearningContentInterface = "LearningContentInterface";
|
||||||
export const LearningContentLearningModuleObjectType = "LearningContentLearningModuleObjectType";
|
export const LearningContentLearningModuleObjectType = "LearningContentLearningModuleObjectType";
|
||||||
export const LearningContentMediaLibraryObjectType = "LearningContentMediaLibraryObjectType";
|
export const LearningContentMediaLibraryObjectType = "LearningContentMediaLibraryObjectType";
|
||||||
export const LearningContentPlaceholderObjectType = "LearningContentPlaceholderObjectType";
|
export const LearningContentPlaceholderObjectType = "LearningContentPlaceholderObjectType";
|
||||||
export const LearningContentRichTextObjectType = "LearningContentRichTextObjectType";
|
export const LearningContentRichTextObjectType = "LearningContentRichTextObjectType";
|
||||||
export const LearningContentTestObjectType = "LearningContentTestObjectType";
|
|
||||||
export const LearningContentVideoObjectType = "LearningContentVideoObjectType";
|
export const LearningContentVideoObjectType = "LearningContentVideoObjectType";
|
||||||
export const LearningPathObjectType = "LearningPathObjectType";
|
export const LearningPathObjectType = "LearningPathObjectType";
|
||||||
export const LearningSequenceObjectType = "LearningSequenceObjectType";
|
export const LearningSequenceObjectType = "LearningSequenceObjectType";
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ export const graphqlClient = new Client({
|
||||||
cacheExchange({
|
cacheExchange({
|
||||||
schema: schema,
|
schema: schema,
|
||||||
keys: {
|
keys: {
|
||||||
AttendanceUserType: (data) => data?.user_id?.toString() ?? null,
|
AttendanceUserObjectType: (data) => data?.user_id?.toString() ?? null,
|
||||||
},
|
},
|
||||||
updates: {
|
updates: {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ export const ASSIGNMENT_COMPLETION_QUERY = graphql(`
|
||||||
`);
|
`);
|
||||||
|
|
||||||
export const COURSE_QUERY = graphql(`
|
export const COURSE_QUERY = graphql(`
|
||||||
query courseQuery($courseId: Int!) {
|
query courseQuery($courseId: ID!) {
|
||||||
course(id: $courseId) {
|
course(id: $courseId) {
|
||||||
id
|
id
|
||||||
slug
|
slug
|
||||||
|
|
@ -122,3 +122,76 @@ export const COMPETENCE_NAVI_CERTIFICATE_QUERY = graphql(`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
export const COURSE_SESSION_DETAIL_QUERY = graphql(`
|
||||||
|
query courseSessionDetail($courseSessionId: ID!) {
|
||||||
|
course_session(id: $courseSessionId) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
course {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
users {
|
||||||
|
id
|
||||||
|
user_id
|
||||||
|
first_name
|
||||||
|
last_name
|
||||||
|
email
|
||||||
|
avatar_url
|
||||||
|
role
|
||||||
|
circles {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attendance_courses {
|
||||||
|
id
|
||||||
|
location
|
||||||
|
trainer
|
||||||
|
due_date {
|
||||||
|
id
|
||||||
|
start
|
||||||
|
end
|
||||||
|
}
|
||||||
|
learning_content_id
|
||||||
|
learning_content {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assignments {
|
||||||
|
id
|
||||||
|
submission_deadline {
|
||||||
|
id
|
||||||
|
start
|
||||||
|
}
|
||||||
|
evaluation_deadline {
|
||||||
|
id
|
||||||
|
start
|
||||||
|
}
|
||||||
|
learning_content {
|
||||||
|
id
|
||||||
|
content_assignment {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
assignment_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
edoniq_tests {
|
||||||
|
id
|
||||||
|
deadline {
|
||||||
|
id
|
||||||
|
start
|
||||||
|
end
|
||||||
|
}
|
||||||
|
learning_content {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { useUserStore } from "@/stores/user";
|
||||||
import type { CourseSession } from "@/types";
|
import type { CourseSession } from "@/types";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed, onMounted } from "vue";
|
import { computed, onMounted } from "vue";
|
||||||
|
import { getLearningPathUrl } from "@/utils/utils";
|
||||||
|
|
||||||
log.debug("DashboardPage created");
|
log.debug("DashboardPage created");
|
||||||
|
|
||||||
|
|
@ -20,9 +21,9 @@ const allDueDates = courseSessionsStore.allDueDates();
|
||||||
const getNextStepLink = (courseSession: CourseSession) => {
|
const getNextStepLink = (courseSession: CourseSession) => {
|
||||||
return computed(() => {
|
return computed(() => {
|
||||||
if (courseSessionsStore.hasCockpit(courseSession)) {
|
if (courseSessionsStore.hasCockpit(courseSession)) {
|
||||||
return courseSession.cockpit_url;
|
return `${courseSession.course_url}/cockpit`;
|
||||||
}
|
}
|
||||||
return courseSession.learning_path_url;
|
return getLearningPathUrl(courseSession);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as log from "loglevel";
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
import { useCourseSessionDetailQuery } from "@/composables";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
courseSlug: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
log.debug("TestCourseSessionComposablePage mounted");
|
||||||
|
});
|
||||||
|
|
||||||
|
// const courseSession = useCurrentCourseSession();
|
||||||
|
const queryResult = useCourseSessionDetailQuery("-1");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
|
||||||
|
<pre>{{ queryResult.courseSessionDetail }}</pre>
|
||||||
|
</template>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
import { useCourseSessionDetailQuery } from "@/composables";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
import { useCompetenceStore } from "@/stores/competence";
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
|
|
@ -16,13 +16,14 @@ const props = defineProps<{
|
||||||
const cockpitStore = useCockpitStore();
|
const cockpitStore = useCockpitStore();
|
||||||
const competenceStore = useCompetenceStore();
|
const competenceStore = useCompetenceStore();
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
const courseSession = useCurrentCourseSession();
|
|
||||||
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("CockpitParentPage mounted", props.courseSlug);
|
log.debug("CockpitParentPage mounted", props.courseSlug);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const members = await cockpitStore.loadCourseSessionMembers(courseSession.value.id);
|
const members = courseSessionDetailResult.filterMembers();
|
||||||
members.forEach((csu) => {
|
members.forEach((csu) => {
|
||||||
competenceStore.loadCompetenceProfilePage(
|
competenceStore.loadCompetenceProfilePage(
|
||||||
props.courseSlug + "-competencenavi-competences",
|
props.courseSlug + "-competencenavi-competences",
|
||||||
|
|
@ -35,7 +36,10 @@ onMounted(async () => {
|
||||||
props.courseSlug + "-lp",
|
props.courseSlug + "-lp",
|
||||||
useUserStore().id
|
useUserStore().id
|
||||||
);
|
);
|
||||||
await cockpitStore.loadCircles(props.courseSlug, courseSession.value.id);
|
await cockpitStore.loadCircles(
|
||||||
|
props.courseSlug,
|
||||||
|
courseSessionDetailResult.findCurrentUser()
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(error);
|
log.error(error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import CirclePage from "@/pages/learningPath/circlePage/CirclePage.vue";
|
import CirclePage from "@/pages/learningPath/circlePage/CirclePage.vue";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { computed, onMounted } from "vue";
|
import { computed, onMounted } from "vue";
|
||||||
|
import { useCourseSessionDetailQuery } from "@/composables";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
@ -12,14 +12,14 @@ const props = defineProps<{
|
||||||
|
|
||||||
log.debug("CockpitUserCirclePage created", props.userId, props.circleSlug);
|
log.debug("CockpitUserCirclePage created", props.userId, props.circleSlug);
|
||||||
|
|
||||||
const cockpitStore = useCockpitStore();
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("CockpitUserCirclePage mounted");
|
log.debug("CockpitUserCirclePage mounted");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { findUser } = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
const user = computed(() => {
|
const user = computed(() => {
|
||||||
return cockpitStore.courseSessionMembers?.find((csu) => csu.user_id === props.userId);
|
return findUser(props.userId);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { computed, onMounted } from "vue";
|
||||||
|
|
||||||
import CompetenceDetail from "@/pages/competence/ActionCompetenceDetail.vue";
|
import CompetenceDetail from "@/pages/competence/ActionCompetenceDetail.vue";
|
||||||
import LearningPathPathView from "@/pages/learningPath/learningPathPage/LearningPathPathView.vue";
|
import LearningPathPathView from "@/pages/learningPath/learningPathPage/LearningPathPathView.vue";
|
||||||
|
import { useCourseSessionDetailQuery } from "@/composables";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
@ -27,8 +28,10 @@ const learningPath = computed(() => {
|
||||||
return learningPathStore.learningPathForUser(props.courseSlug, props.userId);
|
return learningPathStore.learningPathForUser(props.courseSlug, props.userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { findUser } = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
const user = computed(() => {
|
const user = computed(() => {
|
||||||
return cockpitStore.courseSessionMembers?.find((csu) => csu.user_id === props.userId);
|
return findUser(props.userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
function setActiveClasses(isActive: boolean) {
|
function setActiveClasses(isActive: boolean) {
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,15 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
import { useCurrentCourseSession, useCourseSessionDetailQuery } from "@/composables";
|
||||||
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
|
||||||
import EvaluationContainer from "@/pages/cockpit/assignmentEvaluationPage/EvaluationContainer.vue";
|
import EvaluationContainer from "@/pages/cockpit/assignmentEvaluationPage/EvaluationContainer.vue";
|
||||||
import AssignmentSubmissionResponses from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionResponses.vue";
|
import AssignmentSubmissionResponses from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionResponses.vue";
|
||||||
import type {
|
import type { Assignment, AssignmentCompletion } from "@/types";
|
||||||
Assignment,
|
|
||||||
AssignmentCompletion,
|
|
||||||
CourseSessionAssignment,
|
|
||||||
CourseSessionUser,
|
|
||||||
} from "@/types";
|
|
||||||
import { useQuery } from "@urql/vue";
|
import { useQuery } from "@urql/vue";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed, onMounted, reactive } from "vue";
|
import { computed, onMounted } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { getPreviousRoute } from "@/router/history";
|
import { getPreviousRoute } from "@/router/history";
|
||||||
import { getAssignmentTypeTitle } from "@/utils/utils";
|
import { getAssignmentTypeTitle } from "../../../utils/utils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSlug: string;
|
courseSlug: string;
|
||||||
|
|
@ -24,16 +19,6 @@ const props = defineProps<{
|
||||||
|
|
||||||
log.debug("AssignmentEvaluationPage created", props.assignmentId, props.userId);
|
log.debug("AssignmentEvaluationPage created", props.assignmentId, props.userId);
|
||||||
|
|
||||||
interface StateInterface {
|
|
||||||
courseSessionAssignment: CourseSessionAssignment | undefined;
|
|
||||||
assignmentUser: CourseSessionUser | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const state: StateInterface = reactive({
|
|
||||||
courseSessionAssignment: undefined,
|
|
||||||
assignmentUser: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const courseSession = useCurrentCourseSession();
|
const courseSession = useCurrentCourseSession();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
@ -49,12 +34,11 @@ const queryResult = useQuery({
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("AssignmentView mounted", props.assignmentId, props.userId);
|
log.debug("AssignmentView mounted", props.assignmentId, props.userId);
|
||||||
|
|
||||||
state.assignmentUser = courseSession.value.users.find(
|
|
||||||
(user) => user.user_id === props.userId
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
|
const assignmentUser = computed(() => courseSessionDetailResult.findUser(props.userId));
|
||||||
|
|
||||||
const previousRoute = getPreviousRoute();
|
const previousRoute = getPreviousRoute();
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
|
|
@ -103,10 +87,7 @@ const assignment = computed(
|
||||||
<it-icon-close></it-icon-close>
|
<it-icon-close></it-icon-close>
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
<div
|
<div v-if="assignment && assignmentCompletion && assignmentUser" class="relative">
|
||||||
v-if="assignment && assignmentCompletion && state.assignmentUser"
|
|
||||||
class="relative"
|
|
||||||
>
|
|
||||||
<div class="md:h-content flex flex-col md:flex-row">
|
<div class="md:h-content flex flex-col md:flex-row">
|
||||||
<div
|
<div
|
||||||
class="bg-white md:h-full md:overflow-y-auto"
|
class="bg-white md:h-full md:overflow-y-auto"
|
||||||
|
|
@ -118,12 +99,12 @@ const assignment = computed(
|
||||||
|
|
||||||
<div class="my-6 flex items-center">
|
<div class="my-6 flex items-center">
|
||||||
<img
|
<img
|
||||||
:src="state.assignmentUser?.avatar_url"
|
:src="assignmentUser?.avatar_url"
|
||||||
class="mr-4 h-11 w-11 rounded-full"
|
class="mr-4 h-11 w-11 rounded-full"
|
||||||
/>
|
/>
|
||||||
<div class="font-bold">
|
<div class="font-bold">
|
||||||
{{ state.assignmentUser?.first_name }}
|
{{ assignmentUser?.first_name }}
|
||||||
{{ state.assignmentUser?.last_name }}
|
{{ assignmentUser?.last_name }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AssignmentSubmissionResponses
|
<AssignmentSubmissionResponses
|
||||||
|
|
@ -139,7 +120,7 @@ const assignment = computed(
|
||||||
>
|
>
|
||||||
<EvaluationContainer
|
<EvaluationContainer
|
||||||
:assignment-completion="assignmentCompletion"
|
:assignment-completion="assignmentCompletion"
|
||||||
:assignment-user="state.assignmentUser"
|
:assignment-user="assignmentUser"
|
||||||
:assignment="assignment"
|
:assignment="assignment"
|
||||||
@close="close()"
|
@close="close()"
|
||||||
></EvaluationContainer>
|
></EvaluationContainer>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
import EvaluationIntro from "@/pages/cockpit/assignmentEvaluationPage/EvaluationIntro.vue";
|
import EvaluationIntro from "@/pages/cockpit/assignmentEvaluationPage/EvaluationIntro.vue";
|
||||||
import EvaluationSummary from "@/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue";
|
import EvaluationSummary from "@/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue";
|
||||||
import EvaluationTask from "@/pages/cockpit/assignmentEvaluationPage/EvaluationTask.vue";
|
import EvaluationTask from "@/pages/cockpit/assignmentEvaluationPage/EvaluationTask.vue";
|
||||||
import { findAssignmentDetail } from "@/services/assignmentService";
|
|
||||||
import type {
|
import type {
|
||||||
Assignment,
|
Assignment,
|
||||||
AssignmentCompletion,
|
AssignmentCompletion,
|
||||||
|
|
@ -14,6 +13,7 @@ import dayjs from "dayjs";
|
||||||
import { findIndex } from "lodash";
|
import { findIndex } from "lodash";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { computed, onMounted } from "vue";
|
import { computed, onMounted } from "vue";
|
||||||
|
import { useCourseSessionDetailQuery } from "@/composables";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
assignmentUser: CourseSessionUser;
|
assignmentUser: CourseSessionUser;
|
||||||
|
|
@ -58,10 +58,14 @@ function editTask(task: AssignmentEvaluationTask) {
|
||||||
stepIndex.value = taskIndex + 1;
|
stepIndex.value = taskIndex + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const assignmentDetail = computed(() => findAssignmentDetail(props.assignment.id));
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
|
const assignmentDetail = computed(() => {
|
||||||
|
return courseSessionDetailResult.findAssignmentDetail(props.assignment.id.toString());
|
||||||
|
});
|
||||||
|
|
||||||
const dueDate = computed(() =>
|
const dueDate = computed(() =>
|
||||||
dayjs(assignmentDetail.value?.evaluation_deadline_start)
|
dayjs(assignmentDetail.value?.evaluation_deadline.start)
|
||||||
);
|
);
|
||||||
|
|
||||||
const inEvaluationTask = computed(
|
const inEvaluationTask = computed(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
|
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables";
|
||||||
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
||||||
import {
|
import {
|
||||||
maxAssignmentPoints,
|
maxAssignmentPoints,
|
||||||
|
|
@ -77,13 +77,13 @@ const userPoints = computed(() =>
|
||||||
userAssignmentPoints(props.assignment, props.assignmentCompletion)
|
userAssignmentPoints(props.assignment, props.assignmentCompletion)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
const evaluationUser = computed(() => {
|
const evaluationUser = computed(() => {
|
||||||
if (props.assignmentCompletion.evaluation_user) {
|
if (props.assignmentCompletion.evaluation_user) {
|
||||||
return (courseSession.value.users ?? []).find(
|
return courseSessionDetailResult.findUser(
|
||||||
(user) => user.user_id === props.assignmentCompletion.evaluation_user
|
props.assignmentCompletion.evaluation_user
|
||||||
) as CourseSessionUser;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,17 @@
|
||||||
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
||||||
import type { StatusCount } from "@/components/ui/ItProgress.vue";
|
import type { StatusCount } from "@/components/ui/ItProgress.vue";
|
||||||
import type { GradedUser } from "@/services/assignmentService";
|
import type { GradedUser } from "@/services/assignmentService";
|
||||||
import {
|
import { loadAssignmentCompletionStatusData } from "@/services/assignmentService";
|
||||||
findAssignmentDetail,
|
|
||||||
loadAssignmentCompletionStatusData,
|
|
||||||
} from "@/services/assignmentService";
|
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
|
||||||
import type {
|
import type {
|
||||||
CourseSession,
|
CourseSession,
|
||||||
CourseSessionUser,
|
CourseSessionUser,
|
||||||
LearningContentAssignment,
|
LearningContentAssignment,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
import dayjs from "dayjs";
|
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed, onMounted, reactive } from "vue";
|
import { computed, onMounted, reactive } from "vue";
|
||||||
import AssignmentSubmissionProgress from "@/pages/cockpit/cockpitPage/AssignmentSubmissionProgress.vue";
|
import AssignmentSubmissionProgress from "@/pages/cockpit/cockpitPage/AssignmentSubmissionProgress.vue";
|
||||||
|
import { useCourseSessionDetailQuery } from "@/composables";
|
||||||
|
import { formatDueDate } from "../../../components/dueDates/dueDatesUtils";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSession: CourseSession;
|
courseSession: CourseSession;
|
||||||
|
|
@ -27,7 +24,7 @@ log.debug(
|
||||||
props.learningContentAssignment.content_assignment_id
|
props.learningContentAssignment.content_assignment_id
|
||||||
);
|
);
|
||||||
|
|
||||||
const cockpitStore = useCockpitStore();
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
progressStatusCount: {} as StatusCount,
|
progressStatusCount: {} as StatusCount,
|
||||||
|
|
@ -35,6 +32,12 @@ const state = reactive({
|
||||||
assignmentSubmittedUsers: [] as CourseSessionUser[],
|
assignmentSubmittedUsers: [] as CourseSessionUser[],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const assignmentDetail = computed(() => {
|
||||||
|
return courseSessionDetailResult.findAssignmentDetail(
|
||||||
|
props.learningContentAssignment.content_assignment_id.toString()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const { gradedUsers, assignmentSubmittedUsers } =
|
const { gradedUsers, assignmentSubmittedUsers } =
|
||||||
await loadAssignmentCompletionStatusData(
|
await loadAssignmentCompletionStatusData(
|
||||||
|
|
@ -45,10 +48,6 @@ onMounted(async () => {
|
||||||
state.gradedUsers = gradedUsers;
|
state.gradedUsers = gradedUsers;
|
||||||
state.assignmentSubmittedUsers = assignmentSubmittedUsers;
|
state.assignmentSubmittedUsers = assignmentSubmittedUsers;
|
||||||
});
|
});
|
||||||
|
|
||||||
const assignmentDetail = computed(() =>
|
|
||||||
findAssignmentDetail(props.learningContentAssignment.content_assignment_id)
|
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -62,14 +61,12 @@ const assignmentDetail = computed(() =>
|
||||||
<div v-if="assignmentDetail">
|
<div v-if="assignmentDetail">
|
||||||
<span>
|
<span>
|
||||||
{{ $t("Abgabetermin Ergebnisse:") }}
|
{{ $t("Abgabetermin Ergebnisse:") }}
|
||||||
{{ dayjs(assignmentDetail.submission_deadline_start).format("DD.MM.YYYY") }}
|
{{ formatDueDate(assignmentDetail.submission_deadline.start) }}
|
||||||
</span>
|
</span>
|
||||||
<template v-if="assignmentDetail.evaluation_deadline_start">
|
<template v-if="assignmentDetail.evaluation_deadline.start">
|
||||||
<br />
|
<br />
|
||||||
<span v-if="assignmentDetail.evaluation_deadline_start">
|
{{ $t("Freigabetermin Bewertungen:") }}
|
||||||
{{ $t("Freigabetermin Bewertungen:") }}
|
{{ formatDueDate(assignmentDetail.evaluation_deadline.start) }}
|
||||||
{{ dayjs(assignmentDetail.evaluation_deadline_start).format("DD.MM.YYYY") }}
|
|
||||||
</span>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
|
|
@ -85,11 +82,11 @@ const assignmentDetail = computed(() =>
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="cockpitStore.courseSessionMembers?.length" class="mt-6">
|
<div v-if="courseSessionDetailResult.filterMembers().length" class="mt-6">
|
||||||
<ul>
|
<ul>
|
||||||
<ItPersonRow
|
<ItPersonRow
|
||||||
v-for="csu in cockpitStore.courseSessionMembers"
|
v-for="csu in courseSessionDetailResult.filterMembers()"
|
||||||
:key="csu.user_id + csu.session_title"
|
:key="csu.user_id"
|
||||||
:name="`${csu.first_name} ${csu.last_name}`"
|
:name="`${csu.first_name} ${csu.last_name}`"
|
||||||
:avatar-url="csu.avatar_url"
|
:avatar-url="csu.avatar_url"
|
||||||
:data-cy="csu.last_name"
|
:data-cy="csu.last_name"
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@
|
||||||
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
||||||
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||||
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables";
|
||||||
import type { AttendanceUserStatus } from "@/gql/graphql";
|
import type { AttendanceUserStatus } from "@/gql/graphql";
|
||||||
import { ATTENDANCE_CHECK_MUTATION } from "@/graphql/mutations";
|
import { ATTENDANCE_CHECK_MUTATION } from "@/graphql/mutations";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
|
||||||
import type { DropdownSelectable } from "@/types";
|
import type { DropdownSelectable } from "@/types";
|
||||||
import { useMutation } from "@urql/vue";
|
import { useMutation } from "@urql/vue";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
@ -16,9 +15,9 @@ import { ATTENDANCE_CHECK_QUERY } from "@/graphql/queries";
|
||||||
import { graphqlClient } from "@/graphql/client";
|
import { graphqlClient } from "@/graphql/client";
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const cockpitStore = useCockpitStore();
|
|
||||||
const courseSession = useCurrentCourseSession();
|
const courseSession = useCurrentCourseSession();
|
||||||
const attendanceMutation = useMutation(ATTENDANCE_CHECK_MUTATION);
|
const attendanceMutation = useMutation(ATTENDANCE_CHECK_MUTATION);
|
||||||
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
const attendanceCourses = computed(() => {
|
const attendanceCourses = computed(() => {
|
||||||
return courseSession.value.attendance_courses;
|
return courseSession.value.attendance_courses;
|
||||||
|
|
@ -167,8 +166,8 @@ watch(
|
||||||
|
|
||||||
<div class="mt-4 flex flex-col bg-white p-6">
|
<div class="mt-4 flex flex-col bg-white p-6">
|
||||||
<div
|
<div
|
||||||
v-for="(csu, index) in cockpitStore.courseSessionMembers"
|
v-for="(csu, index) in courseSessionDetailResult.filterMembers()"
|
||||||
:key="csu.user_id + csu.session_title"
|
:key="csu.user_id"
|
||||||
>
|
>
|
||||||
<ItPersonRow
|
<ItPersonRow
|
||||||
:name="`${csu.first_name} ${csu.last_name}`"
|
:name="`${csu.first_name} ${csu.last_name}`"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.v
|
||||||
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
||||||
import type { LearningPath } from "@/services/learningPath";
|
import type { LearningPath } from "@/services/learningPath";
|
||||||
|
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
import { useCurrentCourseSession, useCourseSessionDetailQuery } from "@/composables";
|
||||||
import SubmissionsOverview from "@/pages/cockpit/cockpitPage/SubmissionsOverview.vue";
|
import SubmissionsOverview from "@/pages/cockpit/cockpitPage/SubmissionsOverview.vue";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
import { useCompetenceStore } from "@/stores/competence";
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
|
|
@ -24,6 +24,7 @@ const competenceStore = useCompetenceStore();
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
const courseSession = useCurrentCourseSession();
|
const courseSession = useCurrentCourseSession();
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
const courseSessionsStore = useCourseSessionsStore();
|
||||||
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
function userCountStatusForCircle(userId: string) {
|
function userCountStatusForCircle(userId: string) {
|
||||||
if (!cockpitStore.currentCircle) return { FAIL: 0, SUCCESS: 0, UNKNOWN: 0 };
|
if (!cockpitStore.currentCircle) return { FAIL: 0, SUCCESS: 0, UNKNOWN: 0 };
|
||||||
|
|
@ -126,12 +127,15 @@ function userCountStatusForCircle(userId: string) {
|
||||||
></SubmissionsOverview>
|
></SubmissionsOverview>
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<!-- progress -->
|
<!-- progress -->
|
||||||
<div v-if="cockpitStore.courseSessionMembers" class="bg-white p-6">
|
<div
|
||||||
|
v-if="courseSessionDetailResult.filterMembers().length > 0"
|
||||||
|
class="bg-white p-6"
|
||||||
|
>
|
||||||
<h1 class="heading-3 mb-5">{{ $t("cockpit.progress") }}</h1>
|
<h1 class="heading-3 mb-5">{{ $t("cockpit.progress") }}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
<ItPersonRow
|
<ItPersonRow
|
||||||
v-for="csu in cockpitStore.courseSessionMembers"
|
v-for="csu in courseSessionDetailResult.filterMembers()"
|
||||||
:key="csu.user_id + csu.session_title"
|
:key="csu.user_id"
|
||||||
:name="`${csu.first_name} ${csu.last_name}`"
|
:name="`${csu.first_name} ${csu.last_name}`"
|
||||||
:avatar-url="csu.avatar_url"
|
:avatar-url="csu.avatar_url"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import log from "loglevel";
|
||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import ItProgress from "@/components/ui/ItProgress.vue";
|
import ItProgress from "@/components/ui/ItProgress.vue";
|
||||||
import { itGet } from "@/fetchHelpers";
|
import { itGet } from "@/fetchHelpers";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCourseSessionDetailQuery } from "@/composables";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSession: CourseSession;
|
courseSession: CourseSession;
|
||||||
|
|
@ -13,12 +13,11 @@ const props = defineProps<{
|
||||||
|
|
||||||
log.debug("FeedbackSubmissionProgress created");
|
log.debug("FeedbackSubmissionProgress created");
|
||||||
|
|
||||||
const cockpitStore = useCockpitStore();
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
const completeFeedbacks = ref(0);
|
const completeFeedbacks = ref(0);
|
||||||
|
|
||||||
const numFeedbacks = computed(() => {
|
const numFeedbacks = computed(() => {
|
||||||
return cockpitStore.courseSessionMembers?.length ?? 0;
|
return courseSessionDetailResult.filterMembers().length;
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
2
|
2
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AssignmentSubmissionProgress from "@/pages/cockpit/cockpitPage/AssignmentSubmissionProgress.vue";
|
import AssignmentSubmissionProgress from "@/pages/cockpit/cockpitPage/AssignmentSubmissionProgress.vue";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import type {
|
import type {
|
||||||
|
|
@ -14,6 +13,7 @@ import { computed } from "vue";
|
||||||
import { useTranslation } from "i18next-vue";
|
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 { useCourseSessionDetailQuery } from "@/composables";
|
||||||
|
|
||||||
interface Submittable {
|
interface Submittable {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
@ -33,8 +33,9 @@ const props = defineProps<{
|
||||||
log.debug("SubmissionsOverview created", props.courseSession.id);
|
log.debug("SubmissionsOverview created", props.courseSession.id);
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const cockpitStore = useCockpitStore();
|
|
||||||
const learningPathStore = useLearningPathStore();
|
const learningPathStore = useLearningPathStore();
|
||||||
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const submittables = computed(() => {
|
const submittables = computed(() => {
|
||||||
|
|
@ -128,7 +129,10 @@ const getIconName = (lc: LearningContent) => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-white px-6 py-2">
|
<div class="bg-white px-6 py-2">
|
||||||
<div v-if="cockpitStore.courseSessionMembers" class="divide-y divide-gray-500">
|
<div
|
||||||
|
v-if="courseSessionDetailResult.filterMembers().length"
|
||||||
|
class="divide-y divide-gray-500"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="submittable in submittables"
|
v-for="submittable in submittables"
|
||||||
:key="submittable.id"
|
:key="submittable.id"
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,11 @@ const router = createRouter({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/course/:courseSlug/test-composable",
|
||||||
|
component: () => import("../pages/TestCourseSessionComposablePage.vue"),
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/course/:courseSlug/learn",
|
path: "/course/:courseSlug/learn",
|
||||||
component: () =>
|
component: () =>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
|
import { useCourseSessionDetailQuery } from "@/composables";
|
||||||
import { itGet } from "@/fetchHelpers";
|
import { itGet } from "@/fetchHelpers";
|
||||||
import type { LearningPath } from "@/services/learningPath";
|
import type { LearningPath } from "@/services/learningPath";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
|
||||||
import { useUserStore } from "@/stores/user";
|
|
||||||
import type {
|
import type {
|
||||||
Assignment,
|
Assignment,
|
||||||
AssignmentCompletion,
|
AssignmentCompletion,
|
||||||
|
|
@ -35,19 +32,17 @@ export async function loadAssignmentCompletionStatusData(
|
||||||
courseSessionId: number,
|
courseSessionId: number,
|
||||||
learningContentId: number
|
learningContentId: number
|
||||||
) {
|
) {
|
||||||
const cockpitStore = useCockpitStore();
|
const courseSessionDetailResult = useCourseSessionDetailQuery();
|
||||||
|
|
||||||
const assignmentCompletionData = (await itGet(
|
const assignmentCompletionData = (await itGet(
|
||||||
`/api/assignment/${assignmentId}/${courseSessionId}/status/`
|
`/api/assignment/${assignmentId}/${courseSessionId}/status/`
|
||||||
)) as UserAssignmentCompletionStatus[];
|
)) as UserAssignmentCompletionStatus[];
|
||||||
|
|
||||||
const courseSessionUsers = await cockpitStore.loadCourseSessionMembers(
|
const members = courseSessionDetailResult.filterMembers();
|
||||||
courseSessionId
|
|
||||||
);
|
|
||||||
|
|
||||||
const gradedUsers: GradedUser[] = [];
|
const gradedUsers: GradedUser[] = [];
|
||||||
const assignmentSubmittedUsers: CourseSessionUser[] = [];
|
const assignmentSubmittedUsers: CourseSessionUser[] = [];
|
||||||
for (const csu of courseSessionUsers) {
|
for (const csu of members) {
|
||||||
const userAssignmentStatus = assignmentCompletionData.find(
|
const userAssignmentStatus = assignmentCompletionData.find(
|
||||||
(s) =>
|
(s) =>
|
||||||
s.assignment_user_id === csu.user_id &&
|
s.assignment_user_id === csu.user_id &&
|
||||||
|
|
@ -70,34 +65,10 @@ export async function loadAssignmentCompletionStatusData(
|
||||||
return {
|
return {
|
||||||
assignmentSubmittedUsers: assignmentSubmittedUsers,
|
assignmentSubmittedUsers: assignmentSubmittedUsers,
|
||||||
gradedUsers: gradedUsers,
|
gradedUsers: gradedUsers,
|
||||||
total: courseSessionUsers.length,
|
total: members.length,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findAssignmentDetail(assignmentId: number) {
|
|
||||||
const learningPathStore = useLearningPathStore();
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const courseSessionsStore = useCourseSessionsStore();
|
|
||||||
|
|
||||||
// TODO: filter by selected circle
|
|
||||||
if (!courseSessionsStore.currentCourseSession) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const learningContents = calcLearningContentAssignments(
|
|
||||||
learningPathStore.learningPathForUser(
|
|
||||||
courseSessionsStore.currentCourseSession.course.slug,
|
|
||||||
userStore.id
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const learningContent = learningContents.find(
|
|
||||||
(lc) => lc.content_assignment_id === assignmentId
|
|
||||||
);
|
|
||||||
|
|
||||||
return courseSessionsStore.findCourseSessionAssignment(learningContent?.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function maxAssignmentPoints(assignment: Assignment) {
|
export function maxAssignmentPoints(assignment: Assignment) {
|
||||||
return sum(assignment.evaluation_tasks.map((task) => task.value.max_points));
|
return sum(assignment.evaluation_tasks.map((task) => task.value.max_points));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import log from "loglevel";
|
||||||
import { useCircleStore } from "@/stores/circle";
|
import { useCircleStore } from "@/stores/circle";
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
|
import type { CourseSessionUser, ExpertSessionUser } from "@/types";
|
||||||
|
import log from "loglevel";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export type CockpitStoreState = {
|
export type CockpitStoreState = {
|
||||||
|
|
@ -26,13 +28,16 @@ export const useCockpitStore = defineStore({
|
||||||
} as CockpitStoreState;
|
} as CockpitStoreState;
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async loadCircles(courseSlug: string, courseSessionId: number) {
|
async loadCircles(
|
||||||
|
courseSlug: string,
|
||||||
|
currentCourseSessionUser: CourseSessionUser | undefined
|
||||||
|
) {
|
||||||
log.debug("loadCircles called", courseSlug, courseSessionId);
|
log.debug("loadCircles called", courseSlug, courseSessionId);
|
||||||
this.currentCourseSlug = courseSlug;
|
this.currentCourseSlug = courseSlug;
|
||||||
|
|
||||||
const f = await courseCircles(this.currentCourseSlug, courseSessionId);
|
const circles = await courseCircles(this.currentCourseSlug, currentCourseSessionUser);
|
||||||
|
|
||||||
this.circles = f.map((c) => {
|
this.circles = circles.map((c) => {
|
||||||
return {
|
return {
|
||||||
id: c.slug,
|
id: c.slug,
|
||||||
name: c.title,
|
name: c.title,
|
||||||
|
|
@ -53,18 +58,6 @@ export const useCockpitStore = defineStore({
|
||||||
async setCurrentCourseCircleFromEvent(event: { id: string }) {
|
async setCurrentCourseCircleFromEvent(event: { id: string }) {
|
||||||
await this.setCurrentCourseCircle(event.id);
|
await this.setCurrentCourseCircle(event.id);
|
||||||
},
|
},
|
||||||
async loadCourseSessionMembers(courseSessionId: number, reload = false) {
|
|
||||||
log.debug("loadCourseSessionMembers called");
|
|
||||||
const users = (await itGetCached(
|
|
||||||
`/api/course/sessions/${courseSessionId}/users/`,
|
|
||||||
{
|
|
||||||
reload: reload,
|
|
||||||
}
|
|
||||||
)) as CourseSessionUser[];
|
|
||||||
|
|
||||||
this.courseSessionMembers = users.filter((user) => user.role === "MEMBER");
|
|
||||||
return this.courseSessionMembers;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
currentCircle: () => {
|
currentCircle: () => {
|
||||||
|
|
@ -81,18 +74,15 @@ export const useCockpitStore = defineStore({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
async function courseCircles(courseSlug: string, courseSessionId: number) {
|
async function courseCircles(
|
||||||
|
courseSlug: string,
|
||||||
|
currentCourseSessionUser: CourseSessionUser | undefined
|
||||||
|
) {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const userId = userStore.id;
|
const userId = userStore.id;
|
||||||
|
|
||||||
const users = (await itGetCached(`/api/course/sessions/${courseSessionId}/users/`, {
|
if (currentCourseSessionUser && currentCourseSessionUser.role === "EXPERT") {
|
||||||
reload: false,
|
const expert = currentCourseSessionUser as ExpertSessionUser;
|
||||||
})) as CourseSessionUser[];
|
|
||||||
|
|
||||||
// First check if current user is an expert for this course session
|
|
||||||
const currentUser = users.find((user) => user.user_id === userId);
|
|
||||||
if (currentUser && currentUser.role === "EXPERT") {
|
|
||||||
const expert = currentUser as ExpertSessionUser;
|
|
||||||
return expert.circles;
|
return expert.circles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,6 @@
|
||||||
import { itGetCached, itPost } from "@/fetchHelpers";
|
import { itGetCached, itPost } from "@/fetchHelpers";
|
||||||
import { deleteCircleDocument } from "@/services/files";
|
import { deleteCircleDocument } from "@/services/files";
|
||||||
import type {
|
import type { CircleDocument, CourseSession, DueDate } from "@/types";
|
||||||
CircleDocument,
|
|
||||||
CourseSession,
|
|
||||||
CourseSessionAssignment,
|
|
||||||
CourseSessionAttendanceCourse,
|
|
||||||
CourseSessionEdoniqTest,
|
|
||||||
CourseSessionUser,
|
|
||||||
DueDate,
|
|
||||||
ExpertSessionUser,
|
|
||||||
} from "@/types";
|
|
||||||
import eventBus from "@/utils/eventBus";
|
import eventBus from "@/utils/eventBus";
|
||||||
import { useRouteLookups } from "@/utils/route";
|
import { useRouteLookups } from "@/utils/route";
|
||||||
import { useLocalStorage } from "@vueuse/core";
|
import { useLocalStorage } from "@vueuse/core";
|
||||||
|
|
@ -18,7 +9,6 @@ import uniqBy from "lodash/uniqBy";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { useCircleStore } from "./circle";
|
|
||||||
import { useUserStore } from "./user";
|
import { useUserStore } from "./user";
|
||||||
|
|
||||||
const SELECTED_COURSE_SESSIONS_KEY = "selectedCourseSessionMap";
|
const SELECTED_COURSE_SESSIONS_KEY = "selectedCourseSessionMap";
|
||||||
|
|
@ -39,10 +29,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
// TODO: refactor after implementing of Klassenkonzept
|
// TODO: refactor after implementing of Klassenkonzept
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
allCourseSessions.value.map(async (cs) => {
|
allCourseSessions.value.map(async (cs) => {
|
||||||
const users = (await itGetCached(`/api/course/sessions/${cs.id}/users/`, {
|
|
||||||
reload: reload,
|
|
||||||
})) as CourseSessionUser[];
|
|
||||||
cs.users = users;
|
|
||||||
sortDueDates(cs.due_dates);
|
sortDueDates(cs.due_dates);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
@ -161,56 +147,56 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
return Boolean(isCourseExpert && (inLearningPath() || inCompetenceProfile()));
|
return Boolean(isCourseExpert && (inLearningPath() || inCompetenceProfile()));
|
||||||
});
|
});
|
||||||
|
|
||||||
const circleExperts = computed(() => {
|
// const circleExperts = computed(() => {
|
||||||
const circleStore = useCircleStore();
|
// const circleStore = useCircleStore();
|
||||||
const circleTranslationKey = circleStore.circle?.translation_key;
|
// const circleTranslationKey = circleStore.circle?.translation_key;
|
||||||
|
//
|
||||||
|
// if (currentCourseSession.value && circleTranslationKey) {
|
||||||
|
// return currentCourseSession.value.users.filter((u) => {
|
||||||
|
// if (u.role === "EXPERT") {
|
||||||
|
// return (u as ExpertSessionUser).circles
|
||||||
|
// .map((c) => c.translation_key)
|
||||||
|
// .includes(circleTranslationKey);
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
|
// }) as ExpertSessionUser[];
|
||||||
|
// }
|
||||||
|
// return [];
|
||||||
|
// });
|
||||||
|
|
||||||
if (currentCourseSession.value && circleTranslationKey) {
|
// const canUploadCircleDocuments = computed(() => {
|
||||||
return currentCourseSession.value.users.filter((u) => {
|
// const userStore = useUserStore();
|
||||||
if (u.role === "EXPERT") {
|
// return (
|
||||||
return (u as ExpertSessionUser).circles
|
// circleExperts.value.filter((expert) => expert.user_id === userStore.id).length > 0
|
||||||
.map((c) => c.translation_key)
|
// );
|
||||||
.includes(circleTranslationKey);
|
// });
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}) as ExpertSessionUser[];
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
|
|
||||||
const canUploadCircleDocuments = computed(() => {
|
// const circleDocuments = computed(() => {
|
||||||
|
// const circleStore = useCircleStore();
|
||||||
|
//
|
||||||
|
// return (
|
||||||
|
// circleStore.circle?.learningSequences
|
||||||
|
// .map((ls) => ({ id: ls.id, title: ls.title, documents: [] }))
|
||||||
|
// .map((ls: { id: number; title: string; documents: CircleDocument[] }) => {
|
||||||
|
// if (currentCourseSession.value === undefined) {
|
||||||
|
// return ls;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for (const document of currentCourseSession.value.documents) {
|
||||||
|
// if (document.learning_sequence === ls.id) {
|
||||||
|
// ls.documents.push(document);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return ls;
|
||||||
|
// })
|
||||||
|
// .filter((ls) => ls.documents.length > 0) || []
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
|
||||||
|
function hasCockpit(courseSession: CourseSession) {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
return (
|
return (
|
||||||
circleExperts.value.filter((expert) => expert.user_id === userStore.id).length > 0
|
userStore.course_session_experts.includes(courseSession.id) ||
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const circleDocuments = computed(() => {
|
|
||||||
const circleStore = useCircleStore();
|
|
||||||
|
|
||||||
return (
|
|
||||||
circleStore.circle?.learningSequences
|
|
||||||
.map((ls) => ({ id: ls.id, title: ls.title, documents: [] }))
|
|
||||||
.map((ls: { id: number; title: string; documents: CircleDocument[] }) => {
|
|
||||||
if (currentCourseSession.value === undefined) {
|
|
||||||
return ls;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const document of currentCourseSession.value.documents) {
|
|
||||||
if (document.learning_sequence === ls.id) {
|
|
||||||
ls.documents.push(document);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ls;
|
|
||||||
})
|
|
||||||
.filter((ls) => ls.documents.length > 0) || []
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
function hasCockpit(couseSession: CourseSession) {
|
|
||||||
const userStore = useUserStore();
|
|
||||||
return (
|
|
||||||
userStore.course_session_experts.includes(couseSession.id) ||
|
|
||||||
userStore.is_superuser
|
userStore.is_superuser
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -263,35 +249,35 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function findAttendanceCourse(
|
// function findAttendanceCourse(
|
||||||
contentId: number
|
// contentId: number
|
||||||
): CourseSessionAttendanceCourse | undefined {
|
// ): CourseSessionAttendanceCourse | undefined {
|
||||||
if (currentCourseSession.value) {
|
// if (currentCourseSession.value) {
|
||||||
return currentCourseSession.value.attendance_courses.find(
|
// return currentCourseSession.value.attendance_courses.find(
|
||||||
(attendanceCourse) => attendanceCourse.learning_content_id === contentId
|
// (attendanceCourse) => attendanceCourse.learning_content_id === contentId
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
function findCourseSessionAssignment(
|
// function findCourseSessionAssignment(
|
||||||
contentId?: number
|
// contentId?: number
|
||||||
): CourseSessionAssignment | undefined {
|
// ): CourseSessionAssignment | undefined {
|
||||||
if (contentId && currentCourseSession.value) {
|
// if (contentId && currentCourseSession.value) {
|
||||||
return currentCourseSession.value.assignments.find(
|
// return currentCourseSession.value.assignments.find(
|
||||||
(a) => a.learning_content_id === contentId
|
// (a) => a.learning_content_id === contentId
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
function findCourseSessionEdoniqTest(
|
// function findCourseSessionEdoniqTest(
|
||||||
contentId?: number
|
// contentId?: number
|
||||||
): CourseSessionEdoniqTest | undefined {
|
// ): CourseSessionEdoniqTest | undefined {
|
||||||
if (contentId && currentCourseSession.value) {
|
// if (contentId && currentCourseSession.value) {
|
||||||
return currentCourseSession.value.edoniq_tests.find(
|
// return currentCourseSession.value.edoniq_tests.find(
|
||||||
(a) => a.learning_content_id === contentId
|
// (a) => a.learning_content_id === contentId
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uniqueCourseSessionsByCourse,
|
uniqueCourseSessionsByCourse,
|
||||||
|
|
@ -302,15 +288,9 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
|
||||||
hasCockpit,
|
hasCockpit,
|
||||||
hasCourseSessionPreview,
|
hasCourseSessionPreview,
|
||||||
currentCourseSessionHasCockpit,
|
currentCourseSessionHasCockpit,
|
||||||
canUploadCircleDocuments,
|
|
||||||
circleDocuments,
|
|
||||||
circleExperts,
|
|
||||||
addDocument,
|
addDocument,
|
||||||
startUpload,
|
startUpload,
|
||||||
removeDocument,
|
removeDocument,
|
||||||
findAttendanceCourse,
|
|
||||||
findCourseSessionAssignment,
|
|
||||||
findCourseSessionEdoniqTest,
|
|
||||||
allDueDates,
|
allDueDates,
|
||||||
|
|
||||||
// use `useCurrentCourseSession` whenever possible
|
// use `useCurrentCourseSession` whenever possible
|
||||||
|
|
|
||||||
|
|
@ -479,13 +479,23 @@ export interface CourseSessionAttendanceCourse {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CourseSessionAssignment {
|
export interface CourseSessionAssignment {
|
||||||
id: number;
|
id: string;
|
||||||
course_session_id: number;
|
submission_deadline: {
|
||||||
learning_content_id: number;
|
id: string;
|
||||||
submission_deadline_id: number;
|
start: string;
|
||||||
submission_deadline_start: string;
|
};
|
||||||
evaluation_deadline_id: number;
|
evaluation_deadline: {
|
||||||
evaluation_deadline_start: string;
|
id: string;
|
||||||
|
start: string;
|
||||||
|
};
|
||||||
|
learning_content: {
|
||||||
|
id: string;
|
||||||
|
content_assignment: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
assignment_type: AssignmentType;
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CourseSessionEdoniqTest {
|
export interface CourseSessionEdoniqTest {
|
||||||
|
|
@ -504,29 +514,34 @@ export interface CourseSession {
|
||||||
title: string;
|
title: string;
|
||||||
start_date: string;
|
start_date: string;
|
||||||
end_date: string;
|
end_date: string;
|
||||||
learning_path_url: string;
|
// learning_path_url: string;
|
||||||
cockpit_url: string;
|
// cockpit_url: string;
|
||||||
competence_url: string;
|
// competence_url: string;
|
||||||
course_url: string;
|
course_url: string;
|
||||||
media_library_url: string;
|
// media_library_url: string;
|
||||||
attendance_courses: CourseSessionAttendanceCourse[];
|
// attendance_courses: CourseSessionAttendanceCourse[];
|
||||||
assignments: CourseSessionAssignment[];
|
// assignments: CourseSessionAssignment[];
|
||||||
edoniq_tests: CourseSessionEdoniqTest[];
|
// edoniq_tests: CourseSessionEdoniqTest[];
|
||||||
documents: CircleDocument[];
|
// documents: CircleDocument[];
|
||||||
users: CourseSessionUser[];
|
// users: CourseSessionUser[];
|
||||||
due_dates: DueDate[];
|
due_dates: DueDate[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Role = "MEMBER" | "EXPERT" | "TUTOR";
|
export type Role = "MEMBER" | "EXPERT" | "TUTOR";
|
||||||
|
|
||||||
export interface CourseSessionUser {
|
export interface CourseSessionUser {
|
||||||
session_title: string;
|
|
||||||
user_id: string;
|
user_id: string;
|
||||||
first_name: string;
|
first_name: string;
|
||||||
last_name: string;
|
last_name: string;
|
||||||
email: string;
|
email: string;
|
||||||
avatar_url: string;
|
avatar_url: string;
|
||||||
role: Role;
|
role: Role;
|
||||||
|
circles: {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
slug: string;
|
||||||
|
translation_key: string;
|
||||||
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExpertSessionUser extends CourseSessionUser {
|
export interface ExpertSessionUser extends CourseSessionUser {
|
||||||
|
|
@ -539,6 +554,17 @@ export interface ExpertSessionUser extends CourseSessionUser {
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CourseSessionDetail {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
course: {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
assignments: CourseSessionAssignment[];
|
||||||
|
users: CourseSessionUser[];
|
||||||
|
}
|
||||||
|
|
||||||
// document upload
|
// document upload
|
||||||
export interface DocumentUploadData {
|
export interface DocumentUploadData {
|
||||||
file: File | null;
|
file: File | null;
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,30 @@ export function assertUnreachable(msg: string): never {
|
||||||
throw new Error("Didn't expect to get here, " + msg);
|
throw new Error("Didn't expect to get here, " + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCompetenceBaseUrl(courseSession: CourseSession): string {
|
function createCourseUrl(
|
||||||
return courseSession.competence_url.replace(
|
courseSession: CourseSession | undefined,
|
||||||
// TODO: remove the `competence_url` with url to Navi...
|
specificSub: string
|
||||||
"/competences",
|
): string {
|
||||||
""
|
if (!courseSession) {
|
||||||
);
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (["learn", "media", "competence"].includes(specificSub)) {
|
||||||
|
return `${courseSession.course_url}/${specificSub}`;
|
||||||
|
}
|
||||||
|
return courseSession.course_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCompetenceNaviUrl(courseSession: CourseSession | undefined): string {
|
||||||
|
return createCourseUrl(courseSession, "competence");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMediaCenterUrl(courseSession: CourseSession | undefined): string {
|
||||||
|
return createCourseUrl(courseSession, "media");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLearningPathUrl(courseSession: CourseSession | undefined): string {
|
||||||
|
return createCourseUrl(courseSession, "learn");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAssignmentTypeTitle(assignmentType: AssignmentType): string {
|
export function getAssignmentTypeTitle(assignmentType: AssignmentType): string {
|
||||||
|
|
|
||||||
|
|
@ -110,9 +110,9 @@ urlpatterns = [
|
||||||
|
|
||||||
# course
|
# course
|
||||||
path(r"api/course/sessions/", get_course_sessions, name="get_course_sessions"),
|
path(r"api/course/sessions/", get_course_sessions, name="get_course_sessions"),
|
||||||
path(r"api/course/sessions/<signed_int:course_session_id>/users/",
|
# path(r"api/course/sessions/<signed_int:course_session_id>/users/",
|
||||||
get_course_session_users,
|
# get_course_session_users,
|
||||||
name="get_course_session_users"),
|
# name="get_course_session_users"),
|
||||||
path(r"api/course/page/<slug_or_id>/", course_page_api_view,
|
path(r"api/course/page/<slug_or_id>/", course_page_api_view,
|
||||||
name="course_page_api_view"),
|
name="course_page_api_view"),
|
||||||
path(r"api/course/completion/mark/", mark_course_completion_view,
|
path(r"api/course/completion/mark/", mark_course_completion_view,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,22 @@
|
||||||
import graphene
|
import graphene
|
||||||
|
|
||||||
from vbv_lernwelt.course.graphql.types import CourseObjectType
|
from vbv_lernwelt.course.graphql.types import CourseObjectType, CourseSessionObjectType
|
||||||
from vbv_lernwelt.course.models import Course
|
from vbv_lernwelt.course.models import Course, CourseSession
|
||||||
from vbv_lernwelt.course.permissions import has_course_access
|
from vbv_lernwelt.course.permissions import has_course_access
|
||||||
|
|
||||||
|
|
||||||
class CourseQuery(graphene.ObjectType):
|
class CourseQuery(graphene.ObjectType):
|
||||||
course = graphene.Field(CourseObjectType, id=graphene.Int())
|
course = graphene.Field(CourseObjectType, id=graphene.ID())
|
||||||
|
course_session = graphene.Field(CourseSessionObjectType, id=graphene.ID())
|
||||||
|
|
||||||
def resolve_course(root, info, id):
|
def resolve_course(root, info, id):
|
||||||
course = Course.objects.get(pk=id)
|
course = Course.objects.get(pk=id)
|
||||||
if has_course_access(info.context.user, course):
|
if has_course_access(info.context.user, course):
|
||||||
return course
|
return course
|
||||||
raise PermissionError("You do not have access to this course")
|
raise PermissionError("You do not have access to this course")
|
||||||
|
|
||||||
|
def resolve_course_session(root, info, id):
|
||||||
|
course_session = CourseSession.objects.get(pk=id)
|
||||||
|
if has_course_access(info.context.user, course_session.course):
|
||||||
|
return course_session
|
||||||
|
raise PermissionError("You do not have access to this course session")
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,24 @@ from typing import Type
|
||||||
|
|
||||||
import graphene
|
import graphene
|
||||||
import structlog
|
import structlog
|
||||||
|
from graphene import ObjectType
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
from graphql import GraphQLError
|
from graphql import GraphQLError
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
|
|
||||||
from vbv_lernwelt.course.models import Course, CourseBasePage, CoursePage
|
from vbv_lernwelt.course.models import Course, CourseBasePage, CoursePage, \
|
||||||
|
CourseSession, CourseSessionUser
|
||||||
from vbv_lernwelt.course.permissions import has_course_access
|
from vbv_lernwelt.course.permissions import has_course_access
|
||||||
|
from vbv_lernwelt.course_session.graphql.types import (
|
||||||
|
CourseSessionAttendanceCourseObjectType,
|
||||||
|
CourseSessionAssignmentObjectType,
|
||||||
|
CourseSessionEdoniqTestObjectType,
|
||||||
|
)
|
||||||
|
from vbv_lernwelt.course_session.models import (
|
||||||
|
CourseSessionAttendanceCourse,
|
||||||
|
CourseSessionAssignment,
|
||||||
|
CourseSessionEdoniqTest,
|
||||||
|
)
|
||||||
from vbv_lernwelt.learnpath.graphql.types import LearningPathObjectType
|
from vbv_lernwelt.learnpath.graphql.types import LearningPathObjectType
|
||||||
|
|
||||||
logger = structlog.get_logger(__name__)
|
logger = structlog.get_logger(__name__)
|
||||||
|
|
@ -74,3 +86,89 @@ class CourseObjectType(DjangoObjectType):
|
||||||
|
|
||||||
def resolve_learning_path(self, info):
|
def resolve_learning_path(self, info):
|
||||||
return self.get_learning_path()
|
return self.get_learning_path()
|
||||||
|
|
||||||
|
|
||||||
|
class CourseSessionUserExpertCircleType(ObjectType):
|
||||||
|
id = graphene.ID()
|
||||||
|
title = graphene.String()
|
||||||
|
slug = graphene.String()
|
||||||
|
|
||||||
|
|
||||||
|
class CourseSessionUserObjectsType(DjangoObjectType):
|
||||||
|
user_id = graphene.UUID()
|
||||||
|
first_name = graphene.String()
|
||||||
|
last_name = graphene.String()
|
||||||
|
email = graphene.String()
|
||||||
|
avatar_url = graphene.String()
|
||||||
|
role = graphene.String()
|
||||||
|
circles = graphene.List(CourseSessionUserExpertCircleType)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = CourseSessionUser
|
||||||
|
fields = (
|
||||||
|
"id",
|
||||||
|
"user_id",
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"email",
|
||||||
|
"avatar_url",
|
||||||
|
"role",
|
||||||
|
)
|
||||||
|
|
||||||
|
def resolve_user_id(self, info):
|
||||||
|
return self.user.id
|
||||||
|
|
||||||
|
def resolve_first_name(self, info):
|
||||||
|
return self.user.first_name
|
||||||
|
|
||||||
|
def resolve_last_name(self, info):
|
||||||
|
return self.user.last_name
|
||||||
|
|
||||||
|
def resolve_email(self, info):
|
||||||
|
return self.user.email
|
||||||
|
|
||||||
|
def resolve_avatar_url(self, info):
|
||||||
|
return self.user.avatar_url
|
||||||
|
|
||||||
|
def resolve_role(self, info):
|
||||||
|
return self.role
|
||||||
|
|
||||||
|
def resolve_circles(self, info):
|
||||||
|
return self.expert.all().values(
|
||||||
|
"id", "title", "slug", "translation_key"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CourseSessionObjectType(DjangoObjectType):
|
||||||
|
attendance_courses = graphene.List(CourseSessionAttendanceCourseObjectType)
|
||||||
|
assignments = graphene.List(CourseSessionAssignmentObjectType)
|
||||||
|
edoniq_tests = graphene.List(CourseSessionEdoniqTestObjectType)
|
||||||
|
users = graphene.List(CourseSessionUserObjectsType)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = CourseSession
|
||||||
|
fields = (
|
||||||
|
"id",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"course",
|
||||||
|
"title",
|
||||||
|
"start_date",
|
||||||
|
"end_date",
|
||||||
|
"attendance_courses",
|
||||||
|
"users",
|
||||||
|
)
|
||||||
|
|
||||||
|
def resolve_attendance_courses(self, info):
|
||||||
|
return CourseSessionAttendanceCourse.objects.filter(course_session=self)
|
||||||
|
|
||||||
|
def resolve_assignments(self, info):
|
||||||
|
return CourseSessionAssignment.objects.filter(course_session=self)
|
||||||
|
|
||||||
|
def resolve_edoniq_test(self, info):
|
||||||
|
return CourseSessionEdoniqTest.objects.filter(course_session=self)
|
||||||
|
|
||||||
|
def resolve_users(self, info):
|
||||||
|
return CourseSessionUser.objects.filter(
|
||||||
|
course_session_id=self.id
|
||||||
|
).distinct()
|
||||||
|
|
|
||||||
|
|
@ -56,14 +56,15 @@ class CourseCompletionSerializer(serializers.ModelSerializer):
|
||||||
class CourseSessionSerializer(serializers.ModelSerializer):
|
class CourseSessionSerializer(serializers.ModelSerializer):
|
||||||
course = serializers.SerializerMethodField()
|
course = serializers.SerializerMethodField()
|
||||||
course_url = serializers.SerializerMethodField()
|
course_url = serializers.SerializerMethodField()
|
||||||
learning_path_url = serializers.SerializerMethodField()
|
# learning_path_url = serializers.SerializerMethodField()
|
||||||
cockpit_url = serializers.SerializerMethodField()
|
# cockpit_url = serializers.SerializerMethodField()
|
||||||
competence_url = serializers.SerializerMethodField()
|
# competence_url = serializers.SerializerMethodField()
|
||||||
media_library_url = serializers.SerializerMethodField()
|
# media_library_url = serializers.SerializerMethodField()
|
||||||
documents = serializers.SerializerMethodField()
|
# documents = serializers.SerializerMethodField()
|
||||||
attendance_courses = serializers.SerializerMethodField()
|
# attendance_courses = serializers.SerializerMethodField()
|
||||||
assignments = serializers.SerializerMethodField()
|
# assignments = serializers.SerializerMethodField()
|
||||||
edoniq_tests = serializers.SerializerMethodField()
|
# edoniq_tests = serializers.SerializerMethodField()
|
||||||
|
|
||||||
due_dates = serializers.SerializerMethodField()
|
due_dates = serializers.SerializerMethodField()
|
||||||
|
|
||||||
def get_course(self, obj):
|
def get_course(self, obj):
|
||||||
|
|
@ -119,16 +120,16 @@ class CourseSessionSerializer(serializers.ModelSerializer):
|
||||||
"title",
|
"title",
|
||||||
"start_date",
|
"start_date",
|
||||||
"end_date",
|
"end_date",
|
||||||
"additional_json_data",
|
# "additional_json_data",
|
||||||
"attendance_courses",
|
# "attendance_courses",
|
||||||
"assignments",
|
# "assignments",
|
||||||
"edoniq_tests",
|
# "edoniq_tests",
|
||||||
"learning_path_url",
|
# "learning_path_url",
|
||||||
"cockpit_url",
|
# "cockpit_url",
|
||||||
"competence_url",
|
# "competence_url",
|
||||||
"media_library_url",
|
# "media_library_url",
|
||||||
"course_url",
|
"course_url",
|
||||||
"documents",
|
# "documents",
|
||||||
"due_dates",
|
"due_dates",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ from rest_framework.response import Response
|
||||||
from wagtail.models import Page
|
from wagtail.models import Page
|
||||||
|
|
||||||
from vbv_lernwelt.core.utils import get_django_content_type
|
from vbv_lernwelt.core.utils import get_django_content_type
|
||||||
|
|
||||||
from vbv_lernwelt.course.models import (
|
from vbv_lernwelt.course.models import (
|
||||||
CircleDocument,
|
CircleDocument,
|
||||||
CourseCompletion,
|
CourseCompletion,
|
||||||
|
|
@ -135,7 +134,9 @@ def mark_course_completion_view(request):
|
||||||
@api_view(["GET"])
|
@api_view(["GET"])
|
||||||
def get_course_sessions(request):
|
def get_course_sessions(request):
|
||||||
try:
|
try:
|
||||||
course_sessions = course_sessions_for_user_qs(request.user)
|
course_sessions = course_sessions_for_user_qs(request.user).prefetch_related(
|
||||||
|
"course"
|
||||||
|
)
|
||||||
return Response(
|
return Response(
|
||||||
status=200, data=CourseSessionSerializer(course_sessions, many=True).data
|
status=200, data=CourseSessionSerializer(course_sessions, many=True).data
|
||||||
)
|
)
|
||||||
|
|
@ -149,7 +150,9 @@ def get_course_sessions(request):
|
||||||
@api_view(["GET"])
|
@api_view(["GET"])
|
||||||
def get_course_session_users(request, course_session_id):
|
def get_course_session_users(request, course_session_id):
|
||||||
try:
|
try:
|
||||||
qs = CourseSessionUser.objects.filter(course_session_id=course_session_id)
|
qs = CourseSessionUser.objects.filter(
|
||||||
|
course_session_id=course_session_id
|
||||||
|
).distinct()
|
||||||
|
|
||||||
user_data = [csu.to_dict() for csu in qs]
|
user_data = [csu.to_dict() for csu in qs]
|
||||||
return Response(status=200, data=user_data)
|
return Response(status=200, data=user_data)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ import structlog
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
|
|
||||||
from vbv_lernwelt.course.permissions import has_course_access
|
from vbv_lernwelt.course.permissions import has_course_access
|
||||||
from vbv_lernwelt.course_session.graphql.types import CourseSessionAttendanceCourseType
|
from vbv_lernwelt.course_session.graphql.types import (
|
||||||
|
CourseSessionAttendanceCourseObjectType,
|
||||||
|
)
|
||||||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
||||||
from vbv_lernwelt.course_session.services.attendance import (
|
from vbv_lernwelt.course_session.services.attendance import (
|
||||||
AttendanceUserStatus,
|
AttendanceUserStatus,
|
||||||
|
|
@ -21,7 +23,9 @@ class AttendanceUserInputType(graphene.InputObjectType):
|
||||||
|
|
||||||
|
|
||||||
class AttendanceCourseUserMutation(graphene.Mutation):
|
class AttendanceCourseUserMutation(graphene.Mutation):
|
||||||
course_session_attendance_course = graphene.Field(CourseSessionAttendanceCourseType)
|
course_session_attendance_course = graphene.Field(
|
||||||
|
CourseSessionAttendanceCourseObjectType
|
||||||
|
)
|
||||||
|
|
||||||
class Input:
|
class Input:
|
||||||
id = graphene.ID(required=True)
|
id = graphene.ID(required=True)
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,15 @@ from rest_framework.exceptions import PermissionDenied
|
||||||
|
|
||||||
from vbv_lernwelt.course.models import CourseSession
|
from vbv_lernwelt.course.models import CourseSession
|
||||||
from vbv_lernwelt.course.permissions import has_course_access, is_course_session_expert
|
from vbv_lernwelt.course.permissions import has_course_access, is_course_session_expert
|
||||||
from vbv_lernwelt.course_session.graphql.types import CourseSessionAttendanceCourseType
|
from vbv_lernwelt.course_session.graphql.types import (
|
||||||
|
CourseSessionAttendanceCourseObjectType,
|
||||||
|
)
|
||||||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
||||||
|
|
||||||
|
|
||||||
class CourseSessionQuery(object):
|
class CourseSessionQuery(object):
|
||||||
course_session_attendance_course = graphene.Field(
|
course_session_attendance_course = graphene.Field(
|
||||||
CourseSessionAttendanceCourseType,
|
CourseSessionAttendanceCourseObjectType,
|
||||||
id=graphene.ID(required=True),
|
id=graphene.ID(required=True),
|
||||||
assignment_user_id=graphene.ID(required=False),
|
assignment_user_id=graphene.ID(required=False),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,21 @@
|
||||||
import graphene
|
import graphene
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
|
|
||||||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
from vbv_lernwelt.course.permissions import is_course_session_expert
|
||||||
|
from vbv_lernwelt.course_session.models import (
|
||||||
|
CourseSessionAttendanceCourse,
|
||||||
|
CourseSessionAssignment,
|
||||||
|
)
|
||||||
from vbv_lernwelt.course_session.services.attendance import AttendanceUserStatus
|
from vbv_lernwelt.course_session.services.attendance import AttendanceUserStatus
|
||||||
|
from vbv_lernwelt.duedate.graphql.types import DueDateObjectType
|
||||||
|
from vbv_lernwelt.learnpath.graphql.types import (
|
||||||
|
LearningContentAssignmentObjectType,
|
||||||
|
LearningContentAttendanceCourseObjectType,
|
||||||
|
LearningContentEdoniqTestObjectType,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AttendanceUserType(graphene.ObjectType):
|
class AttendanceUserObjectType(graphene.ObjectType):
|
||||||
user_id = graphene.UUID(required=True)
|
user_id = graphene.UUID(required=True)
|
||||||
status = graphene.Field(
|
status = graphene.Field(
|
||||||
graphene.Enum.from_enum(AttendanceUserStatus), required=True
|
graphene.Enum.from_enum(AttendanceUserStatus), required=True
|
||||||
|
|
@ -15,15 +25,14 @@ class AttendanceUserType(graphene.ObjectType):
|
||||||
email = graphene.String()
|
email = graphene.String()
|
||||||
|
|
||||||
|
|
||||||
class CourseSessionAttendanceCourseType(DjangoObjectType):
|
class CourseSessionAttendanceCourseObjectType(DjangoObjectType):
|
||||||
course_session_id = graphene.ID(source="course_session_id")
|
course_session_id = graphene.ID(source="course_session_id")
|
||||||
learning_content_id = graphene.ID(source="learning_content_id")
|
learning_content_id = graphene.ID(source="learning_content_id")
|
||||||
due_date_id = graphene.ID(source="due_date_id")
|
|
||||||
end = graphene.DateTime()
|
|
||||||
start = graphene.DateTime()
|
|
||||||
attendance_user_list = graphene.List(
|
attendance_user_list = graphene.List(
|
||||||
AttendanceUserType, source="attendance_user_list"
|
AttendanceUserObjectType, source="attendance_user_list"
|
||||||
)
|
)
|
||||||
|
due_date = graphene.Field(DueDateObjectType)
|
||||||
|
learning_content = graphene.Field(LearningContentAttendanceCourseObjectType)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CourseSessionAttendanceCourse
|
model = CourseSessionAttendanceCourse
|
||||||
|
|
@ -31,19 +40,49 @@ class CourseSessionAttendanceCourseType(DjangoObjectType):
|
||||||
"id",
|
"id",
|
||||||
"course_session_id",
|
"course_session_id",
|
||||||
"learning_content_id",
|
"learning_content_id",
|
||||||
"due_date_id",
|
"learning_content",
|
||||||
"location",
|
"location",
|
||||||
"trainer",
|
"trainer",
|
||||||
"start",
|
"due_date",
|
||||||
"end",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def resolve_start(self, info):
|
def resolve_attendance_user_list(self, info):
|
||||||
if self.due_date is None:
|
if is_course_session_expert(info.context.user, self.course_session_id):
|
||||||
return None
|
return self.attendance_user_list
|
||||||
return self.due_date.start
|
return []
|
||||||
|
|
||||||
def resolve_end(self, info):
|
|
||||||
if self.due_date is None:
|
class CourseSessionAssignmentObjectType(DjangoObjectType):
|
||||||
return None
|
course_session_id = graphene.ID(source="course_session_id")
|
||||||
return self.due_date.end
|
learning_content_id = graphene.ID(source="learning_content_id")
|
||||||
|
submission_deadline = graphene.Field(DueDateObjectType)
|
||||||
|
evaluation_deadline = graphene.Field(DueDateObjectType)
|
||||||
|
learning_content = graphene.Field(LearningContentAssignmentObjectType)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = CourseSessionAssignment
|
||||||
|
fields = (
|
||||||
|
"id",
|
||||||
|
"course_session_id",
|
||||||
|
"learning_content_id",
|
||||||
|
"submission_deadline",
|
||||||
|
"evaluation_deadline",
|
||||||
|
"learning_content",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CourseSessionEdoniqTestObjectType(DjangoObjectType):
|
||||||
|
course_session_id = graphene.ID(source="course_session_id")
|
||||||
|
learning_content_id = graphene.ID(source="learning_content_id")
|
||||||
|
deadline = graphene.Field(DueDateObjectType)
|
||||||
|
learning_content = graphene.Field(LearningContentEdoniqTestObjectType)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = CourseSessionAssignment
|
||||||
|
fields = (
|
||||||
|
"id",
|
||||||
|
"course_session_id",
|
||||||
|
"learning_content_id",
|
||||||
|
"deadline",
|
||||||
|
"learning_content",
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
from graphene_django import DjangoObjectType
|
||||||
|
|
||||||
|
from vbv_lernwelt.duedate.models import DueDate
|
||||||
|
|
||||||
|
|
||||||
|
class DueDateObjectType(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = DueDate
|
||||||
|
fields = (
|
||||||
|
"id",
|
||||||
|
"start",
|
||||||
|
"end",
|
||||||
|
"manual_override_fields",
|
||||||
|
"title",
|
||||||
|
"assignment_type_translation_key",
|
||||||
|
"date_type_translation_key",
|
||||||
|
"subtitle",
|
||||||
|
"url",
|
||||||
|
"course_session",
|
||||||
|
"page",
|
||||||
|
)
|
||||||
|
|
@ -4,7 +4,7 @@ from vbv_lernwelt.duedate.models import DueDate
|
||||||
|
|
||||||
|
|
||||||
class DueDateSerializer(serializers.ModelSerializer):
|
class DueDateSerializer(serializers.ModelSerializer):
|
||||||
circle = serializers.SerializerMethodField()
|
# circle = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DueDate
|
model = DueDate
|
||||||
|
|
@ -20,7 +20,7 @@ class DueDateSerializer(serializers.ModelSerializer):
|
||||||
"url_expert",
|
"url_expert",
|
||||||
"course_session",
|
"course_session",
|
||||||
"page",
|
"page",
|
||||||
"circle",
|
# "circle",
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_circle(self, obj):
|
def get_circle(self, obj):
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ from vbv_lernwelt.learnpath.graphql.types import (
|
||||||
LearningContentMediaLibraryObjectType,
|
LearningContentMediaLibraryObjectType,
|
||||||
LearningContentPlaceholderObjectType,
|
LearningContentPlaceholderObjectType,
|
||||||
LearningContentRichTextObjectType,
|
LearningContentRichTextObjectType,
|
||||||
LearningContentTestObjectType,
|
LearningContentEdoniqTestObjectType,
|
||||||
LearningContentVideoObjectType,
|
LearningContentVideoObjectType,
|
||||||
LearningPathObjectType,
|
LearningPathObjectType,
|
||||||
)
|
)
|
||||||
|
|
@ -58,7 +58,7 @@ class LearningPathQuery:
|
||||||
)
|
)
|
||||||
learning_content_placeholder = graphene.Field(LearningContentPlaceholderObjectType)
|
learning_content_placeholder = graphene.Field(LearningContentPlaceholderObjectType)
|
||||||
learning_content_rich_text = graphene.Field(LearningContentRichTextObjectType)
|
learning_content_rich_text = graphene.Field(LearningContentRichTextObjectType)
|
||||||
learning_content_test = graphene.Field(LearningContentTestObjectType)
|
learning_content_test = graphene.Field(LearningContentEdoniqTestObjectType)
|
||||||
learning_content_video = graphene.Field(LearningContentVideoObjectType)
|
learning_content_video = graphene.Field(LearningContentVideoObjectType)
|
||||||
learning_content_document_list = graphene.Field(
|
learning_content_document_list = graphene.Field(
|
||||||
LearningContentDocumentListObjectType
|
LearningContentDocumentListObjectType
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ class LearningContentInterface(CoursePageInterface):
|
||||||
elif isinstance(instance, LearningContentRichText):
|
elif isinstance(instance, LearningContentRichText):
|
||||||
return LearningContentRichTextObjectType
|
return LearningContentRichTextObjectType
|
||||||
elif isinstance(instance, LearningContentEdoniqTest):
|
elif isinstance(instance, LearningContentEdoniqTest):
|
||||||
return LearningContentTestObjectType
|
return LearningContentEdoniqTestObjectType
|
||||||
elif isinstance(instance, LearningContentVideo):
|
elif isinstance(instance, LearningContentVideo):
|
||||||
return LearningContentVideoObjectType
|
return LearningContentVideoObjectType
|
||||||
elif isinstance(instance, LearningContentDocumentList):
|
elif isinstance(instance, LearningContentDocumentList):
|
||||||
|
|
@ -102,7 +102,7 @@ class LearningContentMediaLibraryObjectType(DjangoObjectType):
|
||||||
fields = []
|
fields = []
|
||||||
|
|
||||||
|
|
||||||
class LearningContentTestObjectType(DjangoObjectType):
|
class LearningContentEdoniqTestObjectType(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = LearningContentEdoniqTest
|
model = LearningContentEdoniqTest
|
||||||
interfaces = (LearningContentInterface,)
|
interfaces = (LearningContentInterface,)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue