From a15af2bf8629245c93db3fa6fe5aa4354350ff05 Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Fri, 12 May 2023 11:23:17 +0200 Subject: [PATCH] VBV-350: Refactor LearningContent to individual wagtail pages --- client/src/components/FeedbackForm.vue | 6 +- .../learningPath/LearningContentTypeBadge.vue | 2 +- .../circlePage/LearningSequence.vue | 6 +- .../LearningContentPage.vue | 16 +- ...gContent.vue => LearningContentParent.vue} | 52 +- .../assignment/AssignmentView.vue | 21 +- .../blocks/AssignmentBlock.vue | 26 +- .../blocks/AttendanceDayBlock.vue | 19 +- .../blocks/DescriptionBlock.vue | 20 - .../blocks/DescriptionTextBlock.vue | 23 - .../blocks/FeedbackBlock.vue | 9 +- .../blocks/IframeBlock.vue | 32 +- .../blocks/MediaLibraryBlock.vue | 41 +- .../blocks/PlaceholderBlock.vue | 25 +- .../blocks/RichTextBlock.vue | 15 + .../learningContentPage/blocks/VideoBlock.vue | 20 +- .../layouts/LearningContentMultiLayout.vue | 2 +- .../layouts/LearningContentSimpleLayout.vue | 2 +- .../selfEvaluationPage/SelfEvaluation.vue | 2 +- client/src/services/__tests__/circle.spec.ts | 4 +- .../services/__tests__/learningPath.spec.ts | 6 +- .../__tests__/learning_path_json.json | 896 +++++++++-------- client/src/services/assignmentService.ts | 12 +- client/src/services/circle.ts | 24 +- client/src/services/learningPath.ts | 6 +- client/src/stores/circle.ts | 10 +- client/src/types.ts | 141 ++- client/src/utils/typeMaps.ts | 38 +- .../assignment/migrations/0001_initial.py | 147 +-- ...nmentcompletionauditlog_assignment_user.py | 28 + .../assignment/migrations/0003_initial.py | 79 ++ .../competence/migrations/0001_initial.py | 4 +- .../0002_performancecriteria_learning_unit.py | 2 +- .../core/migrations/0001_initial.py | 46 +- .../core/migrations/0002_user_model.py | 33 - .../migrations/0003_alter_user_managers.py | 16 - .../core/migrations/0004_user_sso_id.py | 23 - .../core/migrations/0005_create_users.py | 25 - .../0006_user_additional_json_data.py | 17 - .../course/creators/test_course.py | 117 +-- .../commands/create_default_courses.py | 10 +- .../management/commands/create_uk_course.py | 101 +- .../course/migrations/0001_initial.py | 12 +- .../course/migrations/0002_initial.py | 4 +- .../migrations/0003_auto_20230404_0837.py | 23 - ...4_coursesession_assignment_details_list.py | 18 - ...005_alter_coursesession_attendance_days.py | 19 - ...006_alter_coursesession_attendance_days.py | 19 - .../course/tests/test_completion_api.py | 6 +- .../feedback/migrations/0001_initial.py | 2 +- .../feedback/migrations/0002_initial.py | 6 +- .../files/migrations/0001_initial.py | 3 +- .../learnpath/create_vv_learning_path.py | 917 ------------------ .../learnpath/create_vv_new_learning_path.py | 403 +++----- .../learnpath/migrations/0001_initial.py | 324 ++++--- .../0002_alter_learningcontent_contents.py | 137 --- server/vbv_lernwelt/learnpath/models.py | 133 ++- .../learnpath/models_learning_unit_content.py | 106 -- .../tests/learning_path_factories.py | 203 ++-- .../learnpath/tests/test_models.py | 8 +- .../media_library/content_blocks.py | 6 +- .../media_library/migrations/0001_initial.py | 42 +- .../notify/migrations/0001_initial.py | 3 +- 63 files changed, 1461 insertions(+), 3057 deletions(-) rename client/src/pages/learningPath/learningContentPage/{LearningContent.vue => LearningContentParent.vue} (64%) delete mode 100644 client/src/pages/learningPath/learningContentPage/blocks/DescriptionBlock.vue delete mode 100644 client/src/pages/learningPath/learningContentPage/blocks/DescriptionTextBlock.vue create mode 100644 client/src/pages/learningPath/learningContentPage/blocks/RichTextBlock.vue create mode 100644 server/vbv_lernwelt/assignment/migrations/0002_assignmentcompletionauditlog_assignment_user.py create mode 100644 server/vbv_lernwelt/assignment/migrations/0003_initial.py delete mode 100644 server/vbv_lernwelt/core/migrations/0002_user_model.py delete mode 100644 server/vbv_lernwelt/core/migrations/0003_alter_user_managers.py delete mode 100644 server/vbv_lernwelt/core/migrations/0004_user_sso_id.py delete mode 100644 server/vbv_lernwelt/core/migrations/0005_create_users.py delete mode 100644 server/vbv_lernwelt/core/migrations/0006_user_additional_json_data.py delete mode 100644 server/vbv_lernwelt/course/migrations/0003_auto_20230404_0837.py delete mode 100644 server/vbv_lernwelt/course/migrations/0004_coursesession_assignment_details_list.py delete mode 100644 server/vbv_lernwelt/course/migrations/0005_alter_coursesession_attendance_days.py delete mode 100644 server/vbv_lernwelt/course/migrations/0006_alter_coursesession_attendance_days.py delete mode 100644 server/vbv_lernwelt/learnpath/create_vv_learning_path.py delete mode 100644 server/vbv_lernwelt/learnpath/migrations/0002_alter_learningcontent_contents.py delete mode 100644 server/vbv_lernwelt/learnpath/models_learning_unit_content.py diff --git a/client/src/components/FeedbackForm.vue b/client/src/components/FeedbackForm.vue index facbb4dd..2673badd 100644 --- a/client/src/components/FeedbackForm.vue +++ b/client/src/components/FeedbackForm.vue @@ -12,14 +12,14 @@ import { import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue"; import { useCircleStore } from "@/stores/circle"; import { useCourseSessionsStore } from "@/stores/courseSessions"; -import type { LearningContent } from "@/types"; +import type { LearningContentFeedback } from "@/types"; import { useMutation } from "@urql/vue"; import { useRouteQuery } from "@vueuse/router"; import log from "loglevel"; import { computed, onMounted, reactive, ref } from "vue"; import { useI18n } from "vue-i18n"; -const props = defineProps<{ page: LearningContent }>(); +const props = defineProps<{ page: LearningContentFeedback }>(); const courseSessionsStore = useCourseSessionsStore(); const circleStore = useCircleStore(); const { t } = useI18n(); @@ -132,7 +132,7 @@ const sendFeedback = () => {
(), { const circleStore = useCircleStore(); -function toggleCompleted(learningContent: LearningContent) { +function toggleCompleted(learningContent: LearningContentInterface) { let completionStatus: CourseCompletionStatus = "success"; if (learningContent.completion_status === "success") { completionStatus = "fail"; @@ -173,7 +173,7 @@ const learningSequenceBorderClass = computed(() => {
diff --git a/client/src/pages/learningPath/learningContentPage/LearningContentPage.vue b/client/src/pages/learningPath/learningContentPage/LearningContentPage.vue index 9cedba38..bc3a36f0 100644 --- a/client/src/pages/learningPath/learningContentPage/LearningContentPage.vue +++ b/client/src/pages/learningPath/learningContentPage/LearningContentPage.vue @@ -1,9 +1,10 @@ diff --git a/client/src/pages/learningPath/learningContentPage/LearningContent.vue b/client/src/pages/learningPath/learningContentPage/LearningContentParent.vue similarity index 64% rename from client/src/pages/learningPath/learningContentPage/LearningContent.vue rename to client/src/pages/learningPath/learningContentPage/LearningContentParent.vue index c54a1523..ad4e91ba 100644 --- a/client/src/pages/learningPath/learningContentPage/LearningContent.vue +++ b/client/src/pages/learningPath/learningContentPage/LearningContentParent.vue @@ -2,19 +2,17 @@ import LearningContentContainer from "@/pages/learningPath/learningContentPage/LearningContentContainer.vue"; import { useCircleStore } from "@/stores/circle"; import type { LearningContent, LearningContentType } from "@/types"; +import eventBus from "@/utils/eventBus"; import log from "loglevel"; import type { Component } from "vue"; import { computed, onUnmounted } from "vue"; - -import AssignmentBlock from "@/pages/learningPath/learningContentPage/blocks/AssignmentBlock.vue"; -import AttendanceDayBlock from "@/pages/learningPath/learningContentPage/blocks/AttendanceDayBlock.vue"; -import eventBus from "@/utils/eventBus"; -import DescriptionBlock from "./blocks/DescriptionBlock.vue"; -import DescriptionTextBlock from "./blocks/DescriptionTextBlock.vue"; +import AssignmentBlock from "./blocks/AssignmentBlock.vue"; +import AttendanceDayBlock from "./blocks/AttendanceDayBlock.vue"; import FeedbackBlock from "./blocks/FeedbackBlock.vue"; import IframeBlock from "./blocks/IframeBlock.vue"; import MediaLibraryBlock from "./blocks/MediaLibraryBlock.vue"; import PlaceholderBlock from "./blocks/PlaceholderBlock.vue"; +import DescriptionBlock from "./blocks/RichTextBlock.vue"; import VideoBlock from "./blocks/VideoBlock.vue"; log.debug("LearningContent.vue setup"); @@ -25,37 +23,22 @@ const props = defineProps<{ learningContent: LearningContent; }>(); -const block = computed(() => { - if (props.learningContent?.contents?.length) { - return props.learningContent.contents[0]; - } - - return undefined; -}); - // can't use the type as component name, as some are reserved HTML components, e.g. video const COMPONENTS: Record = { - placeholder: PlaceholderBlock, - video: VideoBlock, - assignment: AssignmentBlock, - resource: DescriptionTextBlock, - exercise: IframeBlock, - test: IframeBlock, - learningmodule: IframeBlock, - feedback: FeedbackBlock, - book: DescriptionBlock, - document: DescriptionBlock, - media_library: MediaLibraryBlock, - online_training: DescriptionBlock, - attendance_day: AttendanceDayBlock, + "learnpath.LearningContentAssignment": AssignmentBlock, + "learnpath.LearningContentAttendanceDay": AttendanceDayBlock, + "learnpath.LearningContentFeedback": FeedbackBlock, + "learnpath.LearningContentLearningModule": IframeBlock, + "learnpath.LearningContentMediaLibrary": MediaLibraryBlock, + "learnpath.LearningContentPlaceholder": PlaceholderBlock, + "learnpath.LearningContentRichText": DescriptionBlock, + "learnpath.LearningContentTest": IframeBlock, + "learnpath.LearningContentVideo": VideoBlock, }; const DEFAULT_BLOCK = DescriptionBlock; const component = computed(() => { - if (block.value) { - return COMPONENTS[block.value.type] || DEFAULT_BLOCK; - } - return DEFAULT_BLOCK; + return COMPONENTS[props.learningContent.type] || DEFAULT_BLOCK; }); function handleFinishedLearningContent() { @@ -71,15 +54,10 @@ onUnmounted(() => { diff --git a/client/src/pages/learningPath/learningContentPage/assignment/AssignmentView.vue b/client/src/pages/learningPath/learningContentPage/assignment/AssignmentView.vue index f977078a..543e2d31 100644 --- a/client/src/pages/learningPath/learningContentPage/assignment/AssignmentView.vue +++ b/client/src/pages/learningPath/learningContentPage/assignment/AssignmentView.vue @@ -12,7 +12,7 @@ import type { AssignmentTask, CourseSessionAssignmentDetails, CourseSessionUser, - LearningContent, + LearningContentAssignment, } from "@/types"; import { useRouteQuery } from "@vueuse/router"; import dayjs from "dayjs"; @@ -36,8 +36,7 @@ const state: State = reactive({ }); const props = defineProps<{ - assignmentId: number; - learningContent: LearningContent; + learningContent: LearningContentAssignment; }>(); // 0 = introduction, 1 - n = tasks, n+1 = submission @@ -49,17 +48,23 @@ const completionStatus = computed(() => { }); onMounted(async () => { - log.debug("AssignmentView mounted", props.assignmentId, props.learningContent); + log.debug( + "AssignmentView mounted", + props.learningContent.content_assignment_id, + props.learningContent + ); const courseSessionsStore = useCourseSessionsStore(); try { - state.assignment = await assignmentStore.loadAssignment(props.assignmentId); + state.assignment = await assignmentStore.loadAssignment( + props.learningContent.content_assignment_id + ); state.courseSessionAssignmentDetails = courseSessionsStore.findAssignmentDetails( props.learningContent.id ); await assignmentStore.loadAssignmentCompletion( - props.assignmentId, + props.learningContent.content_assignment_id, courseSessionId.value ); @@ -140,7 +145,7 @@ const assignmentUser = computed(() => { :current-step="stepIndex" :subtitle="state.assignment?.title ?? ''" :title="getTitle()" - learning-content-type="assignment" + :learning-content-type="props.learningContent.type" :steps-count="numPages" :show-next-button="showNextButton && stepIndex !== 0" :show-exit-button="showExitButton" @@ -164,7 +169,7 @@ const assignmentUser = computed(() => { +import AssignmentView from "@/pages/learningPath/learningContentPage/assignment/AssignmentView.vue"; +import type { LearningContentAssignment } from "@/types"; + +const props = defineProps<{ + content: LearningContentAssignment; +}>(); + + - - diff --git a/client/src/pages/learningPath/learningContentPage/blocks/AttendanceDayBlock.vue b/client/src/pages/learningPath/learningContentPage/blocks/AttendanceDayBlock.vue index fd807063..e96d82fc 100644 --- a/client/src/pages/learningPath/learningContentPage/blocks/AttendanceDayBlock.vue +++ b/client/src/pages/learningPath/learningContentPage/blocks/AttendanceDayBlock.vue @@ -1,22 +1,17 @@ @@ -24,13 +19,13 @@ const attendanceDay = computed(() => {