Merge remote-tracking branch 'origin/develop' into feature/VBV-515-preview

# Conflicts:
#	client/src/components/dueDates/DueDateSingle.vue
#	client/src/components/header/MainNavigationBar.vue
#	client/src/components/header/MobileMenu.vue
#	client/src/pages/cockpit/cockpitPage/CockpitDates.vue
This commit is contained in:
Livio Bieri 2023-09-20 17:33:01 +02:00
commit f6d7f6e89e
123 changed files with 4498 additions and 1458 deletions

View File

@ -12,8 +12,7 @@
"@headlessui/vue": "1.7.7",
"@sentry/tracing": "^7.56.0",
"@sentry/vue": "^7.56.0",
"@urql/devtools": "^2.0.3",
"@urql/exchange-graphcache": "^6.1.4",
"@urql/exchange-graphcache": "^6.3.2",
"@urql/introspection": "^1.0.2",
"@urql/vue": "^1.1.2",
"@vueuse/core": "10.1.0",
@ -7767,33 +7766,21 @@
}
},
"node_modules/@urql/core": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/@urql/core/-/core-4.0.7.tgz",
"integrity": "sha512-UtZ9oSbSFODXzFydgLCXpAQz26KGT1d6uEfcylKphiRWNXSWZi8k7vhJXNceNm/Dn0MiZ+kaaJHKcnGY1jvHRQ==",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/@urql/core/-/core-4.1.2.tgz",
"integrity": "sha512-K+JA5dxEjY7Jkt1hV8G2ShkuOscKS/r+8QnXDDxTkyMzZzviYqz5f/zxgSElObT/QSW17xCC1LFl+kwiyX5opg==",
"dependencies": {
"@0no-co/graphql.web": "^1.0.1",
"wonka": "^6.3.2"
}
},
"node_modules/@urql/devtools": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@urql/devtools/-/devtools-2.0.3.tgz",
"integrity": "sha512-TktPLiBS9LcBPHD6qcnb8wqOVcg3Bx0iCtvQ80uPpfofwwBGJmqnQTjUdEFU6kwaLOFZULQ9+Uo4831G823mQw==",
"dependencies": {
"wonka": ">= 4.0.9"
},
"peerDependencies": {
"@urql/core": ">= 1.14.0",
"graphql": ">= 0.11.0"
}
},
"node_modules/@urql/exchange-graphcache": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@urql/exchange-graphcache/-/exchange-graphcache-6.1.4.tgz",
"integrity": "sha512-GQ1scnYjMVoUHrPoYOlw3ZfU2nXuLTEhWhKzPquhZz87GliVpZPuFMf+o64cI1dKy9xDlbU7aQnKiSaGeT248w==",
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/@urql/exchange-graphcache/-/exchange-graphcache-6.3.2.tgz",
"integrity": "sha512-ajBtuOkCkWgYJVk8MYqlhTF2vNojEREitcUE62q8tUxC6zDHZybk8DUPe6RM0HUyUw6IPAnzmDf6djK5JOEvvw==",
"dependencies": {
"@0no-co/graphql.web": "^1.0.1",
"@urql/core": ">=4.0.0",
"@urql/core": ">=4.1.0",
"wonka": "^6.3.2"
}
},
@ -26352,29 +26339,21 @@
}
},
"@urql/core": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/@urql/core/-/core-4.0.7.tgz",
"integrity": "sha512-UtZ9oSbSFODXzFydgLCXpAQz26KGT1d6uEfcylKphiRWNXSWZi8k7vhJXNceNm/Dn0MiZ+kaaJHKcnGY1jvHRQ==",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/@urql/core/-/core-4.1.2.tgz",
"integrity": "sha512-K+JA5dxEjY7Jkt1hV8G2ShkuOscKS/r+8QnXDDxTkyMzZzviYqz5f/zxgSElObT/QSW17xCC1LFl+kwiyX5opg==",
"requires": {
"@0no-co/graphql.web": "^1.0.1",
"wonka": "^6.3.2"
}
},
"@urql/devtools": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@urql/devtools/-/devtools-2.0.3.tgz",
"integrity": "sha512-TktPLiBS9LcBPHD6qcnb8wqOVcg3Bx0iCtvQ80uPpfofwwBGJmqnQTjUdEFU6kwaLOFZULQ9+Uo4831G823mQw==",
"requires": {
"wonka": ">= 4.0.9"
}
},
"@urql/exchange-graphcache": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@urql/exchange-graphcache/-/exchange-graphcache-6.1.4.tgz",
"integrity": "sha512-GQ1scnYjMVoUHrPoYOlw3ZfU2nXuLTEhWhKzPquhZz87GliVpZPuFMf+o64cI1dKy9xDlbU7aQnKiSaGeT248w==",
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/@urql/exchange-graphcache/-/exchange-graphcache-6.3.2.tgz",
"integrity": "sha512-ajBtuOkCkWgYJVk8MYqlhTF2vNojEREitcUE62q8tUxC6zDHZybk8DUPe6RM0HUyUw6IPAnzmDf6djK5JOEvvw==",
"requires": {
"@0no-co/graphql.web": "^1.0.1",
"@urql/core": ">=4.0.0",
"@urql/core": ">=4.1.0",
"wonka": "^6.3.2"
}
},

View File

@ -24,8 +24,7 @@
"@headlessui/vue": "1.7.7",
"@sentry/tracing": "^7.56.0",
"@sentry/vue": "^7.56.0",
"@urql/devtools": "^2.0.3",
"@urql/exchange-graphcache": "^6.1.4",
"@urql/exchange-graphcache": "^6.3.2",
"@urql/introspection": "^1.0.2",
"@urql/vue": "^1.1.2",
"@vueuse/core": "10.1.0",

View File

@ -33,13 +33,13 @@ async function changeLocale(language: AvailableLanguages) {
<div class="flex-grow"></div>
<div :class="{ hidden: hideVersion }">VBV_VERSION_BUILD_NUMBER_VBV</div>
<Menu>
<MenuButton class="lg:ml-8" data-cy="language-switch-button">
<MenuButton class="text-left lg:ml-8" data-cy="language-switch-button">
<it-icon-globe class="relative top-[2px] h-4 w-4" />
<span class="ml-2 inline">{{ $t(`language.${userStore.language}`) }}</span>
</MenuButton>
<div class="relative">
<MenuItems
class="lg:right- absolute -right-2/3 -top-24 w-40 bg-white px-4 py-4 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
class="absolute bottom-0 w-40 bg-white px-4 py-4 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none lg:right-0"
>
<MenuItem v-for="locale in SUPPORT_LOCALES" :key="locale" class="py-1">
<button

View File

@ -1,5 +1,5 @@
<script lang="ts" setup>
import { formatDate } from "@/components/dueDates/dueDatesUtils";
import { formatDueDate } from "@/components/dueDates/dueDatesUtils";
import type { CourseSession, DueDate } from "@/types";
import { useCourseSessionsStore } from "@/stores/courseSessions";
@ -28,8 +28,8 @@ const disableLink = courseSession
class="flex justify-between py-4"
:class="{ 'flex-col': props.singleLine, 'items-center': !props.singleLine }"
>
<div class="text-bold space-y-1">
<div>
<div class="space-y-1">
<div class="text-bold">
<a v-if="disableLink" class="underline" :href="props.dueDate.url">
{{ props.dueDate.title }}
</a>
@ -48,7 +48,7 @@ const disableLink = courseSession
</div>
</div>
<div>
{{ formatDate(props.dueDate.start, props.dueDate.end) }}
{{ formatDueDate(props.dueDate.start, props.dueDate.end) }}
</div>
</div>
</template>

View File

@ -1,38 +1,45 @@
import type { Dayjs } from "dayjs";
import dayjs from "dayjs";
import LocalizedFormat from "dayjs/plugin/localizedFormat";
import i18next from "i18next";
export const formatDate = (start: Dayjs, end: Dayjs) => {
const startDateString = getDateString(start);
const endDateString = getDateString(end);
export const formatDueDate = (start: string, end: string) => {
dayjs.extend(LocalizedFormat);
const startDayjs = dayjs(start);
const endDayjs = dayjs(end);
const startDateString = getDateString(startDayjs);
const endDateString = getDateString(endDayjs);
// if start isundefined, dont show the day twice
// if startDayjs isundefined, dont show the day twice
if (!start.isValid() && !end.isValid()) {
if (!startDayjs.isValid() && !endDayjs.isValid()) {
return i18next.t("Termin nicht festgelegt");
}
if (!start || (!start.isValid() && end.isValid())) {
return `${endDateString} ${getTimeString(end)} ${end.format("[Uhr]")}`;
if (!startDayjs || (!startDayjs.isValid() && endDayjs.isValid())) {
return `${endDateString} ${getTimeString(endDayjs)} ${endDayjs.format("[Uhr]")}`;
}
if (!end || (!end.isValid() && start.isValid())) {
return `${startDateString} ${getTimeString(start)} ${start.format("[Uhr]")}`;
}
// if start and end are on the same day, dont show the day twice
if (startDateString === endDateString) {
return `${startDateString} ${getTimeString(start)} - ${getTimeString(
end
)} ${end.format("[Uhr]")}`;
}
return `${startDateString} ${getTimeString(start)} - ${endDateString} ${getTimeString(
end
if (!endDayjs || (!endDayjs.isValid() && startDayjs.isValid())) {
return `${startDateString} ${getTimeString(startDayjs)} ${startDayjs.format(
"[Uhr]"
)}`;
}
// if startDayjs and endDayjs are on the same day, dont show the day twice
if (startDateString === endDateString) {
return `${startDateString} ${getTimeString(startDayjs)} - ${getTimeString(
endDayjs
)} ${endDayjs.format("[Uhr]")}`;
}
return `${startDateString} ${getTimeString(
startDayjs
)} - ${endDateString} ${getTimeString(endDayjs)}`;
};
export const getTimeString = (date?: Dayjs) => {
if (date) {
return `${date.format("H:mm")}`;
return `${date.format("HH:mm")}`;
}
return "";
};

View File

@ -146,7 +146,11 @@ onMounted(() => {
</router-link>
<router-link
:to="courseSessionsStore.currentCourseSession.competence_url"
:to="`${courseSessionsStore.currentCourseSession.competence_url.replace(
// TODO: remove the `competence_url` with url to Navi...
'/competences',
''
)}`"
class="nav-item"
:class="{ 'nav-item--active': inCompetenceProfile() }"
>

View File

@ -8,8 +8,6 @@ const router = useRouter();
defineProps<{
show: boolean;
hasExpertNavigation: boolean;
hasMemberNavigation: boolean;
courseSession: CourseSession | undefined;
mediaUrl?: string;
user: UserState | undefined;
@ -23,6 +21,8 @@ const clickLink = (to: string | undefined) => {
emit("closemodal");
}
};
const courseSessionsStore = useCourseSessionsStore();
</script>
<template>
@ -51,53 +51,53 @@ const clickLink = (to: string | undefined) => {
</div>
</div>
<div>
<div v-if="courseSession" class="mt-6 border-b pb-6">
<div v-if="courseSession" class="mt-6 border-b">
<h4 class="text-sm text-gray-900">{{ courseSession?.course.title }}</h4>
<ul class="mt-6">
<template v-if="hasMemberNavigation">
<li>
<button @click="clickLink(courseSession?.learning_path_url)">
{{ $t("general.learningPath") }}
</button>
</li>
<li>
<button @click="clickLink(courseSession?.competence_url)">
{{ $t("competences.title") }}
</button>
</li>
</template>
<template v-if="hasExpertNavigation">
<li class="mt-6">
<li
v-if="courseSessionsStore.currentCourseSessionHasCockpit"
class="mb-6"
>
<button @click="clickLink(`${courseSession?.course_url}/cockpit`)">
{{ $t("cockpit.title") }}
</button>
</li>
<li>
<li class="mb-6">
<button @click="clickLink(courseSession?.learning_path_url)">
{{ $t("a.VorschauTeilnehmer") }}
{{ $t("general.learningPath") }}
</button>
</li>
</template>
<li class="mt-6">
<li class="mb-6">
<button
@click="
clickLink(
courseSession?.competence_url.replace(
// TODO: remove the `competence_url` with url to Navi...
'/competences',
''
)
)
"
>
{{ $t("competences.title") }}
</button>
</li>
<li class="mb-6">
<button
data-cy="medialibrary-link"
@click="clickLink(`${courseSession?.media_library_url}`)"
>
{{ $t("mediaLibrary.title") }}
{{ $t("a.Mediathek") }}
</button>
</li>
</ul>
</div>
<div class="mt-6 border-b pb-6">
<div class="mt-6 border-b">
<ul>
<li>
<a
class="nav-item"
target="_blank"
href="https://bildung.vbv.ch/ilp/pages/catalogsearch.jsf"
>
Shop
</a>
<li class="mb-6">
<button data-cy="medialibrary-link" @click="clickLink('/')">
myVBV
</button>
</li>
</ul>
</div>

View File

@ -1,11 +1,23 @@
<script setup lang="ts">
import type { CheckboxItem } from "@/components/ui/checkbox.types";
import log from "loglevel";
import {
itCheckboxDefaultIconCheckedTailwindClass,
itCheckboxDefaultIconUncheckedTailwindClass,
} from "@/constants";
const props = defineProps<{
interface Props {
checkboxItem: CheckboxItem<any>;
disabled?: boolean;
}>();
iconCheckedTailwindClass?: string;
iconUncheckedTailwindClass?: string;
}
const props = withDefaults(defineProps<Props>(), {
disabled: false,
iconCheckedTailwindClass: itCheckboxDefaultIconCheckedTailwindClass,
iconUncheckedTailwindClass: itCheckboxDefaultIconUncheckedTailwindClass,
});
const emit = defineEmits(["toggle"]);
const toggle = () => {
@ -39,8 +51,8 @@ const input = () => {
class="flex h-8 items-center bg-contain bg-no-repeat pl-8 disabled:opacity-50"
:class="
checkboxItem.checked
? 'bg-[url(/static/icons/icon-checkbox-checked.svg)] hover:bg-[url(/static/icons/icon-checkbox-checked-hover.svg)]'
: 'bg-[url(/static/icons/icon-checkbox-unchecked.svg)] hover:bg-[url(/static/icons/icon-checkbox-unchecked-hover.svg)]'
? props.iconCheckedTailwindClass
: props.iconUncheckedTailwindClass
"
tabindex="0"
@keydown.stop="keydown"

View File

@ -11,7 +11,7 @@ defineProps<{
<ItRow>
<template #firstRow>
<slot name="leading"></slot>
<img class="mr-2 h-[45px] rounded-full" :src="avatarUrl" />
<img class="mr-2 h-11 w-11 rounded-full" :src="avatarUrl" />
<p class="text-bold lg:leading-[45px]">{{ name }}</p>
</template>
<template #center>

View File

@ -1,11 +1,11 @@
<template>
<li
class="flex flex-col justify-between border-t border-gray-500 py-4 leading-[45px] lg:flex-row"
class="flex flex-col justify-between gap-2 border-t border-gray-500 py-4 leading-[45px] lg:flex-row lg:gap-4"
>
<div class="flex flex-row items-center md:w-1/4">
<div class="flex flex-row items-center lg:w-1/3">
<slot name="firstRow"></slot>
</div>
<div class="flex flex-1 items-center">
<div class="flex flex-1 lg:items-center">
<slot name="center"></slot>
</div>
<div class="flex items-center lg:w-1/4">

View File

@ -3,3 +3,9 @@ import type { CourseCompletionStatus } from "@/types";
export const COMPLETION_SUCCESS: CourseCompletionStatus = "SUCCESS";
export const COMPLETION_FAILURE: CourseCompletionStatus = "FAIL";
export const COMPLETION_UNKNOWN: CourseCompletionStatus = "UNKNOWN";
export const itCheckboxDefaultIconCheckedTailwindClass =
"bg-[url(/static/icons/icon-checkbox-checked.svg)] hover:bg-[url(/static/icons/icon-checkbox-checked-hover.svg)]";
export const itCheckboxDefaultIconUncheckedTailwindClass =
"bg-[url(/static/icons/icon-checkbox-unchecked.svg)] hover:bg-[url(/static/icons/icon-checkbox-unchecked-hover.svg)]";

View File

@ -15,10 +15,12 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
const documents = {
"\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument,
"\n mutation AttendanceCheckMutation(\n $attendanceCourseId: ID!\n $attendanceUserList: [AttendanceUserInputType]!\n ) {\n update_course_session_attendance_course_users(\n id: $attendanceCourseId\n attendance_user_list: $attendanceUserList\n ) {\n course_session_attendance_course {\n id\n attendance_user_list {\n user_id\n first_name\n last_name\n email\n status\n }\n }\n }\n }\n": types.AttendanceCheckMutationDocument,
"\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n": types.UpsertAssignmentCompletionDocument,
"\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n": types.UpsertAssignmentCompletionDocument,
"\n fragment CoursePageFields on CoursePageInterface {\n title\n id\n slug\n content_type\n frontend_url\n }\n": types.CoursePageFieldsFragmentDoc,
"\n query attendanceCheckQuery($courseSessionId: ID!) {\n course_session_attendance_course(id: $courseSessionId) {\n id\n attendance_user_list {\n user_id\n status\n }\n }\n }\n": types.AttendanceCheckQueryDocument,
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
"\n query courseQuery($courseId: Int!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n": types.CourseQueryDocument,
"\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n }\n learning_content {\n title\n id\n slug\n content_type\n frontend_url\n circle {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument,
};
/**
@ -46,7 +48,11 @@ export function graphql(source: "\n mutation AttendanceCheckMutation(\n $att
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"): (typeof documents)["\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"];
export function graphql(source: "\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"): (typeof documents)["\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n $initializeCompletion: Boolean\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n initialize_completion: $initializeCompletion\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment CoursePageFields on CoursePageInterface {\n title\n id\n slug\n content_type\n frontend_url\n }\n"): (typeof documents)["\n fragment CoursePageFields on CoursePageInterface {\n title\n id\n slug\n content_type\n frontend_url\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
@ -54,11 +60,15 @@ export function graphql(source: "\n query attendanceCheckQuery($courseSessionId
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n"): (typeof documents)["\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n"];
export function graphql(source: "\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n"): (typeof documents)["\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n max_points\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n competence_certificate {\n ...CoursePageFields\n }\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query courseQuery($courseId: Int!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n"): (typeof documents)["\n query courseQuery($courseId: Int!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n }\n learning_content {\n title\n id\n slug\n content_type\n frontend_url\n circle {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {\n competence_certificate_list(course_slug: $courseSlug) {\n ...CoursePageFields\n competence_certificates {\n ...CoursePageFields\n assignments {\n ...CoursePageFields\n assignment_type\n max_points\n completion(course_session_id: $courseSessionId) {\n id\n completion_status\n submitted_at\n evaluation_points\n }\n learning_content {\n title\n id\n slug\n content_type\n frontend_url\n circle {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n"];
export function graphql(source: string) {
return (documents as any)[source] ?? {};

View File

@ -45,6 +45,10 @@ export type Scalars = {
export type AssignmentAssignmentAssignmentTypeChoices =
/** CASEWORK */
| 'CASEWORK'
/** CONDITION_ACCEPTANCE */
| 'CONDITION_ACCEPTANCE'
/** EDONIQ_TEST */
| 'EDONIQ_TEST'
/** PREP_ASSIGNMENT */
| 'PREP_ASSIGNMENT'
/** REFLECTION */
@ -94,7 +98,11 @@ export type AssignmentCompletionStatus =
export type AssignmentObjectType = CoursePageInterface & {
__typename?: 'AssignmentObjectType';
assignment_type: AssignmentAssignmentAssignmentTypeChoices;
circle?: Maybe<CircleObjectType>;
competence_certificate?: Maybe<CompetenceCertificateObjectType>;
completion?: Maybe<AssignmentCompletionObjectType>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
/** Zeitaufwand als Text */
effort_required: Scalars['String']['output'];
/** Beschreibung der Bewertung */
@ -106,7 +114,9 @@ export type AssignmentObjectType = CoursePageInterface & {
id?: Maybe<Scalars['ID']['output']>;
/** Erläuterung der Ausgangslage */
intro_text: Scalars['String']['output'];
learning_content?: Maybe<LearningContentInterface>;
live?: Maybe<Scalars['Boolean']['output']>;
max_points?: Maybe<Scalars['Int']['output']>;
performance_objectives?: Maybe<Scalars['JSONStreamField']['output']>;
slug?: Maybe<Scalars['String']['output']>;
tasks?: Maybe<Scalars['JSONStreamField']['output']>;
@ -114,6 +124,13 @@ export type AssignmentObjectType = CoursePageInterface & {
translation_key?: Maybe<Scalars['String']['output']>;
};
export type AssignmentObjectTypeCompletionArgs = {
assignment_user_id?: InputMaybe<Scalars['UUID']['input']>;
course_session_id: Scalars['ID']['input'];
learning_content_page_id?: InputMaybe<Scalars['ID']['input']>;
};
export type AttendanceCourseUserMutation = {
__typename?: 'AttendanceCourseUserMutation';
course_session_attendance_course?: Maybe<CourseSessionAttendanceCourseType>;
@ -140,7 +157,9 @@ export type AttendanceUserType = {
export type CircleObjectType = CoursePageInterface & {
__typename?: 'CircleObjectType';
circle?: Maybe<CircleObjectType>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description: Scalars['String']['output'];
frontend_url?: Maybe<Scalars['String']['output']>;
goals: Scalars['String']['output'];
@ -152,6 +171,56 @@ export type CircleObjectType = CoursePageInterface & {
translation_key?: Maybe<Scalars['String']['output']>;
};
export type CompetenceCertificateListObjectType = CoursePageInterface & {
__typename?: 'CompetenceCertificateListObjectType';
circle?: Maybe<CircleObjectType>;
competence_certificates?: Maybe<Array<Maybe<CompetenceCertificateObjectType>>>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
depth: Scalars['Int']['output'];
draft_title: Scalars['String']['output'];
expire_at?: Maybe<Scalars['DateTime']['output']>;
expired: Scalars['Boolean']['output'];
first_published_at?: Maybe<Scalars['DateTime']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
go_live_at?: Maybe<Scalars['DateTime']['output']>;
has_unpublished_changes: Scalars['Boolean']['output'];
id?: Maybe<Scalars['ID']['output']>;
last_published_at?: Maybe<Scalars['DateTime']['output']>;
latest_revision_created_at?: Maybe<Scalars['DateTime']['output']>;
live?: Maybe<Scalars['Boolean']['output']>;
locked: Scalars['Boolean']['output'];
locked_at?: Maybe<Scalars['DateTime']['output']>;
locked_by?: Maybe<UserType>;
numchild: Scalars['Int']['output'];
owner?: Maybe<UserType>;
path: Scalars['String']['output'];
/** Die informative Beschreibung, dargestellt in Suchmaschinen-Ergebnissen unter der Überschrift. */
search_description: Scalars['String']['output'];
/** Der Titel der Seite, dargestellt in Suchmaschinen-Ergebnissen als die verlinkte Überschrift. */
seo_title: Scalars['String']['output'];
/** Ob ein Link zu dieser Seite in automatisch generierten Menüs auftaucht. */
show_in_menus: Scalars['Boolean']['output'];
slug?: Maybe<Scalars['String']['output']>;
title?: Maybe<Scalars['String']['output']>;
translation_key?: Maybe<Scalars['String']['output']>;
url_path: Scalars['String']['output'];
};
export type CompetenceCertificateObjectType = CoursePageInterface & {
__typename?: 'CompetenceCertificateObjectType';
assignments?: Maybe<Array<Maybe<AssignmentObjectType>>>;
circle?: Maybe<CircleObjectType>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
live?: Maybe<Scalars['Boolean']['output']>;
slug?: Maybe<Scalars['String']['output']>;
title?: Maybe<Scalars['String']['output']>;
translation_key?: Maybe<Scalars['String']['output']>;
};
/** An enumeration. */
export type CoreUserLanguageChoices =
/** Deutsch */
@ -171,7 +240,9 @@ export type CourseObjectType = {
};
export type CoursePageInterface = {
circle?: Maybe<CircleObjectType>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
live?: Maybe<Scalars['Boolean']['output']>;
@ -211,9 +282,11 @@ export type FeedbackResponse = Node & {
export type LearningContentAssignmentObjectType = LearningContentInterface & {
__typename?: 'LearningContentAssignmentObjectType';
assignment_type: LearnpathLearningContentAssignmentAssignmentTypeChoices;
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_assignment: AssignmentObjectType;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -226,8 +299,10 @@ export type LearningContentAssignmentObjectType = LearningContentInterface & {
export type LearningContentAttendanceCourseObjectType = LearningContentInterface & {
__typename?: 'LearningContentAttendanceCourseObjectType';
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -240,8 +315,10 @@ export type LearningContentAttendanceCourseObjectType = LearningContentInterface
export type LearningContentDocumentListObjectType = LearningContentInterface & {
__typename?: 'LearningContentDocumentListObjectType';
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -254,8 +331,10 @@ export type LearningContentDocumentListObjectType = LearningContentInterface & {
export type LearningContentFeedbackObjectType = LearningContentInterface & {
__typename?: 'LearningContentFeedbackObjectType';
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -267,8 +346,10 @@ export type LearningContentFeedbackObjectType = LearningContentInterface & {
};
export type LearningContentInterface = {
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -281,8 +362,10 @@ export type LearningContentInterface = {
export type LearningContentLearningModuleObjectType = LearningContentInterface & {
__typename?: 'LearningContentLearningModuleObjectType';
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -295,8 +378,10 @@ export type LearningContentLearningModuleObjectType = LearningContentInterface &
export type LearningContentMediaLibraryObjectType = LearningContentInterface & {
__typename?: 'LearningContentMediaLibraryObjectType';
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -309,8 +394,10 @@ export type LearningContentMediaLibraryObjectType = LearningContentInterface & {
export type LearningContentPlaceholderObjectType = LearningContentInterface & {
__typename?: 'LearningContentPlaceholderObjectType';
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -323,8 +410,10 @@ export type LearningContentPlaceholderObjectType = LearningContentInterface & {
export type LearningContentRichTextObjectType = LearningContentInterface & {
__typename?: 'LearningContentRichTextObjectType';
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -337,8 +426,11 @@ export type LearningContentRichTextObjectType = LearningContentInterface & {
export type LearningContentTestObjectType = LearningContentInterface & {
__typename?: 'LearningContentTestObjectType';
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_assignment?: Maybe<AssignmentObjectType>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -351,8 +443,10 @@ export type LearningContentTestObjectType = LearningContentInterface & {
export type LearningContentVideoObjectType = LearningContentInterface & {
__typename?: 'LearningContentVideoObjectType';
circle?: Maybe<CircleObjectType>;
content?: Maybe<Scalars['String']['output']>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
description?: Maybe<Scalars['String']['output']>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
@ -365,7 +459,9 @@ export type LearningContentVideoObjectType = LearningContentInterface & {
export type LearningPathObjectType = CoursePageInterface & {
__typename?: 'LearningPathObjectType';
circle?: Maybe<CircleObjectType>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
depth: Scalars['Int']['output'];
draft_title: Scalars['String']['output'];
expire_at?: Maybe<Scalars['DateTime']['output']>;
@ -399,7 +495,9 @@ export type LearningPathObjectType = CoursePageInterface & {
export type LearningSequenceObjectType = CoursePageInterface & {
__typename?: 'LearningSequenceObjectType';
circle?: Maybe<CircleObjectType>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
frontend_url?: Maybe<Scalars['String']['output']>;
icon: Scalars['String']['output'];
id?: Maybe<Scalars['ID']['output']>;
@ -412,7 +510,9 @@ export type LearningSequenceObjectType = CoursePageInterface & {
export type LearningUnitObjectType = CoursePageInterface & {
__typename?: 'LearningUnitObjectType';
circle?: Maybe<CircleObjectType>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
learning_contents?: Maybe<Array<Maybe<LearningContentInterface>>>;
@ -426,6 +526,10 @@ export type LearningUnitObjectType = CoursePageInterface & {
export type LearnpathLearningContentAssignmentAssignmentTypeChoices =
/** CASEWORK */
| 'CASEWORK'
/** CONDITION_ACCEPTANCE */
| 'CONDITION_ACCEPTANCE'
/** EDONIQ_TEST */
| 'EDONIQ_TEST'
/** PREP_ASSIGNMENT */
| 'PREP_ASSIGNMENT'
/** REFLECTION */
@ -458,6 +562,7 @@ export type MutationUpsertAssignmentCompletionArgs = {
course_session_id: Scalars['ID']['input'];
evaluation_grade?: InputMaybe<Scalars['Float']['input']>;
evaluation_points?: InputMaybe<Scalars['Float']['input']>;
initialize_completion?: InputMaybe<Scalars['Boolean']['input']>;
learning_content_page_id?: InputMaybe<Scalars['ID']['input']>;
};
@ -472,6 +577,8 @@ export type Query = {
assignment?: Maybe<AssignmentObjectType>;
assignment_completion?: Maybe<AssignmentCompletionObjectType>;
circle?: Maybe<CircleObjectType>;
competence_certificate?: Maybe<CompetenceCertificateObjectType>;
competence_certificate_list?: Maybe<CompetenceCertificateListObjectType>;
course?: Maybe<CourseObjectType>;
course_session_attendance_course?: Maybe<CourseSessionAttendanceCourseType>;
learning_content_assignment?: Maybe<LearningContentAssignmentObjectType>;
@ -503,7 +610,21 @@ export type QueryAssignmentCompletionArgs = {
export type QueryCircleArgs = {
id?: InputMaybe<Scalars['Int']['input']>;
id?: InputMaybe<Scalars['ID']['input']>;
slug?: InputMaybe<Scalars['String']['input']>;
};
export type QueryCompetenceCertificateArgs = {
id?: InputMaybe<Scalars['ID']['input']>;
slug?: InputMaybe<Scalars['String']['input']>;
};
export type QueryCompetenceCertificateListArgs = {
course_id?: InputMaybe<Scalars['ID']['input']>;
course_slug?: InputMaybe<Scalars['String']['input']>;
id?: InputMaybe<Scalars['ID']['input']>;
slug?: InputMaybe<Scalars['String']['input']>;
};
@ -520,7 +641,9 @@ export type QueryCourseSessionAttendanceCourseArgs = {
export type QueryLearningPathArgs = {
id?: InputMaybe<Scalars['Int']['input']>;
course_id?: InputMaybe<Scalars['ID']['input']>;
course_slug?: InputMaybe<Scalars['String']['input']>;
id?: InputMaybe<Scalars['ID']['input']>;
slug?: InputMaybe<Scalars['String']['input']>;
};
@ -541,8 +664,10 @@ export type SendFeedbackPayload = {
export type TopicObjectType = CoursePageInterface & {
__typename?: 'TopicObjectType';
circle?: Maybe<CircleObjectType>;
circles?: Maybe<Array<Maybe<CircleObjectType>>>;
content_type?: Maybe<Scalars['String']['output']>;
course?: Maybe<CourseObjectType>;
frontend_url?: Maybe<Scalars['String']['output']>;
id?: Maybe<Scalars['ID']['output']>;
is_visible: Scalars['Boolean']['output'];
@ -588,11 +713,30 @@ export type UpsertAssignmentCompletionMutationVariables = Exact<{
completionDataString: Scalars['String']['input'];
evaluationGrade?: InputMaybe<Scalars['Float']['input']>;
evaluationPoints?: InputMaybe<Scalars['Float']['input']>;
initializeCompletion?: InputMaybe<Scalars['Boolean']['input']>;
}>;
export type UpsertAssignmentCompletionMutation = { __typename?: 'Mutation', upsert_assignment_completion?: { __typename?: 'AssignmentCompletionMutation', assignment_completion?: { __typename?: 'AssignmentCompletionObjectType', id: any, completion_status: AssignmentAssignmentCompletionCompletionStatusChoices, submitted_at?: any | null, evaluation_submitted_at?: any | null, evaluation_grade?: number | null, evaluation_points?: number | null, completion_data?: any | null } | null } | null };
type CoursePageFieldsAssignmentObjectTypeFragment = { __typename?: 'AssignmentObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null } & { ' $fragmentName'?: 'CoursePageFieldsAssignmentObjectTypeFragment' };
type CoursePageFieldsCircleObjectTypeFragment = { __typename?: 'CircleObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null } & { ' $fragmentName'?: 'CoursePageFieldsCircleObjectTypeFragment' };
type CoursePageFieldsCompetenceCertificateListObjectTypeFragment = { __typename?: 'CompetenceCertificateListObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null } & { ' $fragmentName'?: 'CoursePageFieldsCompetenceCertificateListObjectTypeFragment' };
type CoursePageFieldsCompetenceCertificateObjectTypeFragment = { __typename?: 'CompetenceCertificateObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null } & { ' $fragmentName'?: 'CoursePageFieldsCompetenceCertificateObjectTypeFragment' };
type CoursePageFieldsLearningPathObjectTypeFragment = { __typename?: 'LearningPathObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null } & { ' $fragmentName'?: 'CoursePageFieldsLearningPathObjectTypeFragment' };
type CoursePageFieldsLearningSequenceObjectTypeFragment = { __typename?: 'LearningSequenceObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null } & { ' $fragmentName'?: 'CoursePageFieldsLearningSequenceObjectTypeFragment' };
type CoursePageFieldsLearningUnitObjectTypeFragment = { __typename?: 'LearningUnitObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null } & { ' $fragmentName'?: 'CoursePageFieldsLearningUnitObjectTypeFragment' };
type CoursePageFieldsTopicObjectTypeFragment = { __typename?: 'TopicObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null } & { ' $fragmentName'?: 'CoursePageFieldsTopicObjectTypeFragment' };
export type CoursePageFieldsFragment = CoursePageFieldsAssignmentObjectTypeFragment | CoursePageFieldsCircleObjectTypeFragment | CoursePageFieldsCompetenceCertificateListObjectTypeFragment | CoursePageFieldsCompetenceCertificateObjectTypeFragment | CoursePageFieldsLearningPathObjectTypeFragment | CoursePageFieldsLearningSequenceObjectTypeFragment | CoursePageFieldsLearningUnitObjectTypeFragment | CoursePageFieldsTopicObjectTypeFragment;
export type AttendanceCheckQueryQueryVariables = Exact<{
courseSessionId: Scalars['ID']['input'];
}>;
@ -608,7 +752,10 @@ export type AssignmentCompletionQueryQueryVariables = Exact<{
}>;
export type AssignmentCompletionQueryQuery = { __typename?: 'Query', assignment?: { __typename?: 'AssignmentObjectType', assignment_type: AssignmentAssignmentAssignmentTypeChoices, content_type?: string | null, effort_required: string, evaluation_description: string, evaluation_document_url: string, evaluation_tasks?: any | null, id?: string | null, intro_text: string, performance_objectives?: any | null, slug?: string | null, tasks?: any | null, title?: string | null, translation_key?: string | null } | null, assignment_completion?: { __typename?: 'AssignmentCompletionObjectType', id: any, completion_status: AssignmentAssignmentCompletionCompletionStatusChoices, submitted_at?: any | null, evaluation_submitted_at?: any | null, evaluation_grade?: number | null, evaluation_points?: number | null, completion_data?: any | null, evaluation_user?: { __typename?: 'UserType', id: any } | null, assignment_user: { __typename?: 'UserType', id: any } } | null };
export type AssignmentCompletionQueryQuery = { __typename?: 'Query', assignment?: { __typename?: 'AssignmentObjectType', assignment_type: AssignmentAssignmentAssignmentTypeChoices, max_points?: number | null, content_type?: string | null, effort_required: string, evaluation_description: string, evaluation_document_url: string, evaluation_tasks?: any | null, id?: string | null, intro_text: string, performance_objectives?: any | null, slug?: string | null, tasks?: any | null, title?: string | null, translation_key?: string | null, competence_certificate?: (
{ __typename?: 'CompetenceCertificateObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCompetenceCertificateObjectTypeFragment': CoursePageFieldsCompetenceCertificateObjectTypeFragment } }
) | null } | null, assignment_completion?: { __typename?: 'AssignmentCompletionObjectType', id: any, completion_status: AssignmentAssignmentCompletionCompletionStatusChoices, submitted_at?: any | null, evaluation_submitted_at?: any | null, evaluation_grade?: number | null, evaluation_points?: number | null, completion_data?: any | null, evaluation_user?: { __typename?: 'UserType', id: any } | null, assignment_user: { __typename?: 'UserType', id: any } } | null };
export type CourseQueryQueryVariables = Exact<{
courseId: Scalars['Int']['input'];
@ -617,10 +764,58 @@ export type CourseQueryQueryVariables = Exact<{
export type CourseQueryQuery = { __typename?: 'Query', course?: { __typename?: 'CourseObjectType', id: string, slug: string, title: string, category_name: string, learning_path?: { __typename?: 'LearningPathObjectType', id?: string | null } | null } | null };
export type CompetenceCertificateQueryQueryVariables = Exact<{
courseSlug: Scalars['String']['input'];
courseSessionId: Scalars['ID']['input'];
}>;
export type CompetenceCertificateQueryQuery = { __typename?: 'Query', competence_certificate_list?: (
{ __typename?: 'CompetenceCertificateListObjectType', competence_certificates?: Array<(
{ __typename?: 'CompetenceCertificateObjectType', assignments?: Array<(
{ __typename?: 'AssignmentObjectType', assignment_type: AssignmentAssignmentAssignmentTypeChoices, max_points?: number | null, completion?: { __typename?: 'AssignmentCompletionObjectType', id: any, completion_status: AssignmentAssignmentCompletionCompletionStatusChoices, submitted_at?: any | null, evaluation_points?: number | null } | null, learning_content?: { __typename?: 'LearningContentAssignmentObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | { __typename?: 'LearningContentAttendanceCourseObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | { __typename?: 'LearningContentDocumentListObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | { __typename?: 'LearningContentFeedbackObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | { __typename?: 'LearningContentLearningModuleObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | { __typename?: 'LearningContentMediaLibraryObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | { __typename?: 'LearningContentPlaceholderObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | { __typename?: 'LearningContentRichTextObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | { __typename?: 'LearningContentTestObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | { __typename?: 'LearningContentVideoObjectType', title?: string | null, id?: string | null, slug?: string | null, content_type?: string | null, frontend_url?: string | null, circle?: (
{ __typename?: 'CircleObjectType' }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCircleObjectTypeFragment': CoursePageFieldsCircleObjectTypeFragment } }
) | null } | null }
& { ' $fragmentRefs'?: { 'CoursePageFieldsAssignmentObjectTypeFragment': CoursePageFieldsAssignmentObjectTypeFragment } }
) | null> | null }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCompetenceCertificateObjectTypeFragment': CoursePageFieldsCompetenceCertificateObjectTypeFragment } }
) | null> | null }
& { ' $fragmentRefs'?: { 'CoursePageFieldsCompetenceCertificateListObjectTypeFragment': CoursePageFieldsCompetenceCertificateListObjectTypeFragment } }
) | null };
export const CoursePageFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CoursePageFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CoursePageInterface"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}}]}}]} as unknown as DocumentNode<CoursePageFieldsFragment, unknown>;
export const SendFeedbackMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendFeedbackMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SendFeedbackInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"send_feedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feedback_response"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"messages"}}]}}]}}]}}]} as unknown as DocumentNode<SendFeedbackMutationMutation, SendFeedbackMutationMutationVariables>;
export const AttendanceCheckMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AttendanceCheckMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"attendanceCourseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"attendanceUserList"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AttendanceUserInputType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"update_course_session_attendance_course_users"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"attendanceCourseId"}}},{"kind":"Argument","name":{"kind":"Name","value":"attendance_user_list"},"value":{"kind":"Variable","name":{"kind":"Name","value":"attendanceUserList"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course_session_attendance_course"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"attendance_user_list"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user_id"}},{"kind":"Field","name":{"kind":"Name","value":"first_name"}},{"kind":"Field","name":{"kind":"Name","value":"last_name"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]}}]} as unknown as DocumentNode<AttendanceCheckMutationMutation, AttendanceCheckMutationMutationVariables>;
export const UpsertAssignmentCompletionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpsertAssignmentCompletion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AssignmentCompletionStatus"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"upsert_assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_data_string"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_grade"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_points"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]}}]} as unknown as DocumentNode<UpsertAssignmentCompletionMutation, UpsertAssignmentCompletionMutationVariables>;
export const UpsertAssignmentCompletionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpsertAssignmentCompletion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AssignmentCompletionStatus"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"initializeCompletion"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"upsert_assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_data_string"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_grade"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_points"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}}},{"kind":"Argument","name":{"kind":"Name","value":"initialize_completion"},"value":{"kind":"Variable","name":{"kind":"Name","value":"initializeCompletion"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]}}]} as unknown as DocumentNode<UpsertAssignmentCompletionMutation, UpsertAssignmentCompletionMutationVariables>;
export const AttendanceCheckQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"attendanceCheckQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course_session_attendance_course"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"attendance_user_list"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user_id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]} as unknown as DocumentNode<AttendanceCheckQueryQuery, AttendanceCheckQueryQueryVariables>;
export const AssignmentCompletionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"assignmentCompletionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"effort_required"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_description"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_document_url"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_tasks"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"intro_text"}},{"kind":"Field","name":{"kind":"Name","value":"performance_objectives"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tasks"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"translation_key"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]} as unknown as DocumentNode<AssignmentCompletionQueryQuery, AssignmentCompletionQueryQueryVariables>;
export const AssignmentCompletionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"assignmentCompletionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"max_points"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"effort_required"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_description"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_document_url"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_tasks"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"intro_text"}},{"kind":"Field","name":{"kind":"Name","value":"performance_objectives"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tasks"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"translation_key"}},{"kind":"Field","name":{"kind":"Name","value":"competence_certificate"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CoursePageFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CoursePageInterface"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}}]}}]} as unknown as DocumentNode<AssignmentCompletionQueryQuery, AssignmentCompletionQueryQueryVariables>;
export const CourseQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"courseQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"category_name"}},{"kind":"Field","name":{"kind":"Name","value":"learning_path"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<CourseQueryQuery, CourseQueryQueryVariables>;
export const CompetenceCertificateQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"competenceCertificateQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"competence_certificate_list"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"course_slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}},{"kind":"Field","name":{"kind":"Name","value":"competence_certificates"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}},{"kind":"Field","name":{"kind":"Name","value":"assignments"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}},{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"max_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}}]}},{"kind":"Field","name":{"kind":"Name","value":"learning_content"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}},{"kind":"Field","name":{"kind":"Name","value":"circle"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoursePageFields"}}]}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CoursePageFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"CoursePageInterface"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"frontend_url"}}]}}]} as unknown as DocumentNode<CompetenceCertificateQueryQuery, CompetenceCertificateQueryQueryVariables>;

View File

@ -1,6 +1,6 @@
type Query {
circle(id: Int, slug: String): CircleObjectType
learning_path(id: Int, slug: String): LearningPathObjectType
learning_path(id: ID, slug: String, course_id: ID, course_slug: String): LearningPathObjectType
circle(id: ID, slug: String): CircleObjectType
learning_content_media_library: LearningContentMediaLibraryObjectType
learning_content_assignment: LearningContentAssignmentObjectType
learning_content_attendance_course: LearningContentAttendanceCourseObjectType
@ -13,69 +13,12 @@ type Query {
learning_content_document_list: LearningContentDocumentListObjectType
course_session_attendance_course(id: ID!, assignment_user_id: ID): CourseSessionAttendanceCourseType
course(id: Int): CourseObjectType
competence_certificate(id: ID, slug: String): CompetenceCertificateObjectType
competence_certificate_list(id: ID, slug: String, course_id: ID, course_slug: String): CompetenceCertificateListObjectType
assignment(id: ID, slug: String): AssignmentObjectType
assignment_completion(assignment_id: ID!, course_session_id: ID!, learning_content_page_id: ID, assignment_user_id: UUID): AssignmentCompletionObjectType
}
type CircleObjectType implements CoursePageInterface {
description: String!
goals: String!
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
learning_sequences: [LearningSequenceObjectType]
}
interface CoursePageInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
}
type LearningSequenceObjectType implements CoursePageInterface {
icon: String!
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
learning_units: [LearningUnitObjectType]
}
type LearningUnitObjectType implements CoursePageInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
learning_contents: [LearningContentInterface]
}
interface LearningContentInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
minutes: Int
description: String
content: String
}
type LearningPathObjectType implements CoursePageInterface {
id: ID
path: String!
@ -115,9 +58,88 @@ type LearningPathObjectType implements CoursePageInterface {
search_description: String!
latest_revision_created_at: DateTime
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
topics: [TopicObjectType]
}
interface CoursePageInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
}
type CircleObjectType implements CoursePageInterface {
description: String!
goals: String!
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
learning_sequences: [LearningSequenceObjectType]
}
type CourseObjectType {
id: ID!
title: String!
category_name: String!
slug: String!
learning_path: LearningPathObjectType
}
type LearningSequenceObjectType implements CoursePageInterface {
icon: String!
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
learning_units: [LearningUnitObjectType]
}
type LearningUnitObjectType implements CoursePageInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
learning_contents: [LearningContentInterface]
}
interface 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
}
"""
The `DateTime` scalar type represents a DateTime
value as specified by
@ -165,6 +187,8 @@ type TopicObjectType implements CoursePageInterface {
live: Boolean
translation_key: String
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
circles: [CircleObjectType]
}
@ -176,6 +200,8 @@ type LearningContentMediaLibraryObjectType implements LearningContentInterface {
live: Boolean
translation_key: String
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
minutes: Int
description: String
content: String
@ -191,6 +217,8 @@ type LearningContentAssignmentObjectType implements LearningContentInterface {
live: Boolean
translation_key: String
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
minutes: Int
description: String
content: String
@ -198,6 +226,7 @@ type LearningContentAssignmentObjectType implements LearningContentInterface {
type AssignmentObjectType implements CoursePageInterface {
assignment_type: AssignmentAssignmentAssignmentTypeChoices!
competence_certificate: CompetenceCertificateObjectType
"""Erläuterung der Ausgangslage"""
intro_text: String!
@ -217,9 +246,14 @@ type AssignmentObjectType implements CoursePageInterface {
live: Boolean
translation_key: String
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
tasks: JSONStreamField
evaluation_tasks: JSONStreamField
performance_objectives: JSONStreamField
max_points: Int
learning_content: LearningContentInterface
completion(course_session_id: ID!, learning_content_page_id: ID, assignment_user_id: UUID): AssignmentCompletionObjectType
}
"""An enumeration."""
@ -232,160 +266,29 @@ enum AssignmentAssignmentAssignmentTypeChoices {
"""REFLECTION"""
REFLECTION
"""CONDITION_ACCEPTANCE"""
CONDITION_ACCEPTANCE
"""EDONIQ_TEST"""
EDONIQ_TEST
}
type CompetenceCertificateObjectType implements CoursePageInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
assignments: [AssignmentObjectType]
}
scalar JSONStreamField
"""An enumeration."""
enum LearnpathLearningContentAssignmentAssignmentTypeChoices {
"""CASEWORK"""
CASEWORK
"""PREP_ASSIGNMENT"""
PREP_ASSIGNMENT
"""REFLECTION"""
REFLECTION
}
type LearningContentAttendanceCourseObjectType implements LearningContentInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
minutes: Int
description: String
content: String
}
type LearningContentFeedbackObjectType implements LearningContentInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
minutes: Int
description: String
content: String
}
type LearningContentLearningModuleObjectType implements LearningContentInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
minutes: Int
description: String
content: String
}
type LearningContentPlaceholderObjectType implements LearningContentInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
minutes: Int
description: String
content: String
}
type LearningContentRichTextObjectType implements LearningContentInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
minutes: Int
description: String
content: String
}
type LearningContentTestObjectType implements LearningContentInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
minutes: Int
description: String
content: String
}
type LearningContentVideoObjectType implements LearningContentInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
minutes: Int
description: String
content: String
}
type LearningContentDocumentListObjectType implements LearningContentInterface {
id: ID
title: String
slug: String
content_type: String
live: Boolean
translation_key: String
frontend_url: String
minutes: Int
description: 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 CourseObjectType {
id: ID!
title: String!
category_name: String!
slug: String!
learning_path: LearningPathObjectType
}
type AssignmentCompletionObjectType {
id: UUID!
created_at: DateTime!
@ -433,10 +336,219 @@ schema (one of the key benefits of GraphQL).
"""
scalar JSONString
"""An enumeration."""
enum LearnpathLearningContentAssignmentAssignmentTypeChoices {
"""CASEWORK"""
CASEWORK
"""PREP_ASSIGNMENT"""
PREP_ASSIGNMENT
"""REFLECTION"""
REFLECTION
"""CONDITION_ACCEPTANCE"""
CONDITION_ACCEPTANCE
"""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 {
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 LearningContentLearningModuleObjectType 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 LearningContentPlaceholderObjectType 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 LearningContentRichTextObjectType 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 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 {
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 LearningContentDocumentListObjectType 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 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 {
id: ID
path: String!
depth: Int!
numchild: Int!
translation_key: String
live: Boolean
has_unpublished_changes: Boolean!
first_published_at: DateTime
last_published_at: DateTime
go_live_at: DateTime
expire_at: DateTime
expired: Boolean!
locked: Boolean!
locked_at: DateTime
locked_by: UserType
title: String
draft_title: String!
slug: String
content_type: String
url_path: String!
owner: UserType
"""
Der Titel der Seite, dargestellt in Suchmaschinen-Ergebnissen als die verlinkte Überschrift.
"""
seo_title: String!
"""
Ob ein Link zu dieser Seite in automatisch generierten Menüs auftaucht.
"""
show_in_menus: Boolean!
"""
Die informative Beschreibung, dargestellt in Suchmaschinen-Ergebnissen unter der Überschrift.
"""
search_description: String!
latest_revision_created_at: DateTime
frontend_url: String
circle: CircleObjectType
course: CourseObjectType
competence_certificates: [CompetenceCertificateObjectType]
}
type Mutation {
send_feedback(input: SendFeedbackInput!): SendFeedbackPayload
update_course_session_attendance_course_users(attendance_user_list: [AttendanceUserInputType]!, id: ID!): AttendanceCourseUserMutation
upsert_assignment_completion(assignment_id: ID!, assignment_user_id: UUID, completion_data_string: String, completion_status: AssignmentCompletionStatus, course_session_id: ID!, evaluation_grade: Float, evaluation_points: Float, learning_content_page_id: ID): AssignmentCompletionMutation
upsert_assignment_completion(assignment_id: ID!, assignment_user_id: UUID, completion_data_string: String, completion_status: AssignmentCompletionStatus, course_session_id: ID!, evaluation_grade: Float, evaluation_points: Float, initialize_completion: Boolean, learning_content_page_id: ID): AssignmentCompletionMutation
}
type SendFeedbackPayload {

View File

@ -10,6 +10,8 @@ export const AttendanceUserStatus = "AttendanceUserStatus";
export const AttendanceUserType = "AttendanceUserType";
export const Boolean = "Boolean";
export const CircleObjectType = "CircleObjectType";
export const CompetenceCertificateListObjectType = "CompetenceCertificateListObjectType";
export const CompetenceCertificateObjectType = "CompetenceCertificateObjectType";
export const CoreUserLanguageChoices = "CoreUserLanguageChoices";
export const CourseObjectType = "CourseObjectType";
export const CoursePageInterface = "CoursePageInterface";

View File

@ -1,6 +1,5 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { devtoolsExchange } from "@urql/devtools";
import { cacheExchange } from "@urql/exchange-graphcache";
import { Client, fetchExchange } from "@urql/vue";
import schema from "../gql/minifiedSchema.json";
@ -12,7 +11,6 @@ import {
export const graphqlClient = new Client({
url: import.meta.env.VITE_GRAPHQL_URL || "/server/graphql/",
exchanges: [
devtoolsExchange,
cacheExchange({
schema: schema,
keys: {

View File

@ -33,6 +33,7 @@ export const UPSERT_ASSIGNMENT_COMPLETION_MUTATION = graphql(`
$completionDataString: String!
$evaluationGrade: Float
$evaluationPoints: Float
$initializeCompletion: Boolean
) {
upsert_assignment_completion(
assignment_id: $assignmentId
@ -43,6 +44,7 @@ export const UPSERT_ASSIGNMENT_COMPLETION_MUTATION = graphql(`
completion_data_string: $completionDataString
evaluation_grade: $evaluationGrade
evaluation_points: $evaluationPoints
initialize_completion: $initializeCompletion
) {
assignment_completion {
id

View File

@ -1,5 +1,16 @@
import { graphql } from "@/gql";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const CoursePageFragment = graphql(`
fragment CoursePageFields on CoursePageInterface {
title
id
slug
content_type
frontend_url
}
`);
export const ATTENDANCE_CHECK_QUERY = graphql(`
query attendanceCheckQuery($courseSessionId: ID!) {
course_session_attendance_course(id: $courseSessionId) {
@ -21,6 +32,7 @@ export const ASSIGNMENT_COMPLETION_QUERY = graphql(`
) {
assignment(id: $assignmentId) {
assignment_type
max_points
content_type
effort_required
evaluation_description
@ -33,6 +45,9 @@ export const ASSIGNMENT_COMPLETION_QUERY = graphql(`
tasks
title
translation_key
competence_certificate {
...CoursePageFields
}
}
assignment_completion(
assignment_id: $assignmentId
@ -70,3 +85,35 @@ export const COURSE_QUERY = graphql(`
}
}
`);
export const COMPETENCE_NAVI_CERTIFICATE_QUERY = graphql(`
query competenceCertificateQuery($courseSlug: String!, $courseSessionId: ID!) {
competence_certificate_list(course_slug: $courseSlug) {
...CoursePageFields
competence_certificates {
...CoursePageFields
assignments {
...CoursePageFields
assignment_type
max_points
completion(course_session_id: $courseSessionId) {
id
completion_status
submitted_at
evaluation_points
}
learning_content {
title
id
slug
content_type
frontend_url
circle {
...CoursePageFields
}
}
}
}
}
}
`);

View File

@ -1,4 +1,10 @@
{
"100%": "100%",
"20%": "20%",
"40%": "40%",
"60%": "60%",
"80%": "80%",
"Abgabetermin Ergebnisse:": "Abgabetermin Ergebnisse:",
"Alle": "Alle",
"Anwesenheit Präsenzkurse": "Anwesenheit Präsenzkurse",
"Anwesenheit bestätigen": "Anwesenheit bestätigen",
@ -6,17 +12,35 @@
"Anwesenheitskontrolle Präsenzkurse": "Anwesenheitskontrolle Präsenzkurse",
"Benutzername": "Benutzername",
"Ergebnisse anschauen": "Ergebnisse anschauen",
"Ergebnisse anzeigen": "Ergebnisse anzeigen",
"Feedback": "Feedback",
"Feedback anschauen": "Feedback anschauen",
"Feedback: Feedback zum Lehrgang": "Feedback: Feedback zum Lehrgang",
"Freigabetermin Bewertungen:": "Freigabetermin Bewertungen:",
"MS Teams öffnen": "MS Teams öffnen",
"Nächste Termine": "Nächste Termine",
"Passwort": "Passwort",
"Präsenzkurs": "Präsenzkurs",
"Sehr unzufrieden": "Sehr unzufrieden",
"Sehr zufrieden": "Sehr zufrieden",
"Status anschauen": "Status anschauen",
"TODO: Nächste Termine": "TODO: Nächste Termine",
"Trainerunterlagen": "Trainerunterlagen",
"Wissens - und Verständnisfragen": "Wissens - und Verständnisfragen",
"Zur Zeit sind keine Termine vorhanden": "Zur Zeit sind keine Termine vorhanden",
"a": {
"Bewertung freigegeben": "Bewertung freigegeben",
"Details anzeigen": "Details anzeigen",
"Ergebnisse abgegeben": "Ergebnisse abgegeben",
"Gesamtpunktzahl": "Gesamtpunktzahl",
"Höchstpunktzahl": "Höchstpunktzahl",
"KompetenzNavi": "KompetenzNavi",
"Kompetenznachweise": "Kompetenznachweise",
"Punkte": "Punkte",
"Selbsteinschätzungen": "Selbsteinschätzungen",
"Zwischenstand": "Zwischenstand",
"Übersicht": "Übersicht"
},
"assignment": {
"acceptConditionsDisclaimer": "Bedingungen akzeptieren und Ergebnisse abgeben",
"assessmentDocumentDisclaimer": "Diese geleitete Fallarbeit wird auf Grund des folgenden Beurteilungsinstrument bewertet:",
@ -37,7 +61,9 @@
"submissionNotificationDisclaimer": "{{name}} wird deine Ergebnisse bewerten. Du wirst per Benachrichtigung informiert, sobald die Bewertung für dich freigegeben wurde.",
"submitAssignment": "Ergebnisse abgeben",
"taskDefinition": "Bearbeite die Teilaufgaben und dokumentiere deine Ergebnisse.",
"taskDefinitionTitle": "Aufgabenstellung"
"taskDefinitionTitle": "Aufgabenstellung",
"von x Punkten": "von {{x}} Punkten",
"x von y Arbeiten abgeschlossen": "{{x}} von {{y}} Arbeiten abgeschlossen"
},
"circlePage": {
"circleContentBoxTitle": "Das lernst du in diesem Circle",
@ -81,6 +107,12 @@
"title": "Cockpit",
"trainerFilesText": "Hier findest du die Trainerunterlagen (Lösungsblätter, Präsentationen etc.) für deinen Circle."
},
"competenceCertificate": {
"mainTitle": "competenceCertificate.mainTitle"
},
"competenceCertificates": {
"mainTitle": "competenceCertificates.mainTitle"
},
"competences": {
"assessAgain": "Sich nochmals einschätzen",
"assessment": "Einschätzungen",
@ -171,6 +203,7 @@
"exam_other": "Prüfungen",
"feedback_one": "Feedback",
"feedback_other": "Feedbacks",
"im circle x anschauen": "Im Circle «{{x}}» anzeigen",
"introduction": "Einleitung",
"learningPath": "Lernpfad",
"learningSequence": "Lernsequenz",
@ -252,7 +285,6 @@
"description": "Finde eine vollständige Liste der Bücher und anderen Medien, auf die im Kurs verwiesen wird.",
"titel": "Lernmedien"
},
"overview": "Übersicht",
"title": "Mediathek"
},
"messages": {
@ -293,8 +325,10 @@
"welcome": "Es hat alles geklappt, du bist nun auf der digitalen Lernumgebung des Berufsbildungsverbands derVersicherungswirtschaft (VBV) registriert!"
}
},
"unzufrieden": "unzufrieden",
"x von y Bewertungen freigegeben": "{{x}} von {{y}} Bewertungen freigegeben",
"x von y Ergebnisse abgegeben": "{{x}} von {{y}} Ergebnisse abgegeben",
"x von y Feedbacks abgegeben": "{{x}} von {{y}} Feedbacks abgegeben",
"x von y abgeschlossen": "{{x}} von {{y}} abgeschlossen"
"x von y abgeschlossen": "{{x}} von {{y}} abgeschlossen",
"zufrieden": "zufrieden"
}

View File

@ -15,6 +15,17 @@
"Trainerunterlagen": "Documents du formateur / de la formatrice",
"Wissens - und Verständnisfragen": "Questions de connaissance et de compréhension ",
"Zur Zeit sind keine Termine vorhanden": "Aucune réunion nest prévue pour le moment",
"a": {
"Bewertung freigegeben": "Évaluations validée/s",
"Details anzeigen": "Afficher les détails",
"Ergebnisse abgegeben": "Résultats remis",
"Gesamtpunktzahl": "Score total",
"Höchstpunktzahl": "Score maximum",
"KompetenzNavi": "NaviCompétence",
"Punkte": "points",
"Zwischenstand": "Point intermédiaire",
"Übersicht": "Aperçu"
},
"assignment": {
"acceptConditionsDisclaimer": "Accepter les conditions et remettre les résultats",
"assessmentDocumentDisclaimer": "Cette étude de cas dirigée est évaluée par loutil suivant :",
@ -34,7 +45,9 @@
"submissionNotificationDisclaimer": "{{name}} va procéder à lévaluation de tes résultats. Tu recevras une notification dès que lévaluation aura été validée et que tu pourras la consulter.",
"submitAssignment": "Remettre les résultats",
"taskDefinition": "Résous les exercices et documente tes résultats.",
"taskDefinitionTitle": "Énoncé du problème"
"taskDefinitionTitle": "Énoncé du problème",
"von x Punkten": "sur {{x}} points",
"x von y Arbeiten abgeschlossen": "{{x}} sur {{y}} épreuves terminées"
},
"circlePage": {
"circleContentBoxTitle": "Ce que tu vas apprendre dans ce cercle",
@ -169,6 +182,7 @@
"feedback_many": "Feed-backs",
"feedback_one": "Feed-back",
"feedback_other": "Feed-backs",
"im circle x anschauen": "Regarder dans le cercle «{{x}}»",
"introduction": "Introduction",
"learningPath": "Parcours de formation",
"learningSequence": "Séquence",

View File

@ -15,6 +15,17 @@
"Trainerunterlagen": "Documenti del/della trainer",
"Wissens - und Verständnisfragen": "Domande di conoscenza e di comprensione",
"Zur Zeit sind keine Termine vorhanden": "Al momento non ci sono scadenze",
"a": {
"Bewertung freigegeben": "Valutazioni approvate/a",
"Details anzeigen": "Mostrare i dettagli",
"Ergebnisse abgegeben": "Risultati consegnati",
"Gesamtpunktzahl": "Punteggio totale",
"Höchstpunktzahl": "Punteggio massimo",
"KompetenzNavi": "NaviCompetenze",
"Punkte": "punti",
"Zwischenstand": "Punto intermedio",
"Übersicht": "Panoramica"
},
"assignment": {
"acceptConditionsDisclaimer": "Accettare le condizioni e consegnare i risultati",
"assessmentDocumentDisclaimer": "Questa analisi guidata del caso viene valutata sulla base del seguente strumento di valutazione:",
@ -34,7 +45,9 @@
"submissionNotificationDisclaimer": "I tuoi risultati saranno valutati da {{name}}. Riceverai una notifica non appena la tua valutazione sarà disponibile.",
"submitAssignment": "Consegnare i risultati",
"taskDefinition": "Svolgi le attività parziali e documenta i tuoi risultati.",
"taskDefinitionTitle": "Compito"
"taskDefinitionTitle": "Compito",
"von x Punkten": "di {{x}} punti",
"x von y Arbeiten abgeschlossen": "{{x}} di {{y}} compiti completati"
},
"circlePage": {
"circleContentBoxTitle": "Cosa apprenderai in questo Circle",
@ -169,6 +182,7 @@
"feedback_many": "Feedback",
"feedback_one": "Feedback",
"feedback_other": "Feedback",
"im circle x anschauen": "Guarda nel cerchio «{{x}}»",
"introduction": "Introduzione",
"learningPath": "Percorso di formazione",
"learningSequence": "Sequenza di apprendimento",

View File

@ -103,7 +103,7 @@ const getNextStepLink = (courseSession: CourseSession) => {
<aside class="m-8 lg:order-1 lg:w-[343px]">
<div class="mx-auto mb-6 pb-6 text-center">
<img
class="mb-4 inline-block max-w-[150px] rounded-full"
class="mb-4 inline-block h-36 w-36 rounded-full"
:src="userStore.avatar_url"
/>
<div>

View File

@ -25,7 +25,7 @@ onMounted(async () => {
await cockpitStore.loadCourseSessionUsers(courseSession.value.id);
cockpitStore.courseSessionUsers?.forEach((csu) => {
competenceStore.loadCompetenceProfilePage(
props.courseSlug + "-competence",
props.courseSlug + "-competencenavi-competences",
csu.user_id
);

View File

@ -5,7 +5,7 @@ import { useLearningPathStore } from "@/stores/learningPath";
import * as log from "loglevel";
import { computed, onMounted } from "vue";
import CompetenceDetail from "@/components/competences/CompetenceDetail.vue";
import CompetenceDetail from "@/pages/competence/ActionCompetenceDetail.vue";
import LearningPathPathView from "@/pages/learningPath/learningPathPage/LearningPathPathView.vue";
const props = defineProps<{

View File

@ -13,6 +13,7 @@ import { useQuery } from "@urql/vue";
import log from "loglevel";
import { computed, onMounted, reactive } from "vue";
import { useRouter } from "vue-router";
import { getPreviousRoute } from "@/router/history";
const props = defineProps<{
courseSlug: string;
@ -53,11 +54,17 @@ onMounted(async () => {
);
});
const previousRoute = getPreviousRoute();
function close() {
if (previousRoute) {
router.push(previousRoute);
} else {
router.push({
path: `/course/${props.courseSlug}/cockpit/assignment`,
path: `/course/${props.courseSlug}/cockpit`,
});
}
}
const assignmentCompletion = computed(
() =>
@ -79,7 +86,9 @@ const assignment = computed(
>
<div class="flex items-center text-gray-900">
<it-icon-assignment class="h-6 w-6"></it-icon-assignment>
<div class="ml-2">Geleitete Fallarbeit: {{ assignment?.title }}</div>
<div class="ml-2">
{{ $t("a.Geleitete Fallarbeit") }}: {{ assignment?.title }}
</div>
</div>
<button
type="button"
@ -94,11 +103,11 @@ const assignment = computed(
v-if="assignment && assignmentCompletion && state.assignmentUser"
class="relative"
>
<div class="h-content flex flex-col sm:flex-row">
<div class="h-full overflow-y-auto bg-white sm:w-1/2">
<div class="md:h-content flex flex-col md:flex-row">
<div class="bg-white md:h-full md:w-1/2 md:overflow-y-auto">
<!-- Left part content goes here -->
<div class="p-10" data-cy="student-submission">
<h3>Ergebnisse</h3>
<h3>{{ $t("a.Ergebnisse") }}</h3>
<div class="my-6 flex items-center">
<img
@ -117,7 +126,9 @@ const assignment = computed(
></AssignmentSubmissionResponses>
</div>
</div>
<div class="overflow-y-auto bg-gray-200 sm:w-1/2">
<div
class="order-first bg-gray-200 md:order-last md:w-1/2 md:overflow-y-auto"
>
<EvaluationContainer
:assignment-completion="assignmentCompletion"
:assignment-user="state.assignmentUser"

View File

@ -94,7 +94,7 @@ function finishButtonEnabled() {
<template>
<div class="flex min-h-full flex-col">
<div class="flex-1 overflow-y-auto">
<div class="overflow-y-auto">
<section class="p-10">
<EvaluationIntro
v-if="stepIndex === 0"
@ -155,7 +155,7 @@ function finishButtonEnabled() {
@click="emit('close')"
>
<span class="flex items-center">
Bewertung abschliessen
{{ $t("a.Bewertung abschliessen") }}
<it-icon-check class="ml-2 h-6 w-6"></it-icon-check>
</span>
</button>

View File

@ -48,28 +48,36 @@ async function startEvaluation() {
<template>
<div>
<div class="mb-4">
{{ props.assignmentUser.first_name }} {{ props.assignmentUser.last_name }} hat die
Ergebnisse am
{{ dayjs(props.assignmentCompletion.submitted_at).format("DD.MM.YYYY") }} um
{{ dayjs(props.assignmentCompletion.submitted_at).format("HH.mm") }} Uhr
abgegeben.
{{
$t("assignment.x hat die Ergebnisse am y um z Uhr abgegeben", {
x: props.assignmentUser.first_name + " " + props.assignmentUser.last_name,
y: dayjs(props.assignmentCompletion.submitted_at).format("DD.MM.YYYY"),
z: dayjs(props.assignmentCompletion.submitted_at).format("HH.mm"),
})
}}
</div>
<h3>Bewertung</h3>
<h3>{{ $t("a.Bewertung") }}</h3>
<p v-if="props.dueDate" class="my-4">
Du musst die Bewertung bis am {{ props.dueDate.format("DD.MM.YYYY") }} um
{{ props.dueDate.format("HH.mm") }} Uhr abschliessen und freigeben.
{{
$t(
"assignment.Du musst die Bewertung bis am x um y Uhr abschliessen und freigeben",
{
x: props.dueDate.format("DD.MM.YYYY"),
y: props.dueDate.format("HH.mm"),
}
)
}}
</p>
<p class="my-4">
Die Gesamtpunktzahl und die daraus resultierende Note wird auf Grund des
hinterlegeten Beurteilungsinstrument berechnet.
{{ $t("assignment.evaluationInstrumentDescriptionText") }}
</p>
<p class="my-4">
<a :href="props.assignment.evaluation_document_url" class="link" target="_blank">
Beurteilungsinstrument anzeigen
{{ $t("a.Beurteilungsinstrument anzeigen") }}
</a>
</p>
@ -84,16 +92,16 @@ async function startEvaluation() {
props.assignmentCompletion.completion_status === 'EVALUATION_IN_PROGRESS'
"
>
Bewertung fortsetzen
{{ $t("a.Bewertung fortsetzen") }}
</span>
<span
v-else-if="
props.assignmentCompletion.completion_status === 'EVALUATION_SUBMITTED'
"
>
Bewertung ansehen
{{ $t("a.Bewertung ansehen") }}
</span>
<span v-else>Bewertung starten</span>
<span v-else>{{ $t("a.Bewertung starten") }}</span>
</button>
</div>
</div>

View File

@ -102,17 +102,20 @@ const evaluationUser = computed(() => {
<h3 v-if="evaluationUser && props.showEvaluationUser" class="mb-6">
Bewertung von {{ evaluationUser.first_name }} {{ evaluationUser.last_name }}
</h3>
<h3 v-else class="mb-6">Bewertung Freigabe</h3>
<h3 v-else class="mb-6">{{ $t("a.Bewertung Freigabe") }}</h3>
<section class="mb-6 border p-6">
<div class="text-lg font-bold">Note: {{ grade }}</div>
<div class="text-gray-900">
Gesamtpunktezahl {{ userPoints }} / {{ maxPoints }}
<section class="flex items-center">
<div class="heading-1 py-4">
{{ userPoints }}
</div>
<div class="pl-2">
{{ $t("assignment.von x Punkten", { x: maxPoints }) }}
</div>
</section>
<p class="my-4">
Die Gesamtpunktzahl und die daraus resultierende Note wird auf Grund des
hinterlegeten Beurteilungsinstrument berechnet.
{{ $t("assignment.evaluationInstrumentDescriptionText") }}
</p>
<p class="my-4">
@ -121,14 +124,14 @@ const evaluationUser = computed(() => {
class="link"
target="_blank"
>
Beurteilungsinstrument anzeigen
{{ $t("a.Beurteilungsinstrument anzeigen") }}
</a>
</p>
<div
v-if="props.assignmentCompletion.completion_status === 'EVALUATION_SUBMITTED'"
>
Freigabetermin:
{{ $t("assignment.dueDateEvaluation") }}:
{{
dayjs(props.assignmentCompletion.evaluation_submitted_at).format("DD.MM.YYYY")
}}
@ -138,7 +141,7 @@ const evaluationUser = computed(() => {
</div>
<div v-else>
<button class="btn-primary text-large" @click="submitEvaluation()">
Bewertung freigeben
{{ $t("a.Bewertung freigeben") }}
</button>
</div>
@ -154,7 +157,8 @@ const evaluationUser = computed(() => {
<article class="border-t py-4">
<div class="flex flex-row justify-between">
<div class="mb-4 text-gray-900">
Bewertungskriterium {{ index + 1 }}: {{ task.value.title }}
{{ $t("a.Beurteilungskriterium") }} {{ index + 1 }}:
{{ task.value.title }}
</div>
<div
v-if="
@ -193,7 +197,7 @@ const evaluationUser = computed(() => {
</section>
<div>
<span class="font-bold">Begründung:</span>
<span class="font-bold">{{ $t("a.Begründung") }}:</span>
{{ evaluationForTask(task).text }}
</div>
</article>

View File

@ -87,7 +87,7 @@ const evaluateAssignmentCompletionDebounced = useDebounceFn(
<!-- eslint-disable vue/no-v-html -->
<div data-cy="evaluation-task">
<div class="text-bold mb-4 text-sm">
Beurteilungskriterium {{ taskIndex + 1 }} /
{{ $t("a.Beurteilungskriterium") }} {{ taskIndex + 1 }} /
{{ props.assignment.evaluation_tasks.length }}
{{ task.value.title }}
</div>
@ -127,9 +127,9 @@ const evaluateAssignmentCompletionDebounced = useDebounceFn(
<ItTextarea
class="mt-8"
:model-value="expertData.text ?? ''"
label="Begründung"
:label="$t('a.Begründung')"
:disabled="!props.allowEdit"
placeholder="Hier muss zwingend eine Begründung erfasst werden."
:placeholder="$t('assignment.justificationRequiredText')"
data-cy="reason-text"
@update:model-value="onUpdateText($event)"
></ItTextarea>

View File

@ -95,7 +95,7 @@ const assignmentDetail = computed(() =>
:data-cy="csu.last_name"
>
<template #center>
<section class="flex w-full justify-between px-8">
<section class="flex w-full justify-between">
<div
v-if="
state.gradedUsers.map((gradedUser) => gradedUser.user).includes(csu)
@ -107,7 +107,7 @@ const assignmentDetail = computed(() =>
>
<it-icon-check class="h-4/5 w-4/5"></it-icon-check>
</div>
<div class="ml-2">Bewertung freigegeben</div>
<div class="ml-2">{{ $t("a.Bewertung freigegeben") }}</div>
</div>
<div
v-else-if="state.assignmentSubmittedUsers.includes(csu)"
@ -118,7 +118,7 @@ const assignmentDetail = computed(() =>
>
<it-icon-check class="h-6 w-6"></it-icon-check>
</div>
<div class="ml-2">Ergebnisse abgegeben</div>
<div class="ml-2">{{ $t("a.Ergebnisse abgegeben") }}</div>
</div>
<div
@ -126,10 +126,10 @@ const assignmentDetail = computed(() =>
state.gradedUsers.map((gradedUser) => gradedUser.user).includes(csu)
"
>
Note:
{{
state.gradedUsers.find((u) => u.user.user_id === csu.user_id)?.grade
state.gradedUsers.find((u) => u.user.user_id === csu.user_id)?.points
}}
{{ $t("a.Punkte") }}
</div>
</section>
</template>
@ -137,10 +137,10 @@ const assignmentDetail = computed(() =>
<router-link
v-if="state.assignmentSubmittedUsers.includes(csu)"
:to="`/course/${props.courseSession.course.slug}/cockpit/assignment/${learningContentAssignment.content_assignment_id}/${csu.user_id}`"
class="w-full text-right underline"
class="link lg:w-full lg:text-right"
data-cy="show-results"
>
{{ $t("Ergebnisse anzeigen") }}
{{ $t("a.Ergebnisse anschauen") }}
</router-link>
</template>
</ItPersonRow>

View File

@ -96,6 +96,10 @@ const loadAttendanceData = async () => {
}
};
function editAgain() {
state.attendanceSaved = false;
}
onMounted(() => {
log.debug("AttendanceCheckPage mounted");
loadAttendanceData();
@ -153,8 +157,11 @@ watch(
</div>
<div v-else class="self-center">
<p class="text-base">
{{ $t("Die Anwesenheit wurde definitiv bestätigt.") }}
{{ $t("a.Die Anwesenheit wurde definitiv bestätigt") }}
</p>
<button class="btn-link link" @click="editAgain()">
{{ $t("a.Erneut bearbeiten") }}
</button>
</div>
</div>

View File

@ -1,21 +1,36 @@
<script setup lang="ts">
import { useCurrentCourseSession } from "@/composables";
import DueDateSingle from "@/components/dueDates/DueDateSingle.vue";
import { computed } from "vue";
import { useCockpitStore } from "@/stores/cockpit";
const cockpitStore = useCockpitStore();
const courseSession = useCurrentCourseSession();
const dueDates = courseSession.value.due_dates.slice(0, 2);
const circleDates = computed(() => {
const dueDates = courseSession.value.due_dates.filter((dueDate) => {
return cockpitStore.selectedCircles.includes(
dueDate?.circle?.translation_key ?? ""
);
});
return dueDates.slice(0, 4);
});
</script>
<template>
<div class="flex flex-col space-y-2">
<h3 class="heading-3">{{ $t("Nächste Termine") }}</h3>
<div
v-for="dueDate in dueDates"
v-for="dueDate in circleDates"
:key="dueDate.id"
class="border-t border-gray-500 pt-2"
>
<DueDateSingle :due-date="dueDate" single-line></DueDateSingle>
<DueDateSingle :due-date="dueDate" :single-line="true"></DueDateSingle>
</div>
<div v-if="circleDates.length === 0">{{ $t("dueDates.noDueDatesAvailable") }}</div>
<a class="border-t border-gray-500 pt-8 underline" href="">
{{ $t("dueDates.showAllDueDates") }}
</a>
<div v-if="dueDates.length === 0">{{ $t("dueDates.noDueDatesAvailable") }}</div>
</div>
</template>

View File

@ -95,8 +95,8 @@ function setActiveClasses(translationKey: string) {
</div>
</div>
<!-- Status -->
<div class="mb-4 grid grid-rows-3 gap-4 lg:grid-cols-3 lg:grid-rows-none">
<div class="flex flex-col justify-between bg-white px-6 py-5">
<div class="mb-4 gap-4 lg:grid lg:grid-cols-3 lg:grid-rows-none">
<div class="my-4 flex flex-col justify-between bg-white p-6 lg:my-0">
<div>
<h3 class="heading-3 mb-4 flex items-center gap-2">
{{ $t("Trainerunterlagen") }}
@ -115,7 +115,7 @@ function setActiveClasses(translationKey: string) {
</a>
</div>
</div>
<div class="flex flex-col justify-between bg-white p-6">
<div class="my-4 flex flex-col justify-between bg-white p-6 lg:my-0">
<div>
<h3 class="heading-3 mb-4 flex items-center gap-2">
{{ $t("Anwesenheitskontrolle Präsenzkurse") }}
@ -158,13 +158,13 @@ function setActiveClasses(translationKey: string) {
>
<template #center>
<div
class="mt-2 flex w-full flex-row items-center justify-between lg:mt-0"
class="mt-2 flex w-full flex-col items-center justify-between lg:mt-0 lg:flex-row"
>
<ul class="w-full">
<li
v-for="(circle, i) of cockpitStore.selectedCircles"
:key="i"
class="flex h-12 items-center justify-between"
class="flex flex-col justify-between lg:h-12 lg:flex-row lg:items-center"
>
<LearningPathDiagram
v-if="
@ -194,7 +194,7 @@ function setActiveClasses(translationKey: string) {
<it-icon-smiley-thinking
class="mr-2 inline-block h-8 w-8"
></it-icon-smiley-thinking>
<p class="text-bold inline-block">
<p class="text-bold inline-block w-6">
{{ userCountStatusForCircle(csu.user_id, circle).FAIL }}
</p>
</div>
@ -202,7 +202,7 @@ function setActiveClasses(translationKey: string) {
<it-icon-smiley-happy
class="mr-2 inline-block h-8 w-8"
></it-icon-smiley-happy>
<p class="text-bold inline-block">
<p class="text-bold inline-block w-6">
{{ userCountStatusForCircle(csu.user_id, circle).SUCCESS }}
</p>
</li>
@ -210,7 +210,7 @@ function setActiveClasses(translationKey: string) {
<it-icon-smiley-neutral
class="mr-2 inline-block h-8 w-8"
></it-icon-smiley-neutral>
<p class="text-bold inline-block">
<p class="text-bold inline-block w-6">
{{ userCountStatusForCircle(csu.user_id, circle).UNKNOWN }}
</p>
</li>
@ -222,7 +222,7 @@ function setActiveClasses(translationKey: string) {
<template #link>
<router-link
:to="`/course/${props.courseSlug}/cockpit/profile/${csu.user_id}`"
class="w-full text-right underline"
class="link w-full lg:text-right"
>
{{ $t("general.profileLink") }}
</router-link>

View File

@ -91,7 +91,7 @@ const getShowDetailsText = (lc: LearningContent) => {
if (isAssignment(lc)) {
const assignmentType = (lc as LearningContentAssignment).assignment_type;
if (assignmentType === "CASEWORK" || assignmentType === "REFLECTION") {
return t("Ergebnisse anschauen");
return t("a.Ergebnisse anschauen");
} else if (
assignmentType === "PREP_ASSIGNMENT" ||
assignmentType === "CONDITION_ACCEPTANCE"
@ -132,10 +132,15 @@ const getIconName = (lc: LearningContent) => {
<div
v-for="submittable in submittables"
:key="submittable.id"
class="flex flex-row justify-between py-4"
class="flex flex-col justify-between gap-2 py-4 lg:flex-row lg:gap-4"
>
<div class="flex w-1/3 flex-row items-center space-x-4 pr-2">
<component :is="getIconName(submittable.content)" class="h-9 w-9"></component>
<div class="flex flex-row items-center gap-2 lg:w-1/3">
<div class="min-h-9 min-w-9">
<component
:is="getIconName(submittable.content)"
class="min-h-9 min-w-9"
></component>
</div>
<div class="flex flex-col">
<h3 class="text-bold flex items-center gap-2">{{ submittable.title }}</h3>
<p class="text-gray-800">Circle «{{ submittable.circleName }}»</p>
@ -154,7 +159,7 @@ const getIconName = (lc: LearningContent) => {
:circle-id="submittable.content.parentCircle.id"
class="grow pr-8"
></FeedbackSubmissionProgress>
<div class="flex w-1/4 items-center justify-end">
<div class="flex items-center lg:w-1/4 lg:justify-end">
<button class="btn-primary">
<router-link
:to="submittable.detailsLink"

View File

@ -1,11 +1,10 @@
<script setup lang="ts">
import PerformanceCriteriaRow from "@/components/competences/PerformanceCriteriaRow.vue";
import ItProgress from "@/components/ui/ItProgress.vue";
import ItToggleArrow from "@/components/ui/ItToggleArrow.vue";
import { useCompetenceStore } from "@/stores/competence";
import type { CompetencePage } from "@/types";
import log from "loglevel";
import { ref } from "vue";
import { ref, watch } from "vue";
import SinglePerformanceCriteriaRow from "@/pages/competence/SinglePerformanceCriteriaRow.vue";
const competenceStore = useCompetenceStore();
@ -14,17 +13,26 @@ interface Props {
courseSlug: string;
showAssessAgain?: boolean;
isInline?: boolean;
allOpen?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
showAssessAgain: true,
isInline: false,
allOpen: false,
});
log.debug("PerformanceCriteriaRow created", props);
const isOpen = ref(false);
watch(
() => props.allOpen,
(newValue) => {
isOpen.value = newValue;
}
);
const togglePerformanceCriteria = () => {
isOpen.value = !isOpen.value;
};
@ -32,7 +40,7 @@ const togglePerformanceCriteria = () => {
<template>
<div>
<div :class="{ 'mb-4 border-b pb-8': isOpen }" class="-mx-8 px-8">
<div class="-mx-8 border-b px-8">
<div
class="flex flex-row items-center justify-between"
:class="props.isInline ? '' : 'mb-4'"
@ -41,40 +49,27 @@ const togglePerformanceCriteria = () => {
@click="togglePerformanceCriteria()"
>
<h2 :class="props.isInline ? ['text-bold', 'w-2/5'] : 'text-large'">
{{ competence.competence_id }} {{ competence.title }}
{{ competence.title }} ({{ competence.competence_id }})
</h2>
<ItProgress
v-if="isInline"
class="w-[330px]"
:status-count="
competenceStore.calcStatusCount(
competenceStore.criteriaByCompetence(competence)
)
"
></ItProgress>
<ItToggleArrow :is-open="isOpen" :small="isInline"></ItToggleArrow>
</div>
<ItProgress
v-if="!isInline"
:status-count="
competenceStore.calcStatusCount(
competenceStore.criteriaByCompetence(competence)
)
"
></ItProgress>
</div>
<ul v-if="isOpen">
<li class="my-4 border-b pb-4 font-bold">
{{ $t("a.Leistungsziele") }}
</li>
<li
v-for="performanceCriteria in competenceStore.criteriaByCompetence(competence)"
:key="performanceCriteria.id"
class="mb-4 border-b pb-4 last:border-0"
class="my-4 border-b pb-4 last:border-0"
>
<PerformanceCriteriaRow
<SinglePerformanceCriteriaRow
:criteria="performanceCriteria"
:show-state="true"
:show-state="false"
:course-slug="props.courseSlug"
:show-assess-again="props.showAssessAgain"
></PerformanceCriteriaRow>
></SinglePerformanceCriteriaRow>
</li>
</ul>
</div>

View File

@ -0,0 +1,59 @@
<script setup lang="ts">
import CompetenceDetail from "@/pages/competence/ActionCompetenceDetail.vue";
import { useCompetenceStore } from "@/stores/competence";
import * as log from "loglevel";
import { ref } from "vue";
log.debug("CompetenceListPage created");
const props = defineProps<{
courseSlug: string;
}>();
const competenceStore = useCompetenceStore();
const isOpenAll = ref(false);
function toggleOpen() {
log.debug("toggleOpen");
isOpenAll.value = !isOpenAll.value;
}
</script>
<template>
<div class="container-large">
<h2 class="py-4">{{ $t("a.Handlungskompetenzen") }}</h2>
<div class="flex flex-col justify-between gap-4 py-8 lg:flex-row">
<div class="text-xl lg:w-3/4">
{{ $t("competence.listPageDescription") }}
</div>
<div class="lg:whitespace-nowrap">
<button class="link" @click="toggleOpen()">
<span v-if="isOpenAll">
{{ $t("a.Alle zuklappen") }}
</span>
<span v-else>
{{ $t("a.Alle aufklappen") }}
</span>
</button>
</div>
</div>
<ul v-if="competenceStore.competenceProfilePage()">
<li
v-for="competence in competenceStore.competences()"
:key="competence.id"
class="mb-8 bg-white px-8 pt-6"
>
<CompetenceDetail
:competence="competence"
:course-slug="props.courseSlug"
:all-open="isOpenAll"
></CompetenceDetail>
</li>
</ul>
</div>
</template>
<style scoped></style>

View File

@ -0,0 +1,98 @@
<script setup lang="ts">
import type { CompetenceCertificateAssignment } from "@/types";
import * as log from "loglevel";
log.debug("CompetenceAssignmentRow setup");
export interface Props {
assignment: CompetenceCertificateAssignment;
addBorderBottom?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
addBorderBottom: false,
});
const getIconName = () => {
if (props.assignment.assignment_type === "EDONIQ_TEST") {
return "it-icon-test-large";
}
return "it-icon-assignment-large";
};
</script>
<template>
<div
class="flex flex-col gap-4 py-8 lg:flex-row lg:items-center lg:gap-0"
:class="{ 'border-b': props.addBorderBottom }"
:data-cy="`assignment-${assignment.slug}`"
>
<component :is="getIconName()" class="mr-4 hidden h-9 w-9 lg:block"></component>
<div class="flex flex-col lg:w-[420px]">
<h3 class="text-bold flex items-center gap-2">{{ assignment.title }}</h3>
<p class="text-gray-800">
<a
v-if="assignment.learning_content"
:href="assignment.frontend_url"
class="link"
>
{{
$t("general.im circle x anschauen", {
x: assignment.learning_content.circle.title,
})
}}
</a>
<span v-else>Fehler, Lerninhalt nicht korrekt verknüpft</span>
</p>
</div>
<div class="grow lg:px-8">
<div
v-if="assignment.completion?.completion_status === 'EVALUATION_SUBMITTED'"
class="flex items-center"
>
<div
class="relative flex h-7 w-7 items-center justify-center rounded-full border border-green-500 bg-green-500"
>
<it-icon-check class="h-4/5 w-4/5"></it-icon-check>
</div>
<div class="ml-2">{{ $t("a.Bewertung freigegeben") }}</div>
</div>
<div
v-else-if="
['EVALUATION_IN_PROGRESS', 'SUBMITTED'].includes(
assignment.completion?.completion_status || ''
)
"
class="flex items-center"
>
<div
class="relative flex h-7 w-7 items-center justify-center rounded-full border border-green-500"
>
<it-icon-check class="h-6 w-6"></it-icon-check>
</div>
<div class="ml-2">{{ $t("a.Ergebnisse abgegeben") }}</div>
</div>
</div>
<div>
<div
v-if="assignment.completion?.completion_status === 'EVALUATION_SUBMITTED'"
class="flex flex-col lg:items-center"
>
<div class="flex flex-col lg:items-center">
<div class="heading-2">
{{ assignment.completion?.evaluation_points }}
</div>
<div>
{{ $t("assignment.von x Punkten", { x: assignment.max_points }) }}
</div>
</div>
</div>
<div v-else class="flex flex-col lg:items-center">
<div>{{ $t("a.Höchstpunktzahl") }}</div>
<div>{{ assignment.max_points }} {{ $t("a.Punkte") }}</div>
</div>
</div>
</div>
</template>
<style scoped></style>

View File

@ -0,0 +1,118 @@
<script setup lang="ts">
import * as log from "loglevel";
import type { CompetenceCertificate } from "@/types";
import CompetenceAssignmentRow from "@/pages/competence/CompetenceAssignmentRow.vue";
import { computed } from "vue";
import ItProgress from "@/components/ui/ItProgress.vue";
import {
assignmentsMaxEvaluationPoints,
assignmentsUserPoints,
competenceCertificateProgressStatusCount,
} from "@/pages/competence/utils";
log.debug("CompetenceCertificateComponent setup");
const props = defineProps<{
competenceCertificate: CompetenceCertificate;
detailView: boolean;
}>();
const totalPointsEvaluatedAssignments = computed(() => {
return assignmentsMaxEvaluationPoints(props.competenceCertificate.assignments);
});
const userPointsEvaluatedAssignments = computed(() => {
return assignmentsUserPoints(props.competenceCertificate.assignments);
});
const numAssignmentsEvaluated = computed(() => {
return props.competenceCertificate.assignments.filter((a) => {
return a.completion?.completion_status === "EVALUATION_SUBMITTED";
}).length;
});
const numAssignmentsTotal = computed(() => {
return props.competenceCertificate.assignments.length;
});
const progressStatusCount = computed(() => {
return competenceCertificateProgressStatusCount(
props.competenceCertificate.assignments
);
});
</script>
<template>
<div>
<div
class="mb-4 bg-white p-8"
:data-cy="`certificate-${competenceCertificate.slug}`"
>
<div class="flex flex-col lg:flex-row lg:items-center">
<div
v-if="numAssignmentsEvaluated < numAssignmentsTotal"
class="rounded-full bg-gray-200 px-2.5 py-0.5 text-sm lg:ml-2"
>
{{ $t("a.Zwischenstand") }}
</div>
<h3
class="mt-2 lg:order-first lg:mt-0"
:class="{ 'heading-2': props.detailView }"
>
{{ props.competenceCertificate.title }}
</h3>
</div>
<section v-if="userPointsEvaluatedAssignments > 0" class="flex items-center">
<div
class="py-4"
:class="{ 'heading-1': props.detailView, 'heading-2': !props.detailView }"
>
{{ userPointsEvaluatedAssignments }}
</div>
<div class="ml-1">
{{ $t("assignment.von x Punkten", { x: totalPointsEvaluatedAssignments }) }}
</div>
</section>
<section v-else class="py-2">
{{ $t("a.competenceCertificateNoUserPoints") }}
</section>
<ItProgress :status-count="progressStatusCount" />
<div>
{{
$t("assignment.x von y Kompetenznachweis-Elementen abgeschlossen", {
x: numAssignmentsEvaluated,
y: numAssignmentsTotal,
})
}}
</div>
<div v-if="!props.detailView">
<router-link
:to="competenceCertificate.frontend_url"
class="btn-text mt-4 inline-flex items-center py-2 pl-0"
:data-cy="`certificate-${competenceCertificate.slug}-detail-link`"
>
<span>{{ $t("a.Details anzeigen") }}</span>
<it-icon-arrow-right></it-icon-arrow-right>
</router-link>
</div>
</div>
<div v-if="props.detailView">
<div
v-for="(assignment, index) in competenceCertificate.assignments"
:key="assignment.id"
class="bg-white px-8"
>
<CompetenceAssignmentRow
:assignment="assignment"
:add-border-bottom="index < competenceCertificate.assignments.length - 1"
></CompetenceAssignmentRow>
</div>
</div>
</div>
</template>
<style scoped></style>

View File

@ -0,0 +1,59 @@
<script setup lang="ts">
import log from "loglevel";
import { COMPETENCE_NAVI_CERTIFICATE_QUERY } from "@/graphql/queries";
import { useQuery } from "@urql/vue";
import { computed, onMounted } from "vue";
import type { CompetenceCertificate } from "@/types";
import { useCurrentCourseSession } from "@/composables";
import CompetenceCertificateComponent from "@/pages/competence/CompetenceCertificateComponent.vue";
const props = defineProps<{
courseSlug: string;
certificateSlug: string;
}>();
log.debug("CompetenceCertificateDetailPage setup", props);
const courseSession = useCurrentCourseSession();
const certificatesQuery = useQuery({
query: COMPETENCE_NAVI_CERTIFICATE_QUERY,
variables: {
courseSlug: props.courseSlug,
courseSessionId: courseSession.value.id.toString(),
},
});
const certificate = computed(() => {
return (
(certificatesQuery.data.value?.competence_certificate_list
?.competence_certificates as unknown as CompetenceCertificate[]) ?? []
).find((cc) => cc.slug.endsWith(props.certificateSlug));
});
onMounted(async () => {
// log.debug("AssignmentView mounted", props.assignmentId, props.userId);
});
</script>
<template>
<div class="container-large">
<nav class="py-4">
<router-link
class="btn-text inline-flex items-center pl-0"
:to="`/course/${props.courseSlug}/competence/certificates`"
>
<it-icon-arrow-left />
<span>{{ $t("general.back") }}</span>
</router-link>
</nav>
<div v-if="certificate">
<CompetenceCertificateComponent
:competence-certificate="certificate"
:detail-view="true"
></CompetenceCertificateComponent>
</div>
</div>
</template>
<style scoped></style>

View File

@ -0,0 +1,100 @@
<script setup lang="ts">
import log from "loglevel";
import { COMPETENCE_NAVI_CERTIFICATE_QUERY } from "@/graphql/queries";
import { useQuery } from "@urql/vue";
import { computed, onMounted } from "vue";
import type { CompetenceCertificate } from "@/types";
import { useCurrentCourseSession } from "@/composables";
import CompetenceCertificateComponent from "@/pages/competence/CompetenceCertificateComponent.vue";
import {
assignmentsMaxEvaluationPoints,
assignmentsUserPoints,
} from "@/pages/competence/utils";
const props = defineProps<{
courseSlug: string;
}>();
log.debug("CompetenceCertificateListPage setup", props);
const courseSession = useCurrentCourseSession();
const certificatesQuery = useQuery({
query: COMPETENCE_NAVI_CERTIFICATE_QUERY,
variables: {
courseSlug: props.courseSlug,
courseSessionId: courseSession.value.id.toString(),
},
});
const competenceCertificates = computed(() => {
return (
(certificatesQuery.data.value?.competence_certificate_list
?.competence_certificates as unknown as CompetenceCertificate[]) ?? []
);
});
const assignments = computed(() => {
return competenceCertificates.value.flatMap((cc) => cc.assignments);
});
const totalPointsEvaluatedAssignments = computed(() => {
return assignmentsMaxEvaluationPoints(assignments.value);
});
const userPointsEvaluatedAssignments = computed(() => {
return assignmentsUserPoints(assignments.value);
});
const numAssignmentsEvaluated = computed(() => {
return assignments.value.filter((a) => {
return a.completion?.completion_status === "EVALUATION_SUBMITTED";
}).length;
});
onMounted(async () => {
// log.debug("AssignmentView mounted", props.assignmentId, props.userId);
});
</script>
<template>
<div class="container-large">
<h2 class="mb-4 lg:py-4">{{ $t("a.Kompetenznachweise") }}</h2>
<div class="mb-4 bg-white p-8" data-cy="certificate-total-points-text">
<div class="flex flex-col lg:flex-row lg:items-center">
<div
v-if="numAssignmentsEvaluated < assignments.length"
class="rounded-full bg-gray-200 px-2.5 py-0.5 text-sm lg:ml-2"
>
{{ $t("a.Zwischenstand") }}
</div>
<h3 class="mt-2 lg:order-first lg:mt-0">{{ $t("a.Gesamtpunktzahl") }}</h3>
</div>
<section v-if="userPointsEvaluatedAssignments > 0" class="flex items-center">
<div class="heading-1 py-4">
{{ userPointsEvaluatedAssignments }}
</div>
<div class="pl-2">
{{ $t("assignment.von x Punkten", { x: totalPointsEvaluatedAssignments }) }}
</div>
</section>
<section v-else class="my-4">
{{ $t("a.competenceCertificateNoUserPoints") }}
</section>
</div>
<div
v-for="competenceCertificate in competenceCertificates"
:key="competenceCertificate.id"
>
<CompetenceCertificateComponent
:competence-certificate="competenceCertificate"
:detail-view="false"
></CompetenceCertificateComponent>
</div>
</div>
</template>
<style scoped></style>

View File

@ -1,176 +1,195 @@
<script setup lang="ts">
import PerformanceCriteriaRow from "@/components/competences/PerformanceCriteriaRow.vue";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import log from "loglevel";
import { COMPETENCE_NAVI_CERTIFICATE_QUERY } from "@/graphql/queries";
import { useQuery } from "@urql/vue";
import { computed } from "vue";
import type { CompetenceCertificate } from "@/types";
import { useCurrentCourseSession } from "@/composables";
import {
assignmentsMaxEvaluationPoints,
assignmentsUserPoints,
competenceCertificateProgressStatusCount,
} from "@/pages/competence/utils";
import ItProgress from "@/components/ui/ItProgress.vue";
import { useCompetenceStore } from "@/stores/competence";
import maxBy from "lodash/maxBy";
import orderBy from "lodash/orderBy";
import * as log from "loglevel";
import { computed } from "vue";
log.debug("CompetenceIndexPage created");
const props = defineProps<{
courseSlug: string;
}>();
log.debug("CompetenceIndexPage created", props);
log.debug("CompetenceIndexPage setup", props);
const courseSession = useCurrentCourseSession();
const competenceStore = useCompetenceStore();
const failedCriteria = computed(() => {
return competenceStore
.flatPerformanceCriteria()
.filter((criteria) => {
return criteria.completion_status === "FAIL";
})
.slice(0, 3);
});
const lastUpdatedCompetences = computed(() => {
return orderBy(
competenceStore.competences(),
[
(competence) => {
let criteria = competence.children;
if (competenceStore.selectedCircle.id != "all") {
criteria = criteria.filter((criteria) => {
return (
criteria.circle.translation_key === competenceStore.selectedCircle.id
);
});
}
return (
maxBy(criteria, "completion_status_updated_at")
?.completion_status_updated_at || ""
);
const certificatesQuery = useQuery({
query: COMPETENCE_NAVI_CERTIFICATE_QUERY,
variables: {
courseSlug: props.courseSlug,
courseSessionId: courseSession.value.id.toString(),
},
],
["desc"]
).slice(0, 3);
});
const countStatus = computed(() => {
const competenceCertificates = computed(() => {
return (
(certificatesQuery.data.value?.competence_certificate_list
?.competence_certificates as unknown as CompetenceCertificate[]) ?? []
);
});
const allAssignments = computed(() => {
return competenceCertificates.value.flatMap((cc) => cc.assignments);
});
const totalPointsEvaluatedAssignments = computed(() => {
return assignmentsMaxEvaluationPoints(allAssignments.value);
});
const userPointsEvaluatedAssignments = computed(() => {
return assignmentsUserPoints(allAssignments.value);
});
const performanceCriteriaStatusCount = computed(() => {
return competenceStore.calcStatusCount(competenceStore.flatPerformanceCriteria());
});
</script>
<template>
<div class="container-large lg:mt-4">
<div
v-if="competenceStore.competenceProfilePage()"
class="mb-10 flex flex-col justify-between lg:flex-row lg:items-center"
>
<h1>{{ $t("competences.title") }}</h1>
<ItDropdownSelect
v-model="competenceStore.selectedCircle"
class="mt-4 w-full lg:mt-0 lg:w-96"
:items="competenceStore.availableCircles"
></ItDropdownSelect>
<h1 class="mb-8">{{ $t("a.KompetenzNavi") }}</h1>
<section class="mb-4 bg-white p-8">
<div class="flex items-center">
<h3>{{ $t("a.Kompetenznachweise") }}</h3>
</div>
<div class="l mb-4 bg-white px-8 py-4 lg:mb-8 lg:py-8">
<div class="mt-4" data-cy="certificate-total-points-text">
<div v-if="userPointsEvaluatedAssignments > 0">
{{ $t("a.Zwischenstand") }} {{ $t("a.Gesamtpunktzahl") }}:
<span class="font-bold">
{{ userPointsEvaluatedAssignments }}
</span>
{{ $t("assignment.von x Punkten", { x: totalPointsEvaluatedAssignments }) }}
</div>
<div v-else>
{{ $t("a.competenceCertificateNoUserPoints") }}
</div>
</div>
<div>
<h3 class="border-b pb-4">{{ $t("competences.lastImprovements") }}</h3>
<ul>
<li
v-for="competence in lastUpdatedCompetences"
:key="competence.id"
class="flex flex-col border-b py-4 last:mb-8 lg:flex-row lg:items-center"
<div class="mt-4">
<div
v-for="certificate in competenceCertificates"
:key="certificate.id"
class="flex flex-col justify-between border-b py-4 first:border-t lg:flex-row lg:items-center"
:data-cy="`certificate-${certificate.slug}`"
>
<p class="mb-4 inline-block lg:mb-0 lg:mr-5 lg:w-1/4">
{{ competence.competence_id }} {{ competence.title }}
</p>
<div class="text-bold text-xl">
{{ certificate.title }}
</div>
<div class="mt-4 lg:mt-0">
<span class="text-bold">
{{ assignmentsUserPoints(certificate.assignments) }}
</span>
{{
$t("assignment.von x Punkten", {
x: assignmentsMaxEvaluationPoints(certificate.assignments),
})
}}
</div>
<div class="flex">
<div>
{{
$t("assignment.x von y Kompetenznachweis-Elementen abgeschlossen", {
x: certificate.assignments.filter(
(a) => a.completion?.completion_status === "EVALUATION_SUBMITTED"
).length,
y: certificate.assignments.length,
})
}}
</div>
<div class="ml-2 hidden w-40 lg:block">
<ItProgress
:status-count="
competenceStore.calcStatusCount(
competenceStore.criteriaByCompetence(competence)
)
competenceCertificateProgressStatusCount(certificate.assignments)
"
></ItProgress>
</li>
</ul>
/>
</div>
</div>
</div>
<div>
<router-link
:to="`${competenceStore.competenceProfilePage()?.frontend_url}/competences`"
class="btn-text inline-flex items-center py-2 pl-0"
:to="`/course/${props.courseSlug}/competence/certificates`"
class="btn-text mt-4 inline-flex items-center py-2 pl-0"
data-cy="certificates-show-all-button"
>
<span>{{ $t("general.showAll") }}</span>
<span>{{ $t("a.Details anzeigen") }}</span>
<it-icon-arrow-right></it-icon-arrow-right>
</router-link>
</div>
</div>
<div class="l mb-4 bg-white px-8 py-4 lg:mb-8 lg:py-8">
</div>
</section>
<section class="mb-4 bg-white px-8 py-4 lg:mb-8 lg:py-8">
<h3 class="mb-4 border-b pb-4 lg:border-0 lg:pb-0">
{{ $t("competences.assessment") }}
{{ $t("a.Selbsteinschätzungen") }}
</h3>
<ul
class="mb-6 flex flex-col lg:flex-row lg:items-center lg:justify-between lg:gap-8"
>
<li
class="mb-4 inline-block flex-1 border-b pb-4 lg:mb-0 lg:border-b-0 lg:border-r lg:pb-0"
class="mb-4 inline-block flex-1 border-b pb-4 lg:mb-0 lg:w-1/3 lg:border-b-0 lg:border-r lg:pb-0"
>
<h5 class="mb-4 text-gray-700">«{{ $t("selfEvaluation.no") }}»</h5>
<div class="flex flex-row items-center">
<it-icon-smiley-thinking class="h-16 w-16"></it-icon-smiley-thinking>
<p class="ml-4 inline-block text-7xl font-bold">{{ countStatus.FAIL }}</p>
<p
class="ml-4 inline-block text-7xl font-bold"
data-cy="self-evaluation-fail"
>
{{ performanceCriteriaStatusCount.FAIL }}
</p>
</div>
</li>
<li
class="mb-4 inline-block flex-1 border-b pb-4 lg:mb-0 lg:border-b-0 lg:border-r lg:pb-0"
class="mb-4 inline-block flex-1 border-b pb-4 lg:mb-0 lg:w-1/3 lg:border-b-0 lg:border-r lg:pb-0"
>
<h5 class="mb-4 text-gray-700">«{{ $t("selfEvaluation.yes") }}»</h5>
<div class="flex flex-row items-center">
<it-icon-smiley-happy class="h-16 w-16"></it-icon-smiley-happy>
<p class="ml-4 inline-block text-7xl font-bold">
{{ countStatus.SUCCESS }}
<p
class="ml-4 inline-block text-7xl font-bold"
data-cy="self-evaluation-success"
>
{{ performanceCriteriaStatusCount.SUCCESS }}
</p>
</div>
</li>
<li class="lg:mb-0flex-1 border-b pb-4 lg:border-b-0 lg:pb-0">
<li class="flex-1 border-b pb-4 lg:mb-0 lg:w-1/3 lg:border-b-0 lg:pb-0">
<h5 class="mb-4 text-gray-700">{{ $t("competences.notAssessed") }}</h5>
<div class="flex flex-row items-center">
<it-icon-smiley-neutral class="h-16 w-16"></it-icon-smiley-neutral>
<p class="ml-4 inline-block text-7xl font-bold">
{{ countStatus.UNKNOWN }}
<p
class="ml-4 inline-block text-7xl font-bold"
data-cy="self-evaluation-unknown"
>
{{ performanceCriteriaStatusCount.UNKNOWN }}
</p>
</div>
</li>
</ul>
<div>
<router-link
:to="`${competenceStore.competenceProfilePage()?.frontend_url}/criteria`"
class="btn-text inline-flex items-center py-2 pl-0"
>
<span>{{ $t("general.showAll") }}</span>
<it-icon-arrow-right></it-icon-arrow-right>
</router-link>
</div>
<div
v-if="failedCriteria.length > 0"
class="l mb-4 bg-white px-8 py-4 lg:mb-8 lg:py-8"
>
<div class="mb-4 flex flex-row items-center border-b pb-4">
<it-icon-smiley-thinking class="mr-5 h-11 w-11"></it-icon-smiley-thinking>
<h3>«{{ $t("selfEvaluation.no") }}»</h3>
</div>
<ul class="mb-6">
<li
v-for="criteria in failedCriteria"
:key="criteria.id"
class="mb-4 border-b pb-4"
>
<PerformanceCriteriaRow
:criteria="criteria"
:course-slug="props.courseSlug"
></PerformanceCriteriaRow>
</li>
</ul>
<router-link
:to="`${competenceStore.competenceProfilePage()?.frontend_url}/criteria`"
class="btn-text inline-flex items-center py-2 pl-0"
:to="`/course/${props.courseSlug}/competence/criteria`"
class="btn-text mt-4 inline-flex items-center py-2 pl-0"
>
<span>{{ $t("general.showAll") }}</span>
<it-icon-arrow-right></it-icon-arrow-right>
</router-link>
</div>
</section>
</div>
</template>

View File

@ -1,51 +0,0 @@
<script setup lang="ts">
import CompetenceDetail from "@/components/competences/CompetenceDetail.vue";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import { useCompetenceStore } from "@/stores/competence";
import * as log from "loglevel";
log.debug("CompetenceListPage created");
const props = defineProps<{
courseSlug: string;
}>();
const competenceStore = useCompetenceStore();
</script>
<template>
<div class="container-large">
<nav class="py-4 lg:pb-8">
<router-link
v-if="competenceStore.competenceProfilePage()"
class="btn-text inline-flex items-center pl-0"
:to="competenceStore.competenceProfilePage()?.frontend_url as string"
>
<it-icon-arrow-left />
<span>{{ $t("general.back") }}</span>
</router-link>
</nav>
<div class="mb-10 flex flex-col items-center justify-between lg:flex-row">
<h1>Kompetenzen</h1>
<ItDropdownSelect
v-model="competenceStore.selectedCircle"
class="mt-4 w-full lg:mt-0 lg:w-96"
:items="competenceStore.availableCircles"
></ItDropdownSelect>
</div>
<ul v-if="competenceStore.competenceProfilePage()">
<li
v-for="competence in competenceStore.competences()"
:key="competence.id"
class="mb-8 bg-white p-8"
>
<CompetenceDetail
:competence="competence"
:course-slug="props.courseSlug"
></CompetenceDetail>
</li>
</ul>
</div>
</template>
<style scoped></style>

View File

@ -2,6 +2,7 @@
import { useCompetenceStore } from "@/stores/competence";
import * as log from "loglevel";
import { onMounted } from "vue";
import { useRoute } from "vue-router";
log.debug("CompetenceParentPage created");
@ -11,11 +12,29 @@ const props = defineProps<{
const competenceStore = useCompetenceStore();
const route = useRoute();
function routeInOverview() {
return route.path.endsWith("/competence");
}
function routeInCompetenceCertificate() {
return route.path.includes("/certificate");
}
function routeInPerformanceCriteria() {
return route.path.endsWith("/criteria");
}
function routeInActionCompetences() {
return route.path.endsWith("/competences");
}
onMounted(async () => {
log.debug("CompetenceParentPage mounted", props.courseSlug);
try {
const competencePageSlug = props.courseSlug + "-competence";
const competencePageSlug = props.courseSlug + "-competencenavi-competences";
await competenceStore.loadCompetenceProfilePage(competencePageSlug);
} catch (error) {
log.error(error);
@ -25,6 +44,46 @@ onMounted(async () => {
<template>
<div class="bg-gray-200">
<nav class="border-b bg-white px-4 lg:px-8">
<ul class="flex flex-col lg:flex-row">
<li
class="inline-block border-t-2 border-t-transparent py-3"
:class="{ 'border-b-2 border-b-blue-900': routeInOverview() }"
>
<router-link :to="`/course/${courseSlug}/competence`">
{{ $t("a.Übersicht") }}
</router-link>
</li>
<li
class="inline-block border-t-2 border-t-transparent py-3 lg:ml-12"
:class="{ 'border-b-2 border-b-blue-900': routeInCompetenceCertificate() }"
>
<router-link :to="`/course/${courseSlug}/competence/certificates`">
{{ $t("a.Kompetenznachweise") }}
</router-link>
</li>
<li
class="inline-block border-t-2 border-t-transparent py-3 lg:ml-12"
:class="{ 'border-b-2 border-b-blue-900': routeInPerformanceCriteria() }"
>
<router-link :to="`/course/${courseSlug}/competence/criteria`">
{{ $t("a.Selbsteinschätzungen") }}
</router-link>
</li>
<li
class="inline-block border-t-2 border-t-transparent py-3 lg:ml-12"
:class="{ 'border-b-2 border-b-blue-900': routeInActionCompetences() }"
>
<router-link :to="`/course/${courseSlug}/competence/competences`">
{{ $t("a.Handlungskompetenzen") }}
</router-link>
</li>
<!-- Add similar logic for other `li` items as you expand the list -->
<li class="ml-6 inline-block lg:ml-12"></li>
</ul>
</nav>
<main>
<router-view></router-view>
</main>

View File

@ -1,121 +1,112 @@
<script setup lang="ts">
import { default as PerformanceCriteriaRow } from "@/components/competences/PerformanceCriteriaRow.vue";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import { useCompetenceStore } from "@/stores/competence";
import type { CourseCompletionStatus } from "@/types";
import * as log from "loglevel";
import type { Ref } from "vue";
import { computed, ref } from "vue";
import { useTranslation } from "i18next-vue";
import { computed } from "vue";
import _ from "lodash";
const props = defineProps<{
courseSlug: string;
}>();
interface MenuItem {
id: CourseCompletionStatus;
name: string;
iconName: string;
}
log.debug("PerformanceCriteriaPage created", props);
const competenceStore = useCompetenceStore();
const shownCriteria = computed(() => {
return competenceStore.flatPerformanceCriteria().filter((criteria) => {
return criteria.completion_status === activeMenuItem.value.id;
const uniqueLearningUnits = computed(() => {
// FIXME: this complex calculation can go away,
// once the criteria are in its own learning content
// get the learningUnits sorted by circle order in the course
const circles = competenceStore.circles.map((c, index) => {
return { ...c, sortKey: index };
});
return _.orderBy(
_.uniqBy(
competenceStore.flatPerformanceCriteria().map((pc) => {
return {
luId: pc.learning_unit.id,
luTitle: pc.learning_unit.title,
luSlug: pc.learning_unit.slug,
circleId: pc.circle.id,
circleTitle: pc.circle.title,
url: pc.learning_unit.evaluate_url,
sortKey: circles.find((c) => c.id === pc.circle.id)?.sortKey,
};
}),
"luId"
),
"sortKey"
);
});
const { t } = useTranslation();
const mobileMenuItems: MenuItem[] = [
{
id: "FAIL",
name: `«${t("selfEvaluation.no")}»`,
iconName: "it-icon-smiley-thinking",
},
{
id: "SUCCESS",
name: `«${t("selfEvaluation.yes")}»`,
iconName: "it-icon-smiley-happy",
},
{
id: "UNKNOWN",
name: t("competences.notAssessed"),
iconName: "it-icon-smiley-neutral",
},
];
const activeMenuItem: Ref<MenuItem> = ref(mobileMenuItems[0]);
function updateActiveState(status: CourseCompletionStatus) {
activeMenuItem.value =
mobileMenuItems.find((item) => status === item.id) || mobileMenuItems[0];
}
const criteriaByLearningUnit = computed(() => {
return uniqueLearningUnits.value.map((lu) => {
const criteria = competenceStore
.flatPerformanceCriteria()
.filter((pc) => pc.learning_unit.id === lu.luId);
return {
...lu,
countSuccess: criteria.filter((c) => c.completion_status === "SUCCESS").length,
countFail: criteria.filter((c) => c.completion_status === "FAIL").length,
countUnknown: criteria.filter((c) => c.completion_status === "UNKNOWN").length,
criteria: criteria,
};
});
});
</script>
<template>
<div class="container-large">
<nav class="py-4 lg:pb-8">
<router-link
class="btn-text inline-flex items-center pl-0"
:to="`${competenceStore.competenceProfilePage()?.frontend_url}`"
>
<it-icon-arrow-left />
<span>{{ $t("general.back") }}</span>
</router-link>
</nav>
<div class="mb-4 flex flex-col items-center justify-between lg:mb-10 lg:flex-row">
<h1>Einschätzungen</h1>
<ItDropdownSelect
v-model="competenceStore.selectedCircle"
class="mt-4 w-full lg:mt-0 lg:w-96"
:items="competenceStore.availableCircles"
></ItDropdownSelect>
<div class="w-full lg:hidden">
<ItDropdownSelect
v-model="activeMenuItem"
class="mt-4 w-full lg:mt-0 lg:w-96"
:items="mobileMenuItems"
></ItDropdownSelect>
</div>
</div>
<div class="bg-white p-8">
<h2 class="mb-4 lg:py-4">{{ $t("a.Selbsteinschätzungen") }}</h2>
<section class="mb-4 bg-white px-4 py-2">
<div
class="mb-4 flex hidden flex-col justify-between border-b pb-4 lg:block lg:flex-row lg:items-center"
v-for="selfEvaluation in criteriaByLearningUnit"
:key="selfEvaluation.luId"
class="flex flex-col justify-between gap-4 border-b py-4 last:border-b-0 lg:flex-row lg:items-center"
>
<button
v-for="item in mobileMenuItems"
:key="item.id"
:class="{
'bg-gray-200': activeMenuItem.id === item.id,
'mr-6': item.id !== 'UNKNOWN',
}"
class="mr-6 inline-block px-2 py-4"
@click="updateActiveState(item.id)"
>
<div class="flex flex-row items-center">
<span class="mr-2 inline-block">{{ item.name }}</span>
<component :is="item.iconName"></component>
<div class="lg:w-1/3">
{{ $t("a.Circle") }}
{{ selfEvaluation.circleTitle }}:
{{ selfEvaluation.luTitle }}
</div>
</button>
<div class="flex flex-row items-center lg:w-1/3">
<div class="mr-6 flex flex-row items-center">
<it-icon-smiley-thinking
class="mr-2 inline-block h-8 w-8"
></it-icon-smiley-thinking>
<div class="w-6" :data-cy="`${selfEvaluation.luSlug}-fail`">
{{ selfEvaluation.countFail }}
</div>
</div>
<li class="mr-6 flex flex-row items-center">
<it-icon-smiley-happy
class="mr-2 inline-block h-8 w-8"
></it-icon-smiley-happy>
<div class="w-6" :data-cy="`${selfEvaluation.luSlug}-success`">
{{ selfEvaluation.countSuccess }}
</div>
<ul class="mb-6">
<li
v-for="criteria in shownCriteria"
:key="criteria.id"
class="mb-4 border-b pb-4"
>
<PerformanceCriteriaRow
:criteria="criteria"
:show-state="true"
:course-slug="props.courseSlug"
></PerformanceCriteriaRow>
</li>
</ul>
<li class="flex flex-row items-center">
<it-icon-smiley-neutral
class="mr-2 inline-block h-8 w-8"
></it-icon-smiley-neutral>
<div class="w-6" :data-cy="`${selfEvaluation.luSlug}-unknown`">
{{ selfEvaluation.countUnknown }}
</div>
</li>
</div>
<div>
<router-link
:to="selfEvaluation.url"
class="link"
:data-cy="`${selfEvaluation.luSlug}-open`"
>
{{ $t("a.Selbsteinschätzung anschauen") }}
</router-link>
</div>
</div>
</section>
</div>
</template>

View File

@ -1,70 +0,0 @@
<script setup lang="ts">
import { useCircleStore } from "@/stores/circle";
import { useCompetenceStore } from "@/stores/competence";
import * as log from "loglevel";
import LearningContentContainer from "@/pages/learningPath/learningContentPage/LearningContentContainer.vue";
import { computed } from "vue";
import { useRouter } from "vue-router";
const props = defineProps<{
courseSlug: string;
criteriaSlug: string;
}>();
log.debug("SinglePerformanceCriteriaPage.vue setup");
const competenceStore = useCompetenceStore();
const circleStore = useCircleStore();
const router = useRouter();
const singleCriteria = computed(() => {
return competenceStore.flatPerformanceCriteria().find((criteria) => {
return criteria.slug === props.criteriaSlug;
});
});
</script>
<template>
<div v-if="singleCriteria" class="absolute bottom-0 top-0 w-full bg-white">
<LearningContentContainer @exit="router.back()">
<div v-if="singleCriteria" class="container-medium">
<div class="mt-4 border p-6 lg:mt-8 lg:p-12">
<h2 class="heading-2">
{{ singleCriteria.competence_id }} {{ singleCriteria.title }}
</h2>
<div class="mt-4 flex flex-col justify-between gap-6 lg:mt-8 lg:flex-row">
<button
class="inline-flex flex-1 items-center border p-4 text-left"
:class="{
'border-green-500': singleCriteria.completion_status === 'SUCCESS',
'border-2': singleCriteria.completion_status === 'SUCCESS',
}"
data-cy="success"
@click="circleStore.markCompletion(singleCriteria, 'SUCCESS')"
>
<it-icon-smiley-happy class="mr-4 h-16 w-16"></it-icon-smiley-happy>
<span class="text-large font-bold">{{ $t("selfEvaluation.yes") }}</span>
</button>
<button
class="inline-flex flex-1 items-center border p-4 text-left"
:class="{
'border-orange-500': singleCriteria.completion_status === 'FAIL',
'border-2': singleCriteria.completion_status === 'FAIL',
}"
data-cy="fail"
@click="circleStore.markCompletion(singleCriteria, 'FAIL')"
>
<it-icon-smiley-thinking class="mr-4 h-16 w-16"></it-icon-smiley-thinking>
<span class="text-xl font-bold">{{ $t("selfEvaluation.no") }}</span>
</button>
</div>
</div>
</div>
</LearningContentContainer>
</div>
</template>
<style scoped></style>

View File

@ -26,31 +26,17 @@ const props = withDefaults(defineProps<Props>(), {
></it-icon-smiley-thinking>
<it-icon-smiley-neutral v-else></it-icon-smiley-neutral>
</div>
<div class="mb-4 pr-5 lg:mb-0 lg:mr-10">
<h4 class="text-bold mb-2">
{{ criteria.competence_id }} {{ criteria.title }}
</h4>
<p class="hidden lg:block">
{{ $t("general.learningUnit") }}:
<router-link class="link" :to="criteria.learning_unit.frontend_url">
{{ criteria.learning_unit.title }}
</router-link>
</p>
<div class="mb-4 pr-4 lg:mb-0 lg:mr-8">
{{ criteria.title }}
</div>
</div>
<p class="mb-2 lg:hidden">
{{ $t("general.learningUnit") }}:
<router-link class="link" :to="criteria.learning_unit.frontend_url">
{{ criteria.learning_unit.title }}
</router-link>
</p>
<span class="whitespace-nowrap">
<span class="lg:whitespace-nowrap">
<router-link
v-if="props.showAssessAgain"
class="link"
:to="`/course/${props.courseSlug}/competence/criteria/${criteria.slug}`"
:to="criteria.learning_unit.evaluate_url"
>
{{ $t("competences.assessAgain") }}
{{ $t("competences.assessAgain", { x: criteria.circle.title }) }}
</router-link>
</span>
</div>

View File

@ -0,0 +1,34 @@
import type { StatusCount } from "@/components/ui/ItProgress.vue";
import type { CompetenceCertificateAssignment } from "@/types";
import _ from "lodash";
export function assignmentsMaxEvaluationPoints(
assignments: CompetenceCertificateAssignment[]
): number {
return _.sum(
assignments
.filter((a) => a.completion?.completion_status === "EVALUATION_SUBMITTED")
.map((a) => a.max_points)
);
}
export function assignmentsUserPoints(assignments: CompetenceCertificateAssignment[]) {
return _.sum(
assignments
.filter((a) => a.completion?.completion_status === "EVALUATION_SUBMITTED")
.map((a) => a.completion?.evaluation_points ?? 0)
);
}
export function competenceCertificateProgressStatusCount(
assignments: CompetenceCertificateAssignment[]
) {
const numAssignmentsEvaluated = assignments.filter(
(a) => a.completion?.completion_status === "EVALUATION_SUBMITTED"
).length;
return {
SUCCESS: numAssignmentsEvaluated,
UNKNOWN: assignments.length - numAssignmentsEvaluated,
FAIL: 0,
} as StatusCount;
}

View File

@ -13,7 +13,7 @@ const emit = defineEmits(["closemodal"]);
<template>
<ItFullScreenModal :show="show" @closemodal="emit('closemodal')">
<div v-if="circle" class="container-medium">
<h2 data-cy="lc-title">Überblick: Circle «{{ circle.title }}»</h2>
<h2 data-cy="lc-title">{{ $t("a.Übersicht") }}: Circle «{{ circle.title }}»</h2>
<!-- eslint-disable vue/no-v-html -->
<div

View File

@ -5,12 +5,19 @@ import { showIcon } from "@/pages/learningPath/circlePage/learningSequenceUtils"
import { useCircleStore } from "@/stores/circle";
import type {
CourseCompletionStatus,
LearningContent,
LearningContentAssignment,
LearningContentEdoniqTest,
LearningContentInterface,
LearningSequence,
} from "@/types";
import { humanizeDuration } from "@/utils/humanizeDuration";
import findLast from "lodash/findLast";
import { computed } from "vue";
import { humanizeDuration } from "../../../utils/humanizeDuration";
import {
itCheckboxDefaultIconCheckedTailwindClass,
itCheckboxDefaultIconUncheckedTailwindClass,
} from "@/constants";
type Props = {
learningSequence: LearningSequence;
@ -87,6 +94,32 @@ const learningSequenceBorderClass = computed(() => {
return result;
});
function belongsToCompetenceCertificate(lc: LearningContent) {
return (
(lc.content_type === "learnpath.LearningContentAssignment" ||
lc.content_type === "learnpath.LearningContentEdoniqTest") &&
lc.competence_certificate?.frontend_url
);
}
type LearninContentWithCompetenceCertificate =
| LearningContentAssignment
| LearningContentEdoniqTest;
function checkboxIconCheckedTailwindClass(lc: LearningContent) {
if (belongsToCompetenceCertificate(lc)) {
return "bg-[url(/static/icons/icon-lc-competence-certificate-checked.svg)]";
}
return itCheckboxDefaultIconCheckedTailwindClass;
}
function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
if (belongsToCompetenceCertificate(lc)) {
return "bg-[url(/static/icons/icon-lc-competence-certificate.svg)]";
}
return itCheckboxDefaultIconUncheckedTailwindClass;
}
</script>
<template>
@ -123,8 +156,9 @@ const learningSequenceBorderClass = computed(() => {
<li
v-for="learningContent in learningUnit.learningContents"
:key="learningContent.id"
class="flex items-center gap-4 pb-3 lg:pb-6"
>
<div class="pb-6">
<div class="flex items-center gap-4">
<div v-if="props.readonly">
<it-icon-check
v-if="learningContent.completion_status === 'SUCCESS'"
@ -138,12 +172,33 @@ const learningSequenceBorderClass = computed(() => {
value: learningContent.completion_status,
checked: learningContent.completion_status === 'SUCCESS',
}"
:disabled="!learningContent.can_user_self_toggle_course_completion"
:data-cy="`${learningContent.slug}-checkbox`"
:icon-checked-tailwind-class="
checkboxIconCheckedTailwindClass(learningContent)
"
:icon-unchecked-tailwind-class="
checkboxIconUncheckedTailwindClass(learningContent)
"
@toggle="toggleCompleted(learningContent)"
@click="
(event: MouseEvent) => {
// when disabled open the learning content directly
if (!learningContent.can_user_self_toggle_course_completion) {
circleStore.openLearningContent(learningContent);
event.preventDefault();
event.stopPropagation();
}
}
"
/>
<div class="flex-auto pt-1 sm:pt-0">
<span class="flex items-center gap-4 xl:h-10">
<div
class="flex flex-auto flex-col gap-4 xl:flex-row xl:justify-between"
>
<div class="xl:order-last">
<LearningContentBadge :learning-content="learningContent" />
</div>
<div>
<div v-if="props.readonly" class="w-full text-left sm:w-auto">
{{ learningContent.title }}
</div>
@ -155,36 +210,51 @@ const learningSequenceBorderClass = computed(() => {
>
{{ learningContent.title }}
</button>
</div>
</div>
</div>
<div
v-if="belongsToCompetenceCertificate(learningContent)"
class="ml-16 text-sm text-gray-800"
>
{{
$t("circlePage.Dieser Inhalt gehört zu x", {
x: (learningContent as LearninContentWithCompetenceCertificate)
?.competence_certificate?.title,
})
}}
<br />
<router-link
v-if="(learningContent as LearninContentWithCompetenceCertificate).competence_certificate?.frontend_url"
:to="(learningContent as LearninContentWithCompetenceCertificate).competence_certificate?.frontend_url ?? ''"
class="link"
data-cy="show-results"
>
{{ $t("circlePage.Im KompetenzNavi anschauen") }}
</router-link>
</div>
<div
class="flex flex-col items-center justify-between gap-4 sm:grow md:flex-row lg:flex-col xl:flex-row"
v-if="
learningContent.translation_key === continueTranslationKeyTuple[0] &&
!props.readonly
"
class="my-4"
>
<button
v-if="
learningContent.translation_key ===
continueTranslationKeyTuple[0] && !props.readonly
"
class="btn-blue order-1 sm:order-none"
data-cy="ls-continue-button"
@click.stop="circleStore.openLearningContent(learningContent)"
>
<span
v-if="continueTranslationKeyTuple[1]"
class="whitespace-nowrap"
>
<span v-if="continueTranslationKeyTuple[1]" class="whitespace-nowrap">
{{ $t("general.start") }}
</span>
<span v-else class="whitespace-nowrap">
{{ $t("general.nextStep") }}
</span>
</button>
<div class="hidden sm:block"></div>
<div class="w-full sm:w-auto">
<LearningContentBadge :learning-content="learningContent" />
</div>
</div>
</span>
</div>
</li>
</ol>
@ -196,24 +266,21 @@ const learningSequenceBorderClass = computed(() => {
>
<div
v-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'SUCCESS'"
class="self-evaluation-success flex items-center gap-4 pb-3 lg:pb-6"
class="self-evaluation-success flex items-center gap-4 pb-6"
>
<it-icon-smiley-happy class="h-8 w-8 flex-none" data-cy="success" />
<it-icon-smiley-happy class="mr-4 h-8 w-8 flex-none" data-cy="success" />
<div>{{ $t("selfEvaluation.selfEvaluationYes") }}</div>
</div>
<div
v-else-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'FAIL'"
class="self-evaluation-fail flex items-center gap-4 pb-3 lg:pb-6"
class="self-evaluation-fail flex items-center gap-4 pb-6"
>
<it-icon-smiley-thinking class="h-8 w-8 flex-none" data-cy="fail" />
<it-icon-smiley-thinking class="mr-4 h-8 w-8 flex-none" data-cy="fail" />
<div>{{ $t("selfEvaluation.selfEvaluationNo") }}</div>
</div>
<div
v-else
class="self-evaluation-unknown flex items-center gap-4 pb-3 lg:pb-6"
>
<it-icon-smiley-neutral class="h-8 w-8 flex-none" data-cy="unknown" />
<div>{{ $t("selfEvaluation.selfEvaluation") }}</div>
<div v-else class="self-evaluation-unknown flex items-center gap-4 pb-6">
<it-icon-smiley-neutral class="mr-4 h-8 w-8 flex-none" data-cy="unknown" />
<div>{{ $t("a.Selbsteinschätzung") }}</div>
</div>
</div>

View File

@ -4,7 +4,7 @@ import { useCircleStore } from "@/stores/circle";
import type { LearningContent } from "@/types";
import * as log from "loglevel";
import type { Ref } from "vue";
import { onMounted, ref, watch } from "vue";
import { getCurrentInstance, onMounted, onUpdated, ref, watch } from "vue";
log.debug("LearningContentView created");
@ -52,6 +52,24 @@ onMounted(async () => {
);
await loadLearningContent();
});
onUpdated(() => {
const vueInstance = getCurrentInstance();
if (vueInstance) {
// VBV-489: open external links in new tab
const rootElement: HTMLElement = vueInstance.proxy?.$el;
const anchors = rootElement.querySelectorAll("a");
anchors.forEach((anchor: HTMLAnchorElement) => {
if (
/^https?:\/\//i.test(anchor.href) &&
!anchor.href.includes(window.location.hostname)
) {
anchor.setAttribute("target", "_blank");
anchor.setAttribute("rel", "noopener noreferrer");
}
});
}
});
</script>
<template>

View File

@ -16,6 +16,7 @@ import MediaLibraryBlock from "./blocks/MediaLibraryBlock.vue";
import PlaceholderBlock from "./blocks/PlaceholderBlock.vue";
import RichTextBlock from "./blocks/RichTextBlock.vue";
import VideoBlock from "./blocks/VideoBlock.vue";
import { getPreviousRoute } from "@/router/history";
const circleStore = useCircleStore();
@ -25,6 +26,8 @@ const props = defineProps<{
log.debug("LearningContentParent setup", props.learningContent);
const previousRoute = getPreviousRoute();
// can't use the type as component name, as some are reserved HTML components, e.g. video
const COMPONENTS: Record<LearningContentType, Component> = {
"learnpath.LearningContentAssignment": AssignmentBlock,
@ -45,7 +48,7 @@ const component = computed(() => {
});
function handleFinishedLearningContent() {
circleStore.continueFromLearningContent(props.learningContent);
circleStore.continueFromLearningContent(props.learningContent, previousRoute);
}
eventBus.on("finishedLearningContent", handleFinishedLearningContent);
@ -57,7 +60,7 @@ onUnmounted(() => {
<template>
<LearningContentContainer
@exit="circleStore.closeLearningContent(props.learningContent)"
@exit="circleStore.closeLearningContent(props.learningContent, previousRoute)"
>
<div>
<component :is="component" :content="learningContent"></component>

View File

@ -16,8 +16,6 @@ const props = withDefaults(defineProps<Props>(), {
log.debug("AssignmentIntroductionView created", props.assignment, props.dueDate);
// TODO: Test if submission deadline is set correctly, and evaluation_deadline is set.
const step = useRouteQuery("step");
</script>
@ -74,7 +72,7 @@ const step = useRouteQuery("step");
props.assignment.evaluation_document_url
"
>
<h3 class="mb-4 mt-8">{{ $t("assignment.assessmentTitle") }}</h3>
<h3 class="mb-4 mt-8">{{ $t("a.Bewertung") }}</h3>
<p
v-if="props.assignment.evaluation_description"
class="default-wagtail-rich-text text-large"
@ -90,4 +88,24 @@ const step = useRouteQuery("step");
</a>
</p>
</div>
<div>
<h3 class="mb-4 mt-8">{{ $t("a.Kompetenznachweis") }}</h3>
<p class="text-large">
{{
$t("circlePage.Dieser Inhalt gehört zu x", {
x: assignment?.competence_certificate?.title,
})
}}
<br />
<router-link
v-if="assignment.competence_certificate?.frontend_url"
:to="assignment.competence_certificate?.frontend_url ?? ''"
class="link"
data-cy="open-competence-certificate"
>
{{ $t("circlePage.Im KompetenzNavi anschauen") }}
</router-link>
</p>
</div>
</template>

View File

@ -2,7 +2,6 @@
import { useCurrentCourseSession } from "@/composables";
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
import EvaluationSummary from "@/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue";
import AssignmentIntroductionView from "@/pages/learningPath/learningContentPage/assignment/AssignmentIntroductionView.vue";
import AssignmentSubmissionView from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionView.vue";
import AssignmentTaskView from "@/pages/learningPath/learningContentPage/assignment/AssignmentTaskView.vue";
@ -12,7 +11,6 @@ import { useUserStore } from "@/stores/user";
import type {
Assignment,
AssignmentCompletion,
AssignmentCompletionStatus,
AssignmentTask,
CourseSessionAssignment,
CourseSessionUser,
@ -22,10 +20,11 @@ import { useMutation, useQuery } from "@urql/vue";
import { useRouteQuery } from "@vueuse/router";
import dayjs from "dayjs";
import * as log from "loglevel";
import { computed, onMounted, reactive } from "vue";
import { computed, onMounted, reactive, ref, watchEffect } from "vue";
import { useTranslation } from "i18next-vue";
import { bustItGetCache } from "@/fetchHelpers";
import { learningContentTypeData } from "@/utils/typeMaps";
import EvaluationSummary from "@/pages/cockpit/assignmentEvaluationPage/EvaluationSummary.vue";
const { t } = useTranslation();
const courseSession = useCurrentCourseSession();
@ -76,6 +75,28 @@ const completionStatus = computed(() => {
return assignmentCompletion.value?.completion_status ?? "IN_PROGRESS";
});
const hasRunUseQueryPostFetch = ref(false);
watchEffect(() => {
if (
queryResult.data.value &&
!queryResult.error.value &&
!hasRunUseQueryPostFetch.value
) {
// workaround for setting step to last when not IN_PROGRESS anymore
hasRunUseQueryPostFetch.value = true;
try {
if (
stepIndex.value === 0 &&
(completionStatus.value ?? "IN_PROGRESS") !== "IN_PROGRESS"
) {
stepIndex.value = numPages.value - 1;
}
} catch (error) {
log.error(error);
}
}
});
onMounted(async () => {
log.debug(
"AssignmentView mounted",
@ -89,19 +110,8 @@ onMounted(async () => {
// create initial `AssignmentCompletion` first, so that it exists and we don't
// have reactivity problem accessing it.
await upsertAssignmentCompletion("IN_PROGRESS");
await initUpsertAssignmentCompletion();
queryResult.resume();
try {
if (
stepIndex.value === 0 &&
(completionStatus.value ?? "IN_PROGRESS") !== "IN_PROGRESS"
) {
stepIndex.value = numPages.value - 1;
}
} catch (error) {
log.error(error);
}
});
const numTasks = computed(() => assignment.value?.tasks?.length ?? 0);
@ -120,17 +130,18 @@ const currentTask = computed(() => {
return undefined;
});
const upsertAssignmentCompletion = async (status: AssignmentCompletionStatus) => {
const initUpsertAssignmentCompletion = async () => {
try {
await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.learningContent.content_assignment_id.toString(),
courseSessionId: courseSession.value.id.toString(),
learningContentId: props.learningContent.id.toString(),
completionDataString: JSON.stringify({}),
completionStatus: status,
completionStatus: "IN_PROGRESS",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id: assignmentCompletion.value?.id,
initializeCompletion: true,
});
bustItGetCache(
`/api/course/completion/${courseSession.value.id}/${useUserStore().id}/`
@ -194,7 +205,18 @@ const assignmentUser = computed(() => {
<div v-else-if="queryResult.error.value">{{ queryResult.error.value }}</div>
<div v-else>
<div v-if="assignment && assignmentCompletion">
<div class="flex">
<div class="flex flex-col lg:flex-row">
<div
v-if="assignmentCompletion?.completion_status === 'EVALUATION_SUBMITTED'"
class="min-w-2/5 mr-4 bg-gray-200 px-6 py-6 lg:order-last"
>
<EvaluationSummary
:assignment-user="assignmentUser"
:assignment="assignment"
:assignment-completion="assignmentCompletion"
:show-evaluation-user="true"
></EvaluationSummary>
</div>
<LearningContentMultiLayout
:current-step="stepIndex"
:sub-title="subTitle"
@ -239,17 +261,6 @@ const assignmentUser = computed(() => {
</div>
</div>
</LearningContentMultiLayout>
<div
v-if="assignmentCompletion?.completion_status === 'EVALUATION_SUBMITTED'"
class="min-w-2/5 mr-4 bg-gray-200 px-6 py-6"
>
<EvaluationSummary
:assignment-user="assignmentUser"
:assignment="assignment"
:assignment-completion="assignmentCompletion"
:show-evaluation-user="true"
></EvaluationSummary>
</div>
</div>
</div>
<div v-else>Could not load all data</div>

View File

@ -1,12 +1,14 @@
<template>
<div class="mb-12 grid grid-cols-icon-card gap-x-4 grid-areas-icon-card">
<it-icon-calendar-light class="w-[60px] grid-in-icon" />
<h2 class="text-large font-bold grid-in-title">Datum</h2>
<p class="grid-in-value">{{ formatDate(start, end) }}</p>
<h2 class="text-large font-bold grid-in-title">{{ $t("a.Datum") }}</h2>
<p class="grid-in-value">
{{ formatDueDate(props.attendanceCourse.start, props.attendanceCourse.end) }}
</p>
</div>
<div class="mb-12 grid grid-cols-icon-card gap-x-4 grid-areas-icon-card">
<it-icon-location class="w-[60px] grid-in-icon" />
<h2 class="text-large font-bold grid-in-title">Standort</h2>
<h2 class="text-large font-bold grid-in-title">{{ $t("a.Standort") }}</h2>
<p v-if="location.startsWith('https://')" class="grid-in-value">
<a class="link" target="_blank" :href="location">{{ location }}</a>
</p>
@ -14,13 +16,13 @@
</div>
<div class="grid grid-cols-icon-card content-between gap-x-4 grid-areas-icon-card">
<it-icon-trainer class="w-[60px] grid-in-icon" />
<h2 class="text-large font-bold grid-in-title">Trainer</h2>
<h2 class="text-large font-bold grid-in-title">{{ $t("a.Trainer") }}</h2>
<p class="grid-in-value">{{ trainer }}</p>
</div>
</template>
<script setup lang="ts">
import { formatDate } from "@/components/dueDates/dueDatesUtils";
import { formatDueDate } from "@/components/dueDates/dueDatesUtils";
import type { CourseSessionAttendanceCourse } from "@/types";
import dayjs from "dayjs";
import LocalizedFormat from "dayjs/plugin/localizedFormat";
@ -33,8 +35,6 @@ export interface Props {
const props = defineProps<Props>();
dayjs.extend(LocalizedFormat);
const start = computed(() => dayjs(props.attendanceCourse.start));
const end = computed(() => dayjs(props.attendanceCourse.end));
const location = computed(() => props.attendanceCourse.location);
const trainer = computed(() => props.attendanceCourse.trainer);
</script>

View File

@ -2,10 +2,17 @@
import { useTranslation } from "i18next-vue";
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import LearningContentSimpleLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentSimpleLayout.vue";
import type { LearningContentEdoniqTest } from "@/types";
import { ref } from "vue";
import type {
Assignment,
AssignmentCompletion,
LearningContentEdoniqTest,
} from "@/types";
import { computed, ref } from "vue";
import * as log from "loglevel";
import { itPost } from "@/fetchHelpers";
import { useQuery } from "@urql/vue";
import { ASSIGNMENT_COMPLETION_QUERY } from "@/graphql/queries";
import { useCurrentCourseSession } from "@/composables";
const { t } = useTranslation();
@ -13,6 +20,29 @@ const props = defineProps<{
content: LearningContentEdoniqTest;
}>();
const courseSession = useCurrentCourseSession();
const queryResult = useQuery({
query: ASSIGNMENT_COMPLETION_QUERY,
variables: {
courseSessionId: courseSession.value.id.toString(),
assignmentId: props.content.content_assignment_id.toString(),
learningContentId: props.content.id.toString(),
},
});
const assignment = computed(
() => queryResult.data.value?.assignment as Assignment | undefined
);
const assignmentCompletion = computed(
() =>
queryResult.data.value?.assignment_completion as AssignmentCompletion | undefined
);
const completionStatus = computed(() => {
return assignmentCompletion.value?.completion_status ?? "IN_PROGRESS";
});
const termsAccepted = ref(false);
const extendedTimeTest = ref(false);
@ -33,7 +63,16 @@ async function startTest() {
:learning-content="props.content"
>
<!-- eslint-disable vue/no-v-html -->
<div class="container-medium">
<div v-if="queryResult.data" class="container-medium">
<div v-if="completionStatus !== 'IN_PROGRESS'">
<div v-if="completionStatus === 'EVALUATION_SUBMITTED'">
{{ $t("a.Bewertung") }}:
{{ assignmentCompletion?.evaluation_points }}
{{ $t("assignment.von x Punkten", { x: assignment?.max_points }) }}
</div>
<div v-else>Ergebnisse abgeben, Bewertung ausstehend</div>
</div>
<div v-else>
<p
v-if="props.content.description"
class="default-wagtail-rich-text text-large my-4"
@ -69,10 +108,11 @@ async function startTest() {
class="btn-primary inline-flex items-center"
@click="startTest()"
>
Test starten
{{ $t("edoniqTest.startTest") }}
<it-icon-external-link class="it-icon ml-2 h-5 w-5"></it-icon-external-link>
</button>
</div>
</div>
</div>
</LearningContentSimpleLayout>
</template>

View File

@ -74,7 +74,7 @@ const changeViewType = (viewType: ViewType) => {
<!-- Top -->
<div class="flex flex-row justify-between space-x-8 bg-gray-200 p-6 sm:p-12">
<!-- Left -->
<div class="flex w-1/2 flex-col justify-between">
<div class="flex flex-col justify-between lg:w-1/2">
<div>
<p class="font-bold">
{{ $t("learningPathPage.welcomeBack") }}

View File

@ -10,6 +10,7 @@ import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage
import eventBus from "@/utils/eventBus";
import { useRouteQuery } from "@vueuse/router";
import { computed, onUnmounted } from "vue";
import { getPreviousRoute } from "@/router/history";
log.debug("LearningContent.vue setup");
@ -18,6 +19,8 @@ const courseSession = useCurrentCourseSession();
const questionIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" });
const previousRoute = getPreviousRoute();
const props = defineProps<{
learningUnit: LearningUnit;
}>();
@ -52,7 +55,7 @@ function handleBack() {
}
function handleFinishedLearningContent() {
circleStore.closeSelfEvaluation(props.learningUnit);
circleStore.closeSelfEvaluation(props.learningUnit, previousRoute);
}
eventBus.on("finishedLearningContent", handleFinishedLearningContent);
@ -65,12 +68,12 @@ onUnmounted(() => {
<template>
<div v-if="learningUnit">
<LearningContentContainer
@exit="circleStore.closeSelfEvaluation(props.learningUnit)"
@exit="circleStore.closeSelfEvaluation(props.learningUnit, previousRoute)"
>
<LearningContentMultiLayout
:current-step="questionIndex"
:sub-title="$t('selfEvaluation.title')"
:title="$t('selfEvaluation.title', { title: learningUnit.title })"
:sub-title="$t('a.Selbsteinschätzung')"
:title="`${learningUnit.title}`"
icon="it-icon-lc-learning-module"
:steps-count="questions.length"
:show-next-button="showNextButton"
@ -84,7 +87,7 @@ onUnmounted(() => {
<div class="h-full">
<div class="mt-8">
<h3 class="heading-3">
{{ currentQuestion.competence_id }} {{ currentQuestion.title }}
{{ currentQuestion.title }}
</h3>
<div
@ -101,7 +104,7 @@ onUnmounted(() => {
>
<it-icon-smiley-happy class="mr-4 h-16 w-16"></it-icon-smiley-happy>
<span class="text-large font-bold">
{{ $t("selfEvaluation.yes") }}.
{{ $t("selfEvaluation.yes") }}
</span>
</button>
<button
@ -117,7 +120,7 @@ onUnmounted(() => {
<it-icon-smiley-thinking
class="mr-4 h-16 w-16"
></it-icon-smiley-thinking>
<span class="text-xl font-bold">{{ $t("selfEvaluation.no") }}.</span>
<span class="text-xl font-bold">{{ $t("selfEvaluation.no") }}</span>
</button>
</div>

View File

@ -29,9 +29,9 @@ onMounted(async () => {
v-if="mediaLibraryStore.mediaLibraryPage"
class="scrollbar overflow-auto whitespace-nowrap"
>
<li class="inline-block lg:ml-12">
<li class="inline-block">
<router-link :to="mediaLibraryStore.mediaLibraryPage.frontend_url">
{{ $t("mediaLibrary.overview") }}
{{ $t("a.Übersicht") }}
</router-link>
</li>
<li
@ -50,7 +50,6 @@ onMounted(async () => {
{{ category.title }}
</a>
</li>
<li class="ml-6 inline-block lg:ml-12"></li>
</ul>
</nav>
<main>

View File

@ -0,0 +1,41 @@
// handle route history
import type {
NavigationGuard,
RouteLocationNormalized,
RouteLocationRaw,
Router,
} from "vue-router";
const routeHistory: RouteLocationNormalized[] = [];
const MAX_HISTORY = 10; // for example, store the last 10 visited routes
let isFirstNavigation = true;
export const addToHistory: NavigationGuard = (to, from, next) => {
// Add the current route to the history, and ensure it doesn't exceed the maximum length
if (isFirstNavigation) {
isFirstNavigation = false;
} else {
routeHistory.push(from);
}
if (routeHistory.length > MAX_HISTORY) {
routeHistory.shift();
}
next();
};
export function getPreviousRoute() {
if (routeHistory.length > 0) {
return routeHistory[routeHistory.length - 1];
}
return undefined;
}
export function routerBackOrFallback(router: Router, fallbackRoute: RouteLocationRaw) {
// Check the latest route in history
const previousRoute = getPreviousRoute();
if (previousRoute) {
router.back();
} else {
router.push(fallbackRoute);
}
}

View File

@ -5,6 +5,7 @@ import {
redirectToLoginIfRequired,
updateLoggedIn,
} from "@/router/guards";
import { addToHistory } from "@/router/history";
import { createRouter, createWebHistory } from "vue-router";
const router = createRouter({
@ -71,10 +72,18 @@ const router = createRouter({
props: true,
component: () => import("@/pages/competence/CompetenceIndexPage.vue"),
},
{
path: "competences",
path: "certificates",
props: true,
component: () => import("@/pages/competence/CompetenceListPage.vue"),
component: () =>
import("@/pages/competence/CompetenceCertificateListPage.vue"),
},
{
path: "certificates/:certificateSlug",
props: true,
component: () =>
import("@/pages/competence/CompetenceCertificateDetailPage.vue"),
},
{
path: "criteria",
@ -82,10 +91,9 @@ const router = createRouter({
component: () => import("@/pages/competence/PerformanceCriteriaPage.vue"),
},
{
path: "criteria/:criteriaSlug",
path: "competences",
props: true,
component: () =>
import("@/pages/competence/SinglePerformanceCriteriaPage.vue"),
component: () => import("@/pages/competence/ActionCompetenceListPage.vue"),
},
],
},
@ -195,4 +203,6 @@ router.beforeEach(redirectToLoginIfRequired);
// register after login hooks
router.beforeEach(handleCourseSessions);
router.beforeEach(addToHistory);
export default router;

View File

@ -17,6 +17,7 @@ import pick from "lodash/pick";
export interface GradedUser {
user: CourseSessionUser;
grade: number;
points: number;
}
export function calcLearningContentAssignments(learningPath?: LearningPath) {
@ -62,6 +63,7 @@ export async function loadAssignmentCompletionStatusData(
gradedUsers.push({
user: csu,
grade: userAssignmentStatus.evaluation_grade ?? 0,
points: userAssignmentStatus.evaluation_points ?? 0,
});
}
}

View File

@ -1,5 +1,3 @@
import * as log from "loglevel";
import type { Circle } from "@/services/circle";
import { useCompletionStore } from "@/stores/completion";
import { useLearningPathStore } from "@/stores/learningPath";
@ -11,7 +9,9 @@ import type {
LearningUnitPerformanceCriteria,
PerformanceCriteria,
} from "@/types";
import * as log from "loglevel";
import { defineStore } from "pinia";
import type { RouteLocationNormalized } from "vue-router";
export type CircleStoreState = {
circle: Circle | undefined;
@ -127,22 +127,36 @@ export const useCircleStore = defineStore({
path: learningContent.frontend_url,
});
},
closeLearningContent(learningContent: LearningContentInterface) {
closeLearningContent(
learningContent: LearningContentInterface,
returnRoute?: RouteLocationNormalized
) {
if (returnRoute) {
this.router.push(returnRoute);
} else {
this.router.push({
path: `${this.circle?.frontend_url}`,
hash: createLearningUnitHash(learningContent.parentLearningUnit),
});
}
},
openSelfEvaluation(learningUnit: LearningUnit) {
this.router.push({
path: learningUnit.evaluate_url,
});
},
closeSelfEvaluation(learningUnit: LearningUnit) {
closeSelfEvaluation(
learningUnit: LearningUnit,
returnRoute?: RouteLocationNormalized
) {
if (returnRoute) {
this.router.push(returnRoute);
} else {
this.router.push({
path: `${this.circle?.frontend_url}`,
hash: createLearningUnitHash(learningUnit),
});
}
},
calcSelfEvaluationStatus(learningUnit: LearningUnit): CourseCompletionStatus {
if (learningUnit.children.length > 0) {
@ -159,7 +173,10 @@ export const useCircleStore = defineStore({
}
return "UNKNOWN";
},
continueFromLearningContent(currentLearningContent: LearningContentInterface) {
continueFromLearningContent(
currentLearningContent: LearningContentInterface,
returnRoute?: RouteLocationNormalized
) {
if (currentLearningContent) {
if (currentLearningContent.can_user_self_toggle_course_completion) {
this.markCompletion(currentLearningContent, "SUCCESS");
@ -167,7 +184,7 @@ export const useCircleStore = defineStore({
// reload completion data anyway
currentLearningContent.parentCircle?.parentLearningPath?.reloadCompletionData();
}
this.closeLearningContent(currentLearningContent);
this.closeLearningContent(currentLearningContent, returnRoute);
} else {
log.error("currentLearningContent is undefined");
}

View File

@ -9,6 +9,7 @@ import type {
PerformanceCriteria,
} from "@/types";
import i18next from "i18next";
import _ from "lodash";
import cloneDeep from "lodash/cloneDeep";
import groupBy from "lodash/groupBy";
import orderBy from "lodash/orderBy";
@ -19,6 +20,7 @@ export type CompetenceStoreState = {
selectedCircle: { id: string; name: string };
availableCircles: { id: string; name: string }[];
circles: CircleLight[];
};
export const useCompetenceStore = defineStore({
@ -28,6 +30,7 @@ export const useCompetenceStore = defineStore({
competenceProfilePages: new Map<string, CompetenceProfilePage>(),
selectedCircle: { id: "all", name: `Circle: ${i18next.t("Alle")}` },
availableCircles: [],
circles: [],
} as CompetenceStoreState;
},
getters: {},
@ -113,7 +116,8 @@ export const useCompetenceStore = defineStore({
const competenceProfilePage = this.competenceProfilePages.get(userId);
if (competenceProfilePage?.children.length) {
return competenceProfilePage.children.filter((competence) => {
return _.orderBy(
competenceProfilePage.children.filter((competence) => {
let criteria = competence.children;
if (this.selectedCircle.id != "all") {
criteria = criteria.filter((criteria) => {
@ -121,7 +125,10 @@ export const useCompetenceStore = defineStore({
});
}
return criteria.length > 0;
});
}),
["competence_id"],
["asc"]
);
}
}
@ -153,6 +160,7 @@ export const useCompetenceStore = defineStore({
this.competenceProfilePages.set(userId, cloneDeep(competenceProfilePage));
this.circles = competenceProfilePage.circles;
const circles = competenceProfilePage.circles.map((c: CircleLight) => {
return { id: c.translation_key, name: `Circle: ${c.title}` };
});

View File

@ -42,10 +42,6 @@ export const useCourseSessionsStore = defineStore("courseSessions", () => {
reload: reload,
})) as CourseSessionUser[];
cs.users = users;
cs.due_dates.forEach((dueDate) => {
dueDate.start = dayjs(dueDate.start);
dueDate.end = dayjs(dueDate.end);
});
sortDueDates(cs.due_dates);
})
);

View File

@ -1,6 +1,5 @@
import type { AssignmentCompletionStatus as AssignmentCompletionStatusGenerated } from "@/gql/graphql";
import type { Circle } from "@/services/circle";
import type { Dayjs } from "dayjs";
import type { Component } from "vue";
export type LoginMethod = "local" | "sso";
@ -55,6 +54,14 @@ export interface LearningContentAssignment extends LearningContentInterface {
readonly content_type: "learnpath.LearningContentAssignment";
readonly content_assignment_id: number;
readonly assignment_type: AssignmentType;
readonly competence_certificate?: {
id: number;
title: string;
slug: string;
content_type: string;
translation_key: string;
frontend_url: string;
} | null;
}
export interface LearningContentAttendanceCourse extends LearningContentInterface {
@ -97,6 +104,15 @@ export interface LearningContentEdoniqTest extends LearningContentInterface {
readonly content_type: "learnpath.LearningContentEdoniqTest";
readonly checkbox_text: string;
readonly has_extended_time_test: boolean;
readonly content_assignment_id: number;
readonly competence_certificate?: {
id: number;
title: string;
slug: string;
content_type: string;
translation_key: string;
frontend_url: string;
} | null;
}
export interface LearningContentVideo extends LearningContentInterface {
@ -349,7 +365,8 @@ export type AssignmentType =
| "CASEWORK"
| "PREP_ASSIGNMENT"
| "REFLECTION"
| "CONDITION_ACCEPTANCE";
| "CONDITION_ACCEPTANCE"
| "EDONIQ_TEST";
export interface Assignment extends BaseCourseWagtailPage {
readonly content_type: "assignment.Assignment";
@ -361,6 +378,15 @@ export interface Assignment extends BaseCourseWagtailPage {
readonly evaluation_document_url: string;
readonly tasks: AssignmentTask[];
readonly evaluation_tasks: AssignmentEvaluationTask[];
readonly max_points: number;
readonly competence_certificate?: {
id: number;
title: string;
slug: string;
content_type: string;
translation_key: string;
frontend_url: string;
} | null;
}
export interface PerformanceCriteria extends BaseCourseWagtailPage {
@ -368,7 +394,7 @@ export interface PerformanceCriteria extends BaseCourseWagtailPage {
readonly competence_id: string;
readonly circle: CircleLight;
readonly course_category: CourseCategory;
readonly learning_unit: BaseCourseWagtailPage;
readonly learning_unit: BaseCourseWagtailPage & { evaluate_url: string };
}
export interface CompetencePage extends BaseCourseWagtailPage {
@ -384,6 +410,27 @@ export interface CompetenceProfilePage extends BaseCourseWagtailPage {
readonly children: CompetencePage[];
}
export interface CompetenceCertificateAssignment extends BaseCourseWagtailPage {
assignment_type: "CASEWORK" | "EDONIQ_TEST";
max_points: number;
learning_content:
| (BaseCourseWagtailPage & {
circle: CircleLight;
})
| null;
completion: {
id: string;
completion_status: AssignmentCompletionStatus;
evaluation_submitted_at: string | null;
evaluation_points: number | null;
} | null;
}
export interface CompetenceCertificate extends BaseCourseWagtailPage {
readonly content_type: "competence.CompetenceCertificate";
readonly assignments: CompetenceCertificateAssignment[];
}
// dropdown
export interface DropdownListItem {
title: string;
@ -549,6 +596,7 @@ export interface AssignmentCompletion {
evaluation_user: string | null;
completion_data: AssignmentCompletionData;
evaluation_grade: number | null;
evaluation_points: number | null;
}
export type UpsertUserAssignmentCompletion = {
@ -569,13 +617,14 @@ export interface UserAssignmentCompletionStatus {
assignment_user_id: string;
completion_status: AssignmentCompletionStatus;
evaluation_grade: number | null;
evaluation_points: number | null;
learning_content_page_id: number;
}
export type DueDate = {
id: number;
start: Dayjs;
end: Dayjs;
start: string;
end: string;
title: string;
assignment_type_translation_key: string;
date_type_translation_key: string;
@ -583,4 +632,5 @@ export type DueDate = {
url: string;
course_session: number | null;
page: number | null;
circle: CircleLight | null;
};

View File

@ -44,7 +44,7 @@ export function learningContentTypeData(
icon: "it-icon-lc-learning-module",
};
case "learnpath.LearningContentMediaLibrary":
return { title: t("mediaLibrary.title"), icon: "it-icon-lc-media-library" };
return { title: t("a.Mediathek"), icon: "it-icon-lc-media-library" };
case "learnpath.LearningContentVideo":
return { title: t("learningContentTypes.video"), icon: "it-icon-lc-video" };
case "learnpath.LearningContentEdoniqTest":

View File

@ -16,9 +16,10 @@ else
fi
# Use sentry for supercronic only in prod* environments
if [[ $IT_APP_ENVIRONMENT == prod* ]]; then
sed -i "s|command=/usr/local/bin/supercronic /app/supercronic_crontab|command=/usr/local/bin/supercronic /app/supercronic_crontab -sentry-dsn '$IT_SENTRY_DSN'|" /app/supervisord.conf
fi
# FIXME: does not seem to work
#if [[ $IT_APP_ENVIRONMENT == prod* ]]; then
# sed -i "s|command=/usr/local/bin/supercronic /app/supercronic_crontab|command=/usr/local/bin/supercronic /app/supercronic_crontab -sentry-dsn '$IT_SENTRY_DSN'|" /app/supervisord.conf
#fi
# Set the command to run supervisord
/home/django/.local/bin/supervisord -c /app/supervisord.conf

View File

@ -3,7 +3,7 @@ import { login } from "../helpers";
describe("assignmentTrainer.cy.js", () => {
beforeEach(() => {
cy.manageCommand("cypress_reset --create-completion");
cy.manageCommand("cypress_reset --create-assignment-completion");
login("test-trainer1@example.com", "test");
});

View File

@ -1,43 +0,0 @@
import { login } from "./helpers";
describe("competence.cy.js", () => {
beforeEach(() => {
cy.manageCommand("cypress_reset");
login("admin", "test");
// test-lehrgang-lp-circle-reisen-lu-reisen ist eine Selbstevaluation
// mit mehreren Schritten
cy.visit("/course/test-lehrgang/learn/reisen");
});
it("self evaluation should be neutral", () => {
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]')
.find('[data-cy="unknown"]')
.should("exist");
});
it("should be able to make a happy self evaluation", () => {
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]').click();
cy.makeSelfEvaluation([true, true]);
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]')
.find('[data-cy="success"]')
.should("exist");
});
it("should be able to make a fail self evaluation", () => {
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]').click();
cy.makeSelfEvaluation([false, false]);
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]')
.find('[data-cy="fail"]')
.should("exist");
});
it("should be able to make a mixed self evaluation", () => {
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]').click();
cy.makeSelfEvaluation([false, true]);
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]')
.find('[data-cy="fail"]')
.should("exist");
});
});

View File

@ -0,0 +1,144 @@
import { login } from "../helpers";
describe("competenceCertificate.cy.js", () => {
beforeEach(() => {});
it("check without points", () => {
cy.manageCommand("cypress_reset");
login("test-student1@example.com", "test");
cy.visit("/course/test-lehrgang/competence");
cy.get('[data-cy="certificate-total-points-text"]').contains(
"Der Punktestand wird zu einem späteren Zeitpunkt berechnet."
);
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
)
.should("contain", "0 von 0 Punkten")
.and("contain", "0 von 2 Kompetenznachweis-Elementen");
// check on certificates page
cy.get('[data-cy="certificates-show-all-button"]').click();
cy.get('[data-cy="certificate-total-points-text"]').contains(
"Der Punktestand wird zu einem späteren Zeitpunkt berechnet."
);
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
)
.should(
"contain",
"Der Punktestand wird zu einem späteren Zeitpunkt berechnet."
)
.and("contain", "0 von 2 Kompetenznachweis-Elementen");
// check certificate detail page
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]'
).click();
cy.get(
'[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]'
).should("contain", "Höchstpunktzahl");
cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]'
).should("contain", "Höchstpunktzahl");
});
it("check with finished edoniq test", () => {
cy.manageCommand(
"cypress_reset --create-assignment-completion --create-edoniq-test-results"
);
login("test-student1@example.com", "test");
cy.visit("/course/test-lehrgang/competence");
cy.get('[data-cy="certificate-total-points-text"]').contains(
"Zwischenstand Gesamtpunktzahl: 19 von 24 Punkten"
);
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
)
.should("contain", "19 von 24 Punkten")
.and("contain", "1 von 2 Kompetenznachweis-Elementen");
// check on certificates page
cy.get('[data-cy="certificates-show-all-button"]').click();
cy.get('[data-cy="certificate-total-points-text"]')
.should("contain", "19")
.and("contain", "Zwischenstand");
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
)
.should("contain", "19")
.and("contain", "Zwischenstand")
.and("contain", "1 von 2 Kompetenznachweis-Elementen");
// check certificate detail page
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]'
).click();
cy.get(
'[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]'
)
.should("contain", "Höchstpunktzahl")
.and("contain", "Ergebnisse abgegeben");
cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]'
)
.should("contain", "19")
.and("contain", "Bewertung freigegeben");
});
it("check with finished edoniq test and finished casework", () => {
cy.manageCommand(
"cypress_reset --create-assignment-evaluation --create-edoniq-test-results"
);
login("test-student1@example.com", "test");
cy.visit("/course/test-lehrgang/competence");
cy.get('[data-cy="certificate-total-points-text"]').contains(
"Zwischenstand Gesamtpunktzahl: 43 von 48 Punkten"
);
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
)
.should("contain", "43 von 48 Punkten")
.and("contain", "2 von 2 Kompetenznachweis-Elementen");
// check on certificates page
cy.get('[data-cy="certificates-show-all-button"]').click();
cy.get('[data-cy="certificate-total-points-text"]')
.should("contain", "43")
.and("not.contain", "Zwischenstand");
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1"]'
)
.should("contain", "43")
.and("not.contain", "Zwischenstand")
.and("contain", "2 von 2 Kompetenznachweis-Elementen");
// check certificate detail page
cy.get(
'[data-cy="certificate-test-lehrgang-competencenavi-certificates-kompetenznachweis-1-detail-link"]'
).click();
cy.get(
'[data-cy="assignment-test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"]'
)
.should("contain", "24")
.and("contain", "von 24 Punkten")
.and("contain", "Bewertung freigegeben");
cy.get(
'[data-cy="assignment-test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"]'
)
.should("contain", "19")
.and("contain", "von 24 Punkten")
.and("contain", "Bewertung freigegeben");
});
});

View File

@ -0,0 +1,135 @@
import { login } from "../helpers";
describe("selfEvaluation.cy.js", () => {
beforeEach(() => {
cy.manageCommand("cypress_reset");
login("test-student1@example.com", "test");
// test-lehrgang-lp-circle-reisen-lu-reisen ist eine Selbstevaluation
// mit mehreren Schritten
cy.visit("/course/test-lehrgang/learn/reisen");
});
it("self evaluation should be neutral", () => {
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]')
.find('[data-cy="unknown"]')
.should("exist");
});
it("self evaluation from KompetenzNavi", () => {
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]')
.find('[data-cy="unknown"]')
.should("exist");
// data in KompetenzNavi/Übersicht is correct
cy.visit("/course/test-lehrgang/competence");
cy.get('[data-cy="self-evaluation-fail"]').should("have.text", "0");
cy.get('[data-cy="self-evaluation-success"]').should("have.text", "0");
cy.get('[data-cy="self-evaluation-unknown"]').should("have.text", "4");
// data in KompetenzNavi/Selbsteinschätzungen is correct
cy.visit("/course/test-lehrgang/competence/criteria");
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-fail"]').should(
"have.text",
"0"
);
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-success"]'
).should("have.text", "0");
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-unknown"]'
).should("have.text", "2");
// it can open self evaluation from within KompetenzNavi
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-open"]').click();
// starting the self evaluation will return to KompetenzNavi
cy.makeSelfEvaluation([true, false]);
cy.url().should("include", "/course/test-lehrgang/competence/criteria");
// check data again on KompetenzNavi
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-fail"]').should(
"have.text",
"1"
);
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-success"]'
).should("have.text", "1");
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-unknown"]'
).should("have.text", "0");
// data in KompetenzNavi/Übersicht is correct
cy.visit("/course/test-lehrgang/competence");
cy.get('[data-cy="self-evaluation-fail"]').should("have.text", "1");
cy.get('[data-cy="self-evaluation-success"]').should("have.text", "1");
cy.get('[data-cy="self-evaluation-unknown"]').should("have.text", "2");
});
it("should be able to make a happy self evaluation", () => {
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]').click();
cy.makeSelfEvaluation([true, true]);
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]')
.find('[data-cy="success"]')
.should("exist");
// starting the self evaluation from circle should return to circle
cy.url().should("include", "/course/test-lehrgang/learn/reisen");
// data in KompetenzNavi / Selbsteinschätzungen is correct
cy.visit("/course/test-lehrgang/competence/criteria");
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-fail"]').should(
"have.text",
"0"
);
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-success"]'
).should("have.text", "2");
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-unknown"]'
).should("have.text", "0");
});
it("should be able to make a fail self evaluation", () => {
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]').click();
cy.makeSelfEvaluation([false, false]);
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]')
.find('[data-cy="fail"]')
.should("exist");
// data in KompetenzNavi / Selbsteinschätzungen is correct
cy.visit("/course/test-lehrgang/competence/criteria");
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-fail"]').should(
"have.text",
"2"
);
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-success"]'
).should("have.text", "0");
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-unknown"]'
).should("have.text", "0");
});
it("should be able to make a mixed self evaluation", () => {
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]').click();
cy.makeSelfEvaluation([false, true]);
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen"]')
.find('[data-cy="fail"]')
.should("exist");
// data in KompetenzNavi / Selbsteinschätzungen is correct
cy.visit("/course/test-lehrgang/competence/criteria");
cy.get('[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-fail"]').should(
"have.text",
"1"
);
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-success"]'
).should("have.text", "1");
cy.get(
'[data-cy="test-lehrgang-lp-circle-reisen-lu-reisen-unknown"]'
).should("have.text", "0");
});
});

View File

@ -7,7 +7,7 @@ describe("notification list page", () => {
});
it("can paginate notifications", () => {
login("admin", "test");
login("test-student1@example.com", "test");
cy.visit("/notifications");
cy.get('[data-cy="no-notifications"]').should("not.exist");

View File

@ -0,0 +1,29 @@
fragment CoursePageFields on CoursePageInterface {
title
id
slug
content_type
}
{
competence_certificate_list(course_slug:"test-lehrgang") {
...CoursePageFields
competence_certificates {
...CoursePageFields
assignments {
...CoursePageFields
assignment_type
max_points
learning_content {
title
id
slug
content_type
circle {
...CoursePageFields
}
}
}
}
}
}

View File

@ -0,0 +1,30 @@
{
learning_path(slug: "test-lehrgang-lp") {
id
title
content_type
topics {
id
title
content_type
circles {
id
title
content_type
learning_sequences {
id
title
icon
learning_units {
id
title
learning_contents {
id
title
}
}
}
}
}
}
}

View File

@ -25,7 +25,7 @@ from wagtail.blocks.list_block import ListBlock, ListValue
from wagtail.rich_text import RichText
def create_uk_fahrzeug_casework(course_id=COURSE_UK):
def create_uk_fahrzeug_casework(course_id=COURSE_UK, competence_certificate=None):
assignment_list_page = (
CoursePage.objects.get(course_id=course_id)
.get_children()
@ -36,6 +36,7 @@ def create_uk_fahrzeug_casework(course_id=COURSE_UK):
assignment = AssignmentFactory(
parent=assignment_list_page,
title="Überprüfen einer Motorfahrzeugs-Versicherungspolice",
competence_certificate=competence_certificate,
effort_required="ca. 5 Stunden",
intro_text=replace_whitespace(
"""

View File

@ -31,6 +31,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
evaluation_grade = graphene.Float()
evaluation_points = graphene.Float()
initialize_completion = graphene.Boolean(required=False)
@classmethod
def mutate(
@ -45,6 +46,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
completion_data_string="{}",
evaluation_grade=None,
evaluation_points=None,
initialize_completion=False,
):
if assignment_user_id is None:
assignment_user_id = info.context.user.id
@ -64,7 +66,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
if learning_content_page_id:
learning_content_page = Page.objects.get(id=learning_content_page_id)
if learning_content_page is None:
learning_content_page = assignment.learningcontentassignment_set.first()
learning_content_page = assignment.find_attached_learning_content()
assignment_data = {
"assignment_user": assignment_user,
@ -101,6 +103,7 @@ class AssignmentCompletionMutation(graphene.Mutation):
ac = update_assignment_completion(
copy_task_data=False,
initialize_completion=initialize_completion,
**assignment_data,
**evaluation_data,
)

View File

@ -1,14 +1,12 @@
import graphene
from rest_framework.exceptions import PermissionDenied
from vbv_lernwelt.assignment.graphql.types import (
AssignmentCompletionObjectType,
AssignmentObjectType,
resolve_assignment_completion,
)
from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletion
from vbv_lernwelt.assignment.models import Assignment
from vbv_lernwelt.course.graphql.types import resolve_course_page
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.course.permissions import has_course_access, is_course_session_expert
class AssignmentQuery(object):
@ -36,25 +34,10 @@ class AssignmentQuery(object):
assignment_user_id=None,
**kwargs,
):
if assignment_user_id is None:
assignment_user_id = info.context.user.id
if str(assignment_user_id) == str(
info.context.user.id
) or is_course_session_expert(info.context.user, course_session_id):
course_id = CourseSession.objects.get(id=course_session_id).course_id
if has_course_access(info.context.user, course_id):
if learning_content_page_id is None:
learning_content_page = Assignment.objects.get(
id=assignment_id
).learningcontentassignment_set.first()
if learning_content_page:
learning_content_page_id = learning_content_page.id
return AssignmentCompletion.objects.filter(
assignment_user_id=assignment_user_id,
assignment_id=assignment_id,
learning_content_page_id=learning_content_page_id,
course_session_id=course_session_id,
).first()
raise PermissionDenied()
return resolve_assignment_completion(
info,
assignment_id,
course_session_id,
learning_content_page_id,
assignment_user_id,
)

View File

@ -1,27 +1,14 @@
import graphene
from graphene.types.generic import GenericScalar
from graphene_django import DjangoObjectType
from rest_framework.exceptions import PermissionDenied
from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletion
from vbv_lernwelt.core.graphql.types import JSONStreamField
from vbv_lernwelt.course.graphql.interfaces import CoursePageInterface
class AssignmentObjectType(DjangoObjectType):
tasks = JSONStreamField()
evaluation_tasks = JSONStreamField()
performance_objectives = JSONStreamField()
class Meta:
model = Assignment
interfaces = (CoursePageInterface,)
fields = (
"assignment_type",
"intro_text",
"effort_required",
"evaluation_description",
"evaluation_document_url",
)
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.course.permissions import has_course_access, is_course_session_expert
from vbv_lernwelt.learnpath.graphql.types import LearningContentInterface
class AssignmentCompletionObjectType(DjangoObjectType):
@ -47,3 +34,86 @@ class AssignmentCompletionObjectType(DjangoObjectType):
"evaluation_grade",
"evaluation_points",
)
class AssignmentObjectType(DjangoObjectType):
tasks = JSONStreamField()
evaluation_tasks = JSONStreamField()
performance_objectives = JSONStreamField()
max_points = graphene.Int()
learning_content = graphene.Field(LearningContentInterface)
completion = graphene.Field(
AssignmentCompletionObjectType,
course_session_id=graphene.ID(required=True),
learning_content_page_id=graphene.ID(required=False),
assignment_user_id=graphene.UUID(required=False),
)
class Meta:
model = Assignment
interfaces = (CoursePageInterface,)
fields = (
"assignment_type",
"intro_text",
"effort_required",
"evaluation_description",
"evaluation_document_url",
"learning_content",
"competence_certificate",
)
def resolve_max_points(self, info):
return self.get_max_points()
def resolve_learning_content(self, info):
return self.find_attached_learning_content()
def resolve_completion(
self,
info,
course_session_id,
learning_content_page_id=None,
assignment_user_id=None,
):
if learning_content_page_id is None:
lp = self.find_attached_learning_content()
if lp:
learning_content_page_id = lp.id
return resolve_assignment_completion(
info=info,
course_session_id=course_session_id,
learning_content_page_id=learning_content_page_id,
assignment_user_id=assignment_user_id,
assignment_id=self.id,
)
def resolve_assignment_completion(
info,
assignment_id,
course_session_id,
learning_content_page_id=None,
assignment_user_id=None,
):
if assignment_user_id is None:
assignment_user_id = info.context.user.id
if str(assignment_user_id) == str(info.context.user.id) or is_course_session_expert(
info.context.user, course_session_id
):
course_id = CourseSession.objects.get(id=course_session_id).course_id
if has_course_access(info.context.user, course_id):
if learning_content_page_id is None:
learning_content_page = Assignment.objects.get(
id=assignment_id
).find_attached_learning_content()
if learning_content_page:
learning_content_page_id = learning_content_page.id
return AssignmentCompletion.objects.filter(
assignment_user_id=assignment_user_id,
assignment_id=assignment_id,
learning_content_page_id=learning_content_page_id,
course_session_id=course_session_id,
).first()
raise PermissionDenied()

View File

@ -0,0 +1,42 @@
# Generated by Django 3.2.20 on 2023-09-01 09:12
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
(
"competence",
"0003_competencecertificate_competencecertificatelist_competencenavipage",
),
("assignment", "0006_auto_20230823_1127"),
]
operations = [
migrations.AddField(
model_name="assignment",
name="competence_certificate",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="competence.competencecertificate",
),
),
migrations.AlterField(
model_name="assignment",
name="assignment_type",
field=models.CharField(
choices=[
("CASEWORK", "CASEWORK"),
("PREP_ASSIGNMENT", "PREP_ASSIGNMENT"),
("REFLECTION", "REFLECTION"),
("CONDITION_ACCEPTANCE", "CONDITION_ACCEPTANCE"),
("EDONIQ_TEST", "EDONIQ_TEST"),
],
default="CASEWORK",
max_length=50,
),
),
]

View File

@ -5,7 +5,7 @@ from django.db import models
from django.db.models import UniqueConstraint
from slugify import slugify
from wagtail import blocks
from wagtail.admin.panels import FieldPanel
from wagtail.admin.panels import FieldPanel, PageChooserPanel
from wagtail.fields import RichTextField, StreamField
from wagtail.models import Page
@ -113,6 +113,7 @@ class AssignmentType(Enum):
PREP_ASSIGNMENT = "PREP_ASSIGNMENT" # Vorbereitungsauftrag
REFLECTION = "REFLECTION" # Reflexion
CONDITION_ACCEPTANCE = "CONDITION_ACCEPTANCE" # Bedingungsannahme
EDONIQ_TEST = "EDONIQ_TEST" # EdonIQ Test
class Assignment(CourseBasePage):
@ -126,12 +127,25 @@ class Assignment(CourseBasePage):
"evaluation_tasks",
]
def get_admin_display_title(self):
circle_title = self.get_attached_circle_title()
if circle_title:
return f"{circle_title}: {self.title}"
return self.title
assignment_type = models.CharField(
max_length=50,
choices=[(tag.value, tag.value) for tag in AssignmentType],
default=AssignmentType.CASEWORK.value,
)
competence_certificate = models.ForeignKey(
"competence.CompetenceCertificate",
null=True,
blank=True,
on_delete=models.SET_NULL,
)
intro_text = RichTextField(
help_text="Erläuterung der Ausgangslage",
features=DEFAULT_RICH_TEXT_FEATURES_WITH_HEADER,
@ -180,6 +194,7 @@ class Assignment(CourseBasePage):
content_panels = Page.content_panels + [
FieldPanel("assignment_type"),
PageChooserPanel("competence_certificate", "competence.CompetenceCertificate"),
FieldPanel("intro_text"),
FieldPanel("effort_required"),
FieldPanel("performance_objectives"),
@ -239,6 +254,39 @@ class Assignment(CourseBasePage):
def get_input_tasks(self):
return self.filter_user_subtasks() + self.get_evaluation_tasks()
def get_max_points(self):
return sum(
[task["value"].get("max_points", 0) for task in self.get_evaluation_tasks()]
)
def find_attached_learning_content(self):
"""
Returns the first learning content page attached to this assignment
"""
page = self.learningcontentassignment_set.first()
if page:
return page.specific
page = self.learningcontentedoniqtest_set.first()
if page:
return page.specific
return None
def get_frontend_url(self):
lp = self.find_attached_learning_content()
if lp:
return lp.get_frontend_url()
return ""
def get_attached_circle_title(self):
if self.learningcontentassignment_set.count() > 1:
# probably "Reflexion" which is attached to multiple circles
return ""
lp = self.find_attached_learning_content()
if lp and lp.get_parent_circle():
return lp.get_parent_circle().title
return ""
class AssignmentCompletionStatus(Enum):
IN_PROGRESS = "IN_PROGRESS"

View File

@ -1,5 +1,4 @@
from copy import deepcopy
from gettext import gettext
from django.utils import timezone
from rest_framework import serializers
@ -16,7 +15,6 @@ from vbv_lernwelt.core.models import User
from vbv_lernwelt.core.utils import find_first
from vbv_lernwelt.course.models import CourseCompletionStatus, CourseSession
from vbv_lernwelt.course.services import mark_course_completion
from vbv_lernwelt.notify.email.email_services import EmailTemplate
from vbv_lernwelt.notify.services import NotificationService
@ -32,6 +30,7 @@ def update_assignment_completion(
evaluation_points: float | None = None,
validate_completion_status_change: bool = True,
copy_task_data: bool = False,
initialize_completion: bool = False,
) -> AssignmentCompletion:
"""
:param completion_data: should have the following structure:
@ -50,6 +49,8 @@ def update_assignment_completion(
:param copy_task_data: if true, the task data will be copied to the completion data
used for "SUBMITTED" and "EVALUATION_SUBMITTED" status, so that we don't lose the question
context
:param initialize_completion: if true, the completion will be created, but not updated
used as a workaround for initial work with the object on the frontend
:return: AssignmentCompletion
"""
if completion_data is None:
@ -64,6 +65,10 @@ def update_assignment_completion(
else None,
)
if initialize_completion:
# ignore further updates
return ac
if not is_valid_assignment_completion_status(completion_status):
raise serializers.ValidationError(
{
@ -140,7 +145,11 @@ def update_assignment_completion(
)
elif completion_status == AssignmentCompletionStatus.EVALUATION_SUBMITTED:
ac.evaluation_submitted_at = timezone.now()
learning_content_assignment = assignment.learningcontentassignment_set.first()
learning_content_assignment = (
learning_content_page
if learning_content_page
else assignment.find_attached_learning_content()
)
if learning_content_assignment:
assignment_frontend_url = learning_content_assignment.get_frontend_url()
NotificationService.send_assignment_evaluated_notification(
@ -195,8 +204,16 @@ def update_assignment_completion(
acl.completion_data[key].update(task_data)
acl.save()
if completion_status == AssignmentCompletionStatus.SUBMITTED:
learning_content = assignment.learningcontentassignment_set.first()
if completion_status in [
AssignmentCompletionStatus.EVALUATION_SUBMITTED,
AssignmentCompletionStatus.EVALUATION_IN_PROGRESS,
AssignmentCompletionStatus.SUBMITTED,
]:
learning_content = (
learning_content_page
if learning_content_page
else assignment.find_attached_learning_content()
)
if learning_content:
mark_course_completion(
user=assignment_user,

View File

@ -235,7 +235,7 @@ class AttendanceCourseUserMutationTestCase(GraphQLTestCase):
ac = AssignmentCompletion.objects.create(
assignment_user=self.student,
assignment=self.assignment,
learning_content_page=self.assignment.learningcontentassignment_set.first(),
learning_content_page=self.assignment.find_attached_learning_content(),
course_session=self.course_session,
completion_status="SUBMITTED",
submitted_at=timezone.now(),
@ -447,7 +447,7 @@ class AttendanceCourseUserMutationTestCase(GraphQLTestCase):
"""
reflection = Assignment.objects.get(slug="test-lehrgang-assignment-reflexion")
reflection_subtasks = reflection.filter_user_subtasks()
reflection_learning_content = reflection.learningcontentassignment_set.first()
reflection_learning_content = reflection.find_attached_learning_content()
self.client.force_login(self.student)
user_text_input = find_first(

View File

@ -21,6 +21,7 @@ def request_assignment_completion_status(request, assignment_id, course_session_
"assignment_user_id",
"completion_status",
"evaluation_grade",
"evaluation_points",
"learning_content_page_id",
)
return Response(status=200, data=qs)

View File

@ -1,9 +1,9 @@
from vbv_lernwelt.competence.factories import (
CompetencePageFactory,
CompetenceProfilePageFactory,
ActionCompetenceFactory,
ActionCompetenceListPageFactory,
PerformanceCriteriaFactory,
)
from vbv_lernwelt.competence.models import CompetencePage
from vbv_lernwelt.competence.models import ActionCompetence, CompetenceNaviPage
from vbv_lernwelt.course.consts import COURSE_UK, COURSE_UK_FR, COURSE_UK_IT
from vbv_lernwelt.course.models import CoursePage
from vbv_lernwelt.learnpath.models import LearningPath, LearningUnit
@ -13,9 +13,9 @@ def create_uk_competence_profile(course_id=COURSE_UK):
course_page = CoursePage.objects.get(course_id=course_id)
slug_prefix = course_page.get_children().exact_type(LearningPath).first().slug
competence_profile_page = CompetenceProfilePageFactory(
title="KompetenzNavi",
parent=course_page,
competence_profile_page = ActionCompetenceListPageFactory(
title="Handlungskompetenzen",
parent=course_page.get_descendants().exact_type(CompetenceNaviPage).first(),
)
competences = [
@ -52,7 +52,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
]
for c in competences:
CompetencePageFactory(
ActionCompetenceFactory(
parent=competence_profile_page,
competence_id=c["competence_id"],
title=c["title"],
@ -60,7 +60,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
)
# Circle Kickoff
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük6",
@ -70,7 +70,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ük1",
@ -81,7 +81,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
)
# Circle Basis
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük2",
@ -91,7 +91,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük5",
@ -101,7 +101,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük6",
@ -111,7 +111,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e2"
),
competence_id="e2.pv.ük3",
@ -122,7 +122,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
)
# Circle Fahrzeug
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük2",
@ -132,7 +132,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük7",
@ -142,7 +142,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük11",
@ -152,7 +152,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ük1",
@ -162,7 +162,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ük2",
@ -172,7 +172,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ük3",
@ -182,7 +182,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ük4",
@ -192,7 +192,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ük1",
@ -202,7 +202,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ük2",
@ -212,7 +212,7 @@ def create_uk_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ük4",
@ -227,7 +227,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
course_page = CoursePage.objects.get(course_id=course_id)
slug_prefix = course_page.get_children().exact_type(LearningPath).first().slug
competence_profile_page = CompetenceProfilePageFactory(
competence_profile_page = ActionCompetenceListPageFactory(
title="KompetenzNavi",
parent=course_page,
)
@ -266,7 +266,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
]
for c in competences:
CompetencePageFactory(
ActionCompetenceFactory(
parent=competence_profile_page,
competence_id=c["competence_id"],
title=c["title"],
@ -275,7 +275,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
# Circle Fahrzeug
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci2",
@ -285,7 +285,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci7",
@ -295,7 +295,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci11",
@ -305,7 +305,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci1",
@ -315,7 +315,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci2",
@ -325,7 +325,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci3",
@ -335,7 +335,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci4",
@ -345,7 +345,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci1",
@ -355,7 +355,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci2",
@ -365,7 +365,7 @@ def create_uk_fr_competence_profile(course_id=COURSE_UK_FR):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci4",
@ -380,7 +380,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
course_page = CoursePage.objects.get(course_id=course_id)
slug_prefix = course_page.get_children().exact_type(LearningPath).first().slug
competence_profile_page = CompetenceProfilePageFactory(
competence_profile_page = ActionCompetenceListPageFactory(
title="KompetenzNavi",
parent=course_page,
)
@ -419,7 +419,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
]
for c in competences:
CompetencePageFactory(
ActionCompetenceFactory(
parent=competence_profile_page,
competence_id=c["competence_id"],
title=c["title"],
@ -428,7 +428,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
# Circle Fahrzeug
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci2",
@ -438,7 +438,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci7",
@ -448,7 +448,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci11",
@ -458,7 +458,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci1",
@ -468,7 +468,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci2",
@ -478,7 +478,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci3",
@ -488,7 +488,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci4",
@ -498,7 +498,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci1",
@ -508,7 +508,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci2",
@ -518,7 +518,7 @@ def create_uk_it_competence_profile(course_id=COURSE_UK_IT):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci4",

View File

@ -1,9 +1,9 @@
from vbv_lernwelt.competence.factories import (
CompetencePageFactory,
CompetenceProfilePageFactory,
ActionCompetenceFactory,
ActionCompetenceListPageFactory,
PerformanceCriteriaFactory,
)
from vbv_lernwelt.competence.models import CompetencePage
from vbv_lernwelt.competence.models import ActionCompetence
from vbv_lernwelt.course.consts import COURSE_UK
from vbv_lernwelt.course.models import CoursePage
from vbv_lernwelt.learnpath.models import LearningPath, LearningUnit
@ -13,7 +13,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
course_page = CoursePage.objects.get(course_id=course_id)
slug_prefix = course_page.get_children().exact_type(LearningPath).first().slug
competence_profile_page = CompetenceProfilePageFactory(
competence_profile_page = ActionCompetenceListPageFactory(
title="KompetenzNavi",
parent=course_page,
)
@ -53,7 +53,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
for c in competences:
print(c["title"])
CompetencePageFactory(
ActionCompetenceFactory(
parent=competence_profile_page,
competence_id=c["competence_id"],
title=c["title"],
@ -61,7 +61,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
)
# Circle Fahrzeug
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük2",
@ -71,7 +71,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük7",
@ -81,7 +81,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ük11",
@ -91,7 +91,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ük1",
@ -101,7 +101,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ük2",
@ -111,7 +111,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ük3",
@ -121,7 +121,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ük4",
@ -131,7 +131,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ük1",
@ -141,7 +141,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ük2",
@ -151,7 +151,7 @@ def create_uk_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ük4",
@ -166,7 +166,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
course_page = CoursePage.objects.get(course_id=course_id)
slug_prefix = course_page.get_children().exact_type(LearningPath).first().slug
competence_profile_page = CompetenceProfilePageFactory(
competence_profile_page = ActionCompetenceListPageFactory(
title="KompetenzNavi",
parent=course_page,
)
@ -206,7 +206,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
for c in competences:
print(c["title"])
CompetencePageFactory(
ActionCompetenceFactory(
parent=competence_profile_page,
competence_id=c["competence_id"],
title=c["title"],
@ -214,7 +214,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
)
# Circle Fahrzeug
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci2",
@ -224,7 +224,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci7",
@ -234,7 +234,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci11",
@ -244,7 +244,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci1",
@ -254,7 +254,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci2",
@ -264,7 +264,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci3",
@ -274,7 +274,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci4",
@ -284,7 +284,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci1",
@ -294,7 +294,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci2",
@ -304,7 +304,7 @@ def create_uk_fr_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci4",
@ -319,7 +319,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
course_page = CoursePage.objects.get(course_id=course_id)
slug_prefix = course_page.get_children().exact_type(LearningPath).first().slug
competence_profile_page = CompetenceProfilePageFactory(
competence_profile_page = ActionCompetenceListPageFactory(
title="KompetenzNavi",
parent=course_page,
)
@ -359,7 +359,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
for c in competences:
print(c["title"])
CompetencePageFactory(
ActionCompetenceFactory(
parent=competence_profile_page,
competence_id=c["competence_id"],
title=c["title"],
@ -367,7 +367,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
)
# Circle Fahrzeug
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci2",
@ -377,7 +377,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci7",
@ -387,7 +387,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="c3"
),
competence_id="c3.pv.ci11",
@ -397,7 +397,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci1",
@ -407,7 +407,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci2",
@ -417,7 +417,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci3",
@ -427,7 +427,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="d2"
),
competence_id="d2.pv.ci4",
@ -437,7 +437,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci1",
@ -447,7 +447,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci2",
@ -457,7 +457,7 @@ def create_uk_it_training_competence_profile(course_id=COURSE_UK):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="e4"
),
competence_id="e4.pv.ci4",

View File

@ -1,9 +1,9 @@
from vbv_lernwelt.competence.factories import (
CompetencePageFactory,
CompetenceProfilePageFactory,
ActionCompetenceFactory,
ActionCompetenceListPageFactory,
PerformanceCriteriaFactory,
)
from vbv_lernwelt.competence.models import CompetencePage
from vbv_lernwelt.competence.models import ActionCompetence
from vbv_lernwelt.course.models import CoursePage
from vbv_lernwelt.learnpath.models import LearningPath, LearningUnit
@ -12,7 +12,7 @@ def create_vv_competence_profile(course_id):
course_page = CoursePage.objects.get(course_id=course_id)
slug_prefix = course_page.get_children().exact_type(LearningPath).first().slug
competence_profile_page = CompetenceProfilePageFactory(
competence_profile_page = ActionCompetenceListPageFactory(
title="KompetenzNavi",
parent=course_page,
)
@ -122,7 +122,7 @@ def create_vv_competence_profile(course_id):
]
for c in competences:
CompetencePageFactory(
ActionCompetenceFactory(
parent=competence_profile_page,
competence_id=c["competence_id"],
title=c["title"],
@ -132,7 +132,7 @@ def create_vv_competence_profile(course_id):
# Daten anhand von WEVM_Version Oktober 2022
# Einstieg/Beobachten Selbsteinschätzung «Einkommenssicherung»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.1",
@ -142,7 +142,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.2",
@ -152,7 +152,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.3",
@ -162,7 +162,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.4",
@ -172,7 +172,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.5",
@ -182,7 +182,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B1"
),
competence_id="B1.1",
@ -192,7 +192,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B1"
),
competence_id="B1.2",
@ -202,7 +202,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B2"
),
competence_id="B2.3",
@ -214,7 +214,7 @@ def create_vv_competence_profile(course_id):
# Einstieg / Anwenden Selbsteinschätzung «Fahrzeug»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A1"
),
competence_id="A1.6",
@ -224,7 +224,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.1",
@ -234,7 +234,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.2",
@ -244,7 +244,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.3",
@ -254,7 +254,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.4",
@ -264,7 +264,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.5",
@ -276,7 +276,7 @@ def create_vv_competence_profile(course_id):
# Einstieg / Anwenden Selbsteinschätzung «Reisen»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.3",
@ -286,7 +286,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.4",
@ -296,7 +296,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A2"
),
competence_id="A2.5",
@ -308,7 +308,7 @@ def create_vv_competence_profile(course_id):
# Analyse / Beobachten Selbsteinschätzung «Einkommenssicherung»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A1"
),
competence_id="A1.5",
@ -318,7 +318,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B1"
),
competence_id="B1.3",
@ -328,7 +328,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B2"
),
competence_id="B2.1",
@ -338,7 +338,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B2"
),
competence_id="B2.2",
@ -350,7 +350,7 @@ def create_vv_competence_profile(course_id):
# Analyse/Anwenden Selbsteinschätzung «Fahrzeug»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B1"
),
competence_id="B1.3",
@ -360,7 +360,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B2"
),
competence_id="B2.1",
@ -370,7 +370,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B2"
),
competence_id="B2.2",
@ -382,7 +382,7 @@ def create_vv_competence_profile(course_id):
# Analyse/Anwenden Selbsteinschätzung «Reisen»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B1"
),
competence_id="B1.3",
@ -392,7 +392,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B2"
),
competence_id="B2.1",
@ -402,7 +402,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B2"
),
competence_id="B2.2",
@ -412,7 +412,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="C1"
),
competence_id="C1.1",
@ -424,7 +424,7 @@ def create_vv_competence_profile(course_id):
# Lösung/Anwenden Selbsteinschätzung «Fahrzeug»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B4"
),
competence_id="B4.2",
@ -434,7 +434,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B4"
),
competence_id="B4.3",
@ -444,7 +444,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B4"
),
competence_id="B4.4",
@ -454,7 +454,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="C1"
),
competence_id="C1.1",
@ -464,7 +464,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="C1"
),
competence_id="C1.2",
@ -476,7 +476,7 @@ def create_vv_competence_profile(course_id):
# Lösung/Anwenden Selbsteinschätzung «Reisen»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B3"
),
competence_id="B3.2",
@ -486,7 +486,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B4"
),
competence_id="B4.2",
@ -496,7 +496,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B4"
),
competence_id="B4.3",
@ -506,7 +506,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B4"
),
competence_id="B4.4",
@ -516,7 +516,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="C1"
),
competence_id="C1.2",
@ -526,7 +526,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="C1"
),
competence_id="C1.3",
@ -538,7 +538,7 @@ def create_vv_competence_profile(course_id):
# Abschluss/Anwenden Selbsteinschätzung «Fahrzeug»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A1"
),
competence_id="A1.2",
@ -548,7 +548,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="A4"
),
competence_id="A4.1",
@ -558,7 +558,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B4"
),
competence_id="B4.6",
@ -568,7 +568,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="C1"
),
competence_id="C1.3",
@ -580,7 +580,7 @@ def create_vv_competence_profile(course_id):
# Abschluss / Anwenden Selbsteinschätzung «Reisen»
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="B4"
),
competence_id="B4.6",
@ -590,7 +590,7 @@ def create_vv_competence_profile(course_id):
),
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(
parent=ActionCompetence.objects.get(
slug__startswith=slug_prefix.replace("-lp", ""), competence_id="C3"
),
competence_id="C3.1",

View File

@ -1,6 +1,7 @@
from vbv_lernwelt.competence.factories import (
CompetencePageFactory,
CompetenceProfilePageFactory,
ActionCompetenceFactory,
ActionCompetenceListPageFactory,
CompetenceNaviPageFactory,
)
from vbv_lernwelt.course.consts import COURSE_VERSICHERUNGSVERMITTLERIN_ID
from vbv_lernwelt.course.models import CoursePage
@ -9,11 +10,16 @@ from vbv_lernwelt.course.models import CoursePage
def create_vv_new_competence_profile(course_id=COURSE_VERSICHERUNGSVERMITTLERIN_ID):
course_page = CoursePage.objects.get(course_id=course_id)
competence_profile_page = CompetenceProfilePageFactory(
competence_navi_page = CompetenceNaviPageFactory(
title="KompetenzNavi",
parent=course_page,
)
competence_profile_page = ActionCompetenceListPageFactory(
title="Handlungskompetenzen",
parent=competence_navi_page,
)
competences = [
{
"competence_id": "V1",
@ -38,7 +44,7 @@ def create_vv_new_competence_profile(course_id=COURSE_VERSICHERUNGSVERMITTLERIN_
]
for c in competences:
CompetencePageFactory(
ActionCompetenceFactory(
parent=competence_profile_page,
competence_id=c["competence_id"],
title=c["title"],

View File

@ -1,25 +1,49 @@
import wagtail_factories
from vbv_lernwelt.competence.models import (
CompetencePage,
CompetenceProfilePage,
ActionCompetence,
ActionCompetenceListPage,
CompetenceCertificate,
CompetenceCertificateList,
CompetenceNaviPage,
PerformanceCriteria,
)
class CompetenceProfilePageFactory(wagtail_factories.PageFactory):
class CompetenceNaviPageFactory(wagtail_factories.PageFactory):
title = "KompetenzNavi"
class Meta:
model = CompetenceProfilePage
model = CompetenceNaviPage
class CompetencePageFactory(wagtail_factories.PageFactory):
class CompetenceCertificateListFactory(wagtail_factories.PageFactory):
title = "Kompetenznachweise"
class Meta:
model = CompetenceCertificateList
class CompetenceCertificateFactory(wagtail_factories.PageFactory):
title = "Kompetenznachweis"
class Meta:
model = CompetenceCertificate
class ActionCompetenceListPageFactory(wagtail_factories.PageFactory):
title = "Handlungskompetenzen"
class Meta:
model = ActionCompetenceListPage
class ActionCompetenceFactory(wagtail_factories.PageFactory):
competence_id = "A1"
title = "Weiterempfehlung für Neukunden generieren"
class Meta:
model = CompetencePage
model = ActionCompetence
class PerformanceCriteriaFactory(wagtail_factories.PageFactory):

View File

@ -0,0 +1,41 @@
import graphene
from vbv_lernwelt.competence.graphql.types import (
CompetenceCertificateListObjectType,
CompetenceCertificateObjectType,
)
from vbv_lernwelt.competence.models import (
CompetenceCertificate,
CompetenceCertificateList,
)
from vbv_lernwelt.course.graphql.types import resolve_course_page
class CompetenceCertificateQuery(object):
competence_certificate = graphene.Field(
CompetenceCertificateObjectType, id=graphene.ID(), slug=graphene.String()
)
competence_certificate_list = graphene.Field(
CompetenceCertificateListObjectType,
id=graphene.ID(),
slug=graphene.String(),
course_id=graphene.ID(),
course_slug=graphene.String(),
)
def resolve_competence_certificate(root, info, id=None, slug=None):
return resolve_course_page(CompetenceCertificate, root, info, id=id, slug=slug)
def resolve_competence_certificate_list(
root, info, id=None, slug=None, course_id=None, course_slug=None
):
return resolve_course_page(
CompetenceCertificateList,
root,
info,
id=id,
slug=slug,
course_id=course_id,
course_slug=course_slug,
)

View File

@ -0,0 +1,32 @@
from graphene import List
from graphene_django import DjangoObjectType
from vbv_lernwelt.assignment.graphql.types import AssignmentObjectType
from vbv_lernwelt.competence.models import (
CompetenceCertificate,
CompetenceCertificateList,
)
from vbv_lernwelt.course.graphql.interfaces import CoursePageInterface
class CompetenceCertificateObjectType(DjangoObjectType):
assignments = List(AssignmentObjectType)
class Meta:
model = CompetenceCertificate
interfaces = (CoursePageInterface,)
fields = ["assignments"]
def resolve_assignments(self, info):
return self.assignment_set.all()
class CompetenceCertificateListObjectType(DjangoObjectType):
competence_certificates = List(CompetenceCertificateObjectType)
class Meta:
model = CompetenceCertificateList
interfaces = (CoursePageInterface,)
def resolve_competence_certificates(self, info):
return CompetenceCertificate.objects.child_of(self)

View File

@ -0,0 +1,74 @@
# Generated by Django 3.2.20 on 2023-09-01 09:12
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("wagtailcore", "0089_log_entry_data_json_null_to_object"),
("competence", "0002_performancecriteria_learning_unit"),
]
operations = [
migrations.CreateModel(
name="CompetenceCertificate",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
],
options={
"abstract": False,
},
bases=("wagtailcore.page",),
),
migrations.CreateModel(
name="CompetenceCertificateList",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
],
options={
"abstract": False,
},
bases=("wagtailcore.page",),
),
migrations.CreateModel(
name="CompetenceNaviPage",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
],
options={
"abstract": False,
},
bases=("wagtailcore.page",),
),
]

View File

@ -0,0 +1,31 @@
# Generated by Django 3.2.20 on 2023-09-11 14:36
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("wagtailforms", "0005_alter_formsubmission_form_data"),
("wagtailcore", "0089_log_entry_data_json_null_to_object"),
("wagtailredirects", "0008_add_verbose_name_plural"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("course", "0004_auto_20230823_1744"),
("duedate", "0004_alter_duedate_start"),
("contenttypes", "0002_remove_content_type_name"),
(
"competence",
"0003_competencecertificate_competencecertificatelist_competencenavipage",
),
]
operations = [
migrations.RenameModel(
old_name="CompetencePage",
new_name="ActionCompetence",
),
migrations.RenameModel(
old_name="CompetenceProfilePage",
new_name="ActionCompetenceListPage",
),
]

View File

@ -0,0 +1,130 @@
# Generated by Django 3.2.20 on 2023-09-11 14:39
from django.db import migrations
from django.db.models import Q
from vbv_lernwelt.assignment.models import Assignment
from vbv_lernwelt.competence.models import (
ActionCompetence,
ActionCompetenceListPage,
CompetenceCertificate,
CompetenceCertificateList,
CompetenceNaviPage,
)
from vbv_lernwelt.course.consts import (
COURSE_TEST_ID,
COURSE_UK,
COURSE_UK_FR,
COURSE_UK_IT,
)
from vbv_lernwelt.course.creators.test_course import create_edoniq_test_assignment
from vbv_lernwelt.course.models import CoursePage
from vbv_lernwelt.learnpath.models import Circle, LearningContentEdoniqTest
def refactor_competence_wagtail_tree(apps=None, schema_editor=None):
# create `CompetenceNaviPage` for every course where there is none
for course_page in CoursePage.objects.all():
competence_navi_page = (
course_page.get_descendants().exact_type(CompetenceNaviPage).first()
)
if not competence_navi_page:
competence_navi_page = CompetenceNaviPage(
title="KompetenzNavi",
)
course_page.add_child(instance=competence_navi_page)
acl = course_page.get_descendants().exact_type(ActionCompetenceListPage).first()
acl.title = "Handlungskompetenzen"
acl.save()
acl.specific.save_revision().publish()
acl = course_page.get_descendants().exact_type(ActionCompetenceListPage).first()
acl.move(competence_navi_page, pos="last-child")
# create `CompetenceCertificateList`
competence_certificate_list = (
competence_navi_page.get_descendants()
.exact_type(CompetenceCertificateList)
.first()
)
if course_page.course.id in [
COURSE_TEST_ID,
COURSE_UK,
COURSE_UK_FR,
COURSE_UK_IT,
]:
if not competence_certificate_list:
title = "Kompetenznachweise"
if course_page.course.id == COURSE_UK_FR:
title = "Contrôles de compétences"
if course_page.course.id == COURSE_UK_IT:
title = "Controlli delle competenze"
competence_certificate_list = CompetenceCertificateList(title=title)
competence_navi_page.add_child(instance=competence_certificate_list)
title = "Kompetenznachweis 1"
if course_page.course.id == COURSE_UK_FR:
title = "Contrôle de compétences 1"
if course_page.course.id == COURSE_UK_IT:
title = "Controllo delle competenze 1"
competence_certificate = CompetenceCertificate(
title=title,
)
competence_certificate_list.add_child(instance=competence_certificate)
for casework_assignment in Assignment.objects.filter(
assignment_type="CASEWORK"
).descendant_of(course_page):
casework_assignment.competence_certificate = competence_certificate
casework_assignment.save()
title = "Wissens- und Verständnisfragen"
if course_page.course.id == COURSE_UK_FR:
title = "Questions de connaissance et de compréhension "
if course_page.course.id == COURSE_UK_IT:
title = "Domande di conoscenza e di comprensione"
edoniq_test = create_edoniq_test_assignment(
course_id=course_page.course.id,
title=title,
competence_certificate=competence_certificate,
)
circle_basis = (
Circle.objects.descendant_of(course_page)
.filter(Q(title="Basis") | Q(title="Base"))
.first()
)
if circle_basis:
for (
learning_content_edoniq
) in LearningContentEdoniqTest.objects.all().descendant_of(
circle_basis
):
learning_content_edoniq.content_assignment = edoniq_test
learning_content_edoniq.save()
for ac in ActionCompetenceListPage.objects.all():
# trigger slug update by saving
ac.save()
for competence in ActionCompetence.objects.all():
if competence.competence_id.endswith(":"):
# remove trailing colon
competence.competence_id = competence.competence_id[:-1]
competence.save()
class Migration(migrations.Migration):
dependencies = [
("competence", "0004_rename_models"),
("learnpath", "0005_alter_learningcontentedoniqtest_content_assignment"),
]
operations = [
migrations.RunPython(refactor_competence_wagtail_tree),
]

View File

@ -9,38 +9,93 @@ from vbv_lernwelt.core.model_utils import find_available_slug
from vbv_lernwelt.course.models import CourseBasePage
class CompetenceProfilePage(CourseBasePage):
class CompetenceNaviPage(CourseBasePage):
parent_page_types = ["course.CoursePage"]
subpage_types = ["competence.CompetenceCertificateList"]
def get_frontend_url(self):
return f"/course/{self.slug.replace('-competencenavi', '')}/competence"
def save(self, clean=True, user=None, log_action=False, **kwargs):
if self.get_parent():
self.slug = find_available_slug(
slugify(f"{self.get_parent().slug}-competencenavi", allow_unicode=True),
ignore_page_id=self.id,
)
super(CompetenceNaviPage, self).save(clean, user, log_action, **kwargs)
class CompetenceCertificateList(CourseBasePage):
"""Kompetenznachweise für einen Lehrgang"""
parent_page_types = ["competence.CompetenceNaviPage"]
subpage_types = ["competence.CompetenceCertificate"]
def get_frontend_url(self):
return f"/course/{self.slug.replace('-competencenavi-certificates', '')}/competence/certificates"
def save(self, clean=True, user=None, log_action=False, **kwargs):
self.slug = find_available_slug(
slugify(f"{self.get_parent().slug}-certificates", allow_unicode=True),
ignore_page_id=self.id,
)
super(CompetenceCertificateList, self).save(clean, user, log_action, **kwargs)
class CompetenceCertificate(CourseBasePage):
"""einzelner Kompetenznachweis"""
parent_page_types = ["competence.CompetenceCertificateList"]
def __str__(self):
course = self.get_course()
return f"{course.title} - {self.title}"
def get_frontend_url(self):
return f"/course/{self.slug.replace('-competencenavi-certificates-', '/competence/certificates/')}"
def save(self, clean=True, user=None, log_action=False, **kwargs):
self.slug = find_available_slug(
slugify(f"{self.get_parent().slug}-{self.title}", allow_unicode=True),
ignore_page_id=self.id,
)
super(CompetenceCertificate, self).save(clean, user, log_action, **kwargs)
class ActionCompetenceListPage(CourseBasePage):
serialize_field_names = [
"course",
"circles",
"children",
]
parent_page_types = ["course.CoursePage"]
subpage_types = ["competence.CompetencePage"]
parent_page_types = ["competence.CompetenceNaviPage"]
subpage_types = ["competence.ActionCompetence"]
content_panels = [
FieldPanel("title", classname="full title"),
]
def get_frontend_url(self):
return f"/course/{self.slug.replace('-competence', '')}/competence"
return f"/course/{self.slug.replace('-competencenavi-competences', '')}/competence/competences"
def save(self, clean=True, user=None, log_action=False, **kwargs):
self.slug = find_available_slug(
slugify(f"{self.get_parent().slug}-competence", allow_unicode=True),
slugify(f"{self.get_parent().slug}-competences", allow_unicode=True),
ignore_page_id=self.id,
)
super(CompetenceProfilePage, self).save(clean, user, log_action, **kwargs)
super(ActionCompetenceListPage, self).save(clean, user, log_action, **kwargs)
class CompetencePage(CourseBasePage):
class ActionCompetence(CourseBasePage):
"""Handlungskompetenz"""
serialize_field_names = [
"competence_id",
"children",
]
parent_page_types = ["competence.CompetenceProfilePage"]
parent_page_types = ["competence.ActionCompetenceListPage"]
subpage_types = ["competence.PerformanceCriteria"]
competence_id = models.TextField(default="A1")
items = StreamField(
@ -63,11 +118,13 @@ class CompetencePage(CourseBasePage):
),
ignore_page_id=self.id,
)
super(CompetencePage, self).save(clean, user, log_action, **kwargs)
super(ActionCompetence, self).save(clean, user, log_action, **kwargs)
class PerformanceCriteria(CourseBasePage):
parent_page_types = ["competence.CompetencePage"]
"""Leistungskriterium"""
parent_page_types = ["competence.ActionCompetence"]
competence_id = models.TextField(default="A1.1")
learning_unit = models.ForeignKey(
"learnpath.LearningUnit",
@ -85,7 +142,9 @@ class PerformanceCriteria(CourseBasePage):
]
def save(self, clean=True, user=None, log_action=False, **kwargs):
profile_parent = self.get_ancestors().exact_type(CompetenceProfilePage).last()
profile_parent = (
self.get_ancestors().exact_type(ActionCompetenceListPage).last()
)
if self.learning_unit and self.learning_unit.course_category:
self.slug = find_available_slug(
slugify(

View File

@ -1,6 +1,6 @@
from rest_framework.test import APITestCase
from vbv_lernwelt.competence.models import CompetenceProfilePage
from vbv_lernwelt.competence.models import ActionCompetenceListPage
from vbv_lernwelt.core.admin import User
from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.course.creators.test_course import create_test_course
@ -14,8 +14,8 @@ class CompetenceAPITestCase(APITestCase):
self.client.login(username="admin", password="test")
def test_get_compentence_page(self):
slug = "test-lehrgang-competence"
competence_profile = CompetenceProfilePage.objects.get(slug=slug)
slug = "test-lehrgang-competencenavi-competences"
competence_profile = ActionCompetenceListPage.objects.get(slug=slug)
response = self.client.get(f"/api/course/page/{slug}/")
self.assertEqual(response.status_code, 200)

View File

@ -4,9 +4,12 @@ from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletion
from vbv_lernwelt.core.constants import (
TEST_COURSE_SESSION_BERN_ID,
TEST_STUDENT1_USER_ID,
TEST_TRAINER1_USER_ID,
)
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.creators.test_course import (
create_edoniq_test_result_data,
create_test_assignment_evaluation_data,
create_test_assignment_submitted_data,
)
from vbv_lernwelt.course.models import CourseCompletion, CourseSession
@ -15,11 +18,25 @@ from vbv_lernwelt.notify.models import Notification
@click.command()
@click.option(
"--create-completion/--no-create-completion",
"--create-assignment-completion/--no-create-assignment-completion",
default=False,
help="will create completion data for some users",
help="will create assignment completion data for test-student1@example.com",
)
def command(create_completion):
@click.option(
"--create-assignment-evaluation/--no-create-assignment-evaluation",
default=False,
help="will create assignment evaluation data for test-student1@example.com",
)
@click.option(
"--create-edoniq-test-results/--no-create-edoniq-test-results",
default=False,
help="will create edoniq result data for test-student1@example.com",
)
def command(
create_assignment_completion,
create_assignment_evaluation,
create_edoniq_test_results,
):
print("cypress reset data")
CourseCompletion.objects.all().delete()
Notification.objects.all().delete()
@ -27,8 +44,8 @@ def command(create_completion):
User.objects.all().update(language="de")
User.objects.all().update(additional_json_data={})
if create_completion:
print("create completion data for test course")
if create_assignment_completion or create_assignment_evaluation:
print("create assignment completion data for test course")
create_test_assignment_submitted_data(
assignment=Assignment.objects.get(
slug="test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"
@ -36,3 +53,24 @@ def command(create_completion):
course_session=CourseSession.objects.get(id=TEST_COURSE_SESSION_BERN_ID),
user=User.objects.get(id=TEST_STUDENT1_USER_ID),
)
if create_assignment_evaluation:
print("create assignment evaulation data for test course")
create_test_assignment_evaluation_data(
assignment=Assignment.objects.get(
slug="test-lehrgang-assignment-überprüfen-einer-motorfahrzeugs-versicherungspolice"
),
course_session=CourseSession.objects.get(id=TEST_COURSE_SESSION_BERN_ID),
assignment_user=User.objects.get(id=TEST_STUDENT1_USER_ID),
evaluation_user=User.objects.get(id=TEST_TRAINER1_USER_ID),
)
if create_edoniq_test_results:
print("create edoniq test results")
create_edoniq_test_result_data(
assignment=Assignment.objects.get(
slug="test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"
),
course_session=CourseSession.objects.get(id=TEST_COURSE_SESSION_BERN_ID),
assignment_user=User.objects.get(id=TEST_STUDENT1_USER_ID),
points=19,
)

View File

@ -2,15 +2,21 @@ import graphene
from vbv_lernwelt.assignment.graphql.mutations import AssignmentMutation
from vbv_lernwelt.assignment.graphql.queries import AssignmentQuery
from vbv_lernwelt.competence.graphql.queries import CompetenceCertificateQuery
from vbv_lernwelt.course.graphql.queries import CourseQuery
from vbv_lernwelt.course_session.graphql.mutations import CourseSessionMutation
from vbv_lernwelt.course_session.graphql.queries import CourseSessionQuery
from vbv_lernwelt.feedback.graphql.mutations import FeedbackMutation
from vbv_lernwelt.learnpath.graphql.queries import CircleQuery
from vbv_lernwelt.learnpath.graphql.queries import LearningPathQuery
class Query(
AssignmentQuery, CourseQuery, CourseSessionQuery, CircleQuery, graphene.ObjectType
AssignmentQuery,
CompetenceCertificateQuery,
CourseQuery,
CourseSessionQuery,
LearningPathQuery,
graphene.ObjectType,
):
pass

View File

@ -134,7 +134,31 @@ def check_rate_limit(request):
@permission_classes((IsAdminUser,))
def cypress_reset_view(request):
if not settings.APP_ENVIRONMENT.startswith("prod"):
call_command("cypress_reset")
# Checking for the flags in the POST request
create_assignment_completion = (
request.data.get("create_assignment_completion") == "true"
)
create_assignment_evaluation = (
request.data.get("create_assignment_evaluation") == "true"
)
create_edoniq_test_results = (
request.data.get("create_edoniq_test_results") == "true"
)
# TODO: Handle the flags as needed. For example:
if create_assignment_completion:
# Logic for creating assignment completion
pass
if create_edoniq_test_results:
# Logic for creating Edoniq test results
pass
call_command(
"cypress_reset",
create_assignment_completion=create_assignment_completion,
create_assignment_evaluation=create_assignment_evaluation,
create_edoniq_test_results=create_edoniq_test_results,
)
return HttpResponseRedirect("/server/admin/")

View File

@ -11,15 +11,26 @@ from vbv_lernwelt.assignment.creators.create_assignments import (
create_uk_fahrzeug_prep_assignment,
create_uk_reflection,
)
from vbv_lernwelt.assignment.models import Assignment, AssignmentCompletionStatus
from vbv_lernwelt.assignment.models import (
Assignment,
AssignmentCompletionStatus,
AssignmentListPage,
)
from vbv_lernwelt.assignment.services import update_assignment_completion
from vbv_lernwelt.assignment.tests.assignment_factories import AssignmentListPageFactory
from vbv_lernwelt.assignment.tests.assignment_factories import (
AssignmentFactory,
AssignmentListPageFactory,
EvaluationTaskBlockFactory,
)
from vbv_lernwelt.competence.factories import (
CompetencePageFactory,
CompetenceProfilePageFactory,
ActionCompetenceFactory,
ActionCompetenceListPageFactory,
CompetenceCertificateFactory,
CompetenceCertificateListFactory,
CompetenceNaviPageFactory,
PerformanceCriteriaFactory,
)
from vbv_lernwelt.competence.models import CompetencePage
from vbv_lernwelt.competence.models import ActionCompetence
from vbv_lernwelt.core.constants import (
TEST_COURSE_SESSION_BERN_ID,
TEST_COURSE_SESSION_ZURICH_ID,
@ -71,18 +82,24 @@ from vbv_lernwelt.media_library.tests.media_library_factories import (
def create_test_course(include_uk=True, include_vv=True, with_sessions=False):
# create_locales_for_wagtail()
course = create_test_course_with_categories()
create_test_competence_profile()
competence_certificate = create_test_competence_navi()
if include_uk:
# assignments create assignments parent page
course_page = CoursePage.objects.get(course_id=COURSE_TEST_ID)
_assignment_list_page = AssignmentListPageFactory(
parent=course_page,
)
create_uk_fahrzeug_casework(course_id=COURSE_TEST_ID)
create_uk_fahrzeug_casework(
course_id=COURSE_TEST_ID, competence_certificate=competence_certificate
)
create_uk_fahrzeug_prep_assignment(course_id=COURSE_TEST_ID)
create_uk_condition_acceptance(course_id=COURSE_TEST_ID)
create_uk_reflection(course_id=COURSE_TEST_ID)
create_edoniq_test_assignment(
course_id=COURSE_TEST_ID,
title="Edoniq Wissens- und Verständisfragen - Circle Fahrzeug (Demo)",
competence_certificate=competence_certificate,
)
create_test_learning_path(include_uk=include_uk, include_vv=include_vv)
create_test_media_library()
@ -212,6 +229,63 @@ def create_test_assignment_submitted_data(assignment, course_session, user):
)
def create_test_assignment_evaluation_data(
assignment, course_session, assignment_user, evaluation_user
):
if assignment and course_session and assignment_user and evaluation_user:
subtasks = assignment.get_evaluation_tasks()
evaluation_points = 0
for index, evaluation_task in enumerate(subtasks):
evaluation_points += evaluation_task["value"]["max_points"]
update_assignment_completion(
assignment_user=assignment_user,
assignment=assignment,
course_session=course_session,
learning_content_page=assignment.find_attached_learning_content(),
completion_data={
evaluation_task["id"]: {
"expert_data": {
"points": evaluation_task["value"]["max_points"],
"text": "Gut gemacht!",
}
},
},
completion_status=AssignmentCompletionStatus.EVALUATION_IN_PROGRESS,
evaluation_user=evaluation_user,
)
update_assignment_completion(
assignment_user=assignment_user,
assignment=assignment,
course_session=course_session,
learning_content_page=assignment.find_attached_learning_content(),
completion_data={},
completion_status=AssignmentCompletionStatus.EVALUATION_SUBMITTED,
evaluation_user=evaluation_user,
evaluation_grade=6,
evaluation_points=evaluation_points,
)
def create_edoniq_test_result_data(
assignment, course_session, assignment_user, points=24
):
if assignment and course_session and assignment_user:
update_assignment_completion(
assignment_user=assignment_user,
assignment=assignment,
course_session=course_session,
learning_content_page=assignment.find_attached_learning_content(),
completion_data={},
completion_status=AssignmentCompletionStatus.EVALUATION_SUBMITTED,
evaluation_user=User.objects.get(username="admin"),
evaluation_grade=6,
evaluation_points=points,
)
def create_test_course_with_categories(apps=None, schema_editor=None):
if apps is not None:
Course = apps.get_model("course", "Course")
@ -310,25 +384,15 @@ damit du erfolgreich mit deinem Lernpfad (durch-)starten kannst.
slug__startswith="test-lehrgang-assignment-fahrzeug-mein-erstes-auto"
),
),
LearningContentEdoniqTestFactory(
title="Wissens- und Verständnisfragen",
parent=circle,
description=RichText(
"<p>Folgender Test mit Wissens- und Verständnisfragen ist Teil des Kompetenznachweises. Der Test kann nur einmal durchgeführt werden und ist notenrelevant.</p>"
),
checkbox_text="Hiermit bestätige ich, dass ich die Anweisungen verstanden und die Redlichkeitserklärung akzeptiert habe.",
test_url="https://exam.vbv-afa.ch/e-tutor/v4/user/course/pre_course_object?aid=1689096897473,2147466097",
extended_time_test_url="https://exam2.vbv-afa.ch/e-tutor/v4/user/course/pre_course_object?aid=1689096897473,2147466097",
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(competence_id="X1"),
parent=ActionCompetence.objects.get(competence_id="X1"),
competence_id="X1.1",
title="Innerhalb des Handlungsfelds «Fahrzeug» bin ich fähig, die Ziele und Pläne des Kunden zu ergründen (SOLL).",
learning_unit=lu,
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(competence_id="X1"),
parent=ActionCompetence.objects.get(competence_id="X1"),
competence_id="X1.1",
title="Innerhalb des Handlungsfelds «Fahrzeug» bin ich fähig, die IST-Situation des Kunden mit der geeigneten Gesprächs-/Fragetechnik zu erfassen.",
learning_unit=lu,
@ -346,10 +410,20 @@ damit du erfolgreich mit deinem Lernpfad (durch-)starten kannst.
parent=circle,
)
LearningUnitFactory(title="Kompetenznachweis", parent=circle)
LearningContentPlaceholderFactory(
LearningContentEdoniqTestFactory(
title="Wissens- und Verständnisfragen",
parent=circle,
description=RichText(
"<p>Folgender Test mit Wissens- und Verständnisfragen ist Teil des Kompetenznachweises. Der Test kann nur einmal durchgeführt werden und ist notenrelevant.</p>"
),
content_assignment=Assignment.objects.get(
slug__startswith="test-lehrgang-assignment-edoniq-wissens-und-verständisfragen-circle-fahrzeug-demo"
),
checkbox_text="Hiermit bestätige ich, dass ich die Anweisungen verstanden und die Redlichkeitserklärung akzeptiert habe.",
test_url="https://exam.vbv-afa.ch/e-tutor/v4/user/course/pre_course_object?aid=1689096897473,2147466097",
extended_time_test_url="https://exam2.vbv-afa.ch/e-tutor/v4/user/course/pre_course_object?aid=1689096897473,2147466097",
)
LearningSequenceFactory(title="Transfer", parent=circle, icon="it-icon-ls-end")
LearningUnitFactory(title="Transfer", parent=circle)
LearningContentAssignmentFactory(
@ -409,13 +483,13 @@ def create_test_circle_reisen(lp):
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(competence_id="Y1"),
parent=ActionCompetence.objects.get(competence_id="Y1"),
competence_id=f"Y1.1",
title=f"Ich bin fähig zu Reisen eine Gesprächsführung zu machen",
learning_unit=lu,
)
PerformanceCriteriaFactory(
parent=CompetencePage.objects.get(competence_id="Y2"),
parent=ActionCompetence.objects.get(competence_id="Y2"),
competence_id=f"Y2.1",
title=f"Ich bin fähig zu Reisen eine Analyse zu machen",
learning_unit=lu,
@ -442,15 +516,29 @@ def create_test_circle_reisen(lp):
)
def create_test_competence_profile():
_course = Course.objects.get(id=COURSE_TEST_ID)
def create_test_competence_navi():
course_page = CoursePage.objects.get(course_id=COURSE_TEST_ID)
competence_profile_page = CompetenceProfilePageFactory(
competence_navi_page = CompetenceNaviPageFactory(
title="KompetenzNavi",
parent=course_page,
)
competence_certificate_list = CompetenceCertificateListFactory(
title="Kompetenznachweise",
parent=competence_navi_page,
)
competence_certificate = CompetenceCertificateFactory(
title="Kompetenznachweis 1",
parent=competence_certificate_list,
)
competence_profile_page = ActionCompetenceListPageFactory(
title="Handlungskompetenzen",
parent=competence_navi_page,
)
competences = [
{
"competence_id": "X1",
@ -480,13 +568,15 @@ def create_test_competence_profile():
]
for c in competences:
CompetencePageFactory(
ActionCompetenceFactory(
parent=competence_profile_page,
competence_id=c["competence_id"],
title=c["title"],
items=[("item", i) for i in c["items"]],
)
return competence_certificate
def create_test_media_library():
course = Course.objects.get(id=COURSE_TEST_ID)
@ -564,3 +654,41 @@ def create_test_media_library():
f"<ul><li>Mit Risiken im Strassenverkehr umgehen</li><li>Versicherungsschutz</li><li>Vertragsarten</li><li>Zusammenfassung</li></ul>"
),
)
def create_edoniq_test_assignment(
course_id=COURSE_TEST_ID, title="", competence_certificate=None
):
assignment_list_page = (
CoursePage.objects.get(course_id=course_id)
.get_children()
.exact_type(AssignmentListPage)
.first()
)
assignment = AssignmentFactory(
parent=assignment_list_page,
assignment_type="EDONIQ_TEST",
title=title,
competence_certificate=competence_certificate,
effort_required="ca. 2 Stunden",
intro_text="Edoniq Test",
performance_objectives=[],
evaluation_document_url="",
evaluation_description="",
)
assignment.evaluation_tasks = []
assignment.evaluation_tasks.append(
(
"task",
EvaluationTaskBlockFactory(
title="Maximale Punktzahl vom Edoniq Test",
max_points=24,
),
),
)
assignment.save()
return assignment

Some files were not shown because too many files have changed in this diff Show More