diff --git a/.gitignore b/.gitignore index 0daeaac9..5eb128d8 100644 --- a/.gitignore +++ b/.gitignore @@ -284,4 +284,4 @@ git-crypt-encrypted-files-check.txt /server/vbv_lernwelt/static/storybook /server/vbv_lernwelt/templates/vue/index.html /server/vbv_lernwelt/media -/client/src/gql/minifiedSchema.json +/client/src/gql/dist/minifiedSchema.json diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index 7f27808e..bc228bf0 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -77,6 +77,7 @@ js-tests: &js-tests - cd client - pwd - npm install + - npm run codegen - npm test js-linting: &js-linting diff --git a/client/codegen.ts b/client/codegen.ts index 4956f075..52694c79 100644 --- a/client/codegen.ts +++ b/client/codegen.ts @@ -11,7 +11,13 @@ const config: CodegenConfig = { "./src/gql/": { preset: "client", config: { + // avoidOptionals: true, useTypeImports: true, + scalars: { + ID: "string", + UUID: "string", + DateTime: "string", + }, }, plugins: [], }, diff --git a/client/minimizeGraphqlSchema.mjs b/client/minimizeGraphqlSchema.mjs index b4f5f7e7..d363c02a 100644 --- a/client/minimizeGraphqlSchema.mjs +++ b/client/minimizeGraphqlSchema.mjs @@ -8,4 +8,4 @@ const schema = readFileSync("./src/gql/schema.graphql", "utf-8"); const minifiedSchema = minifyIntrospectionQuery(getIntrospectedSchema(schema)); // Write the minified schema to a new file -writeFileSync("./src/gql/minifiedSchema.json", JSON.stringify(minifiedSchema)); +writeFileSync("./src/gql/dist/minifiedSchema.json", JSON.stringify(minifiedSchema)); diff --git a/client/package.json b/client/package.json index 60ed3340..69d86730 100644 --- a/client/package.json +++ b/client/package.json @@ -16,7 +16,8 @@ "storybook": "storybook dev -p 6006", "tailwind": "tailwindcss -i tailwind.css -o ../server/vbv_lernwelt/static/css/tailwind.css --watch", "test": "vitest run", - "typecheck": "npm run codegen && vue-tsc --noEmit -p tsconfig.app.json --composite false" + "typecheck": "npm run codegen && vue-tsc --noEmit -p tsconfig.app.json --composite false", + "typecheck-only": "vue-tsc --noEmit -p tsconfig.app.json --composite false" }, "dependencies": { "@headlessui/tailwindcss": "^0.1.3", diff --git a/client/src/components/dueDates/dueDatesUtils.ts b/client/src/components/dueDates/dueDatesUtils.ts index 850377f8..b2d0decd 100644 --- a/client/src/components/dueDates/dueDatesUtils.ts +++ b/client/src/components/dueDates/dueDatesUtils.ts @@ -3,7 +3,7 @@ import dayjs from "dayjs"; import LocalizedFormat from "dayjs/plugin/localizedFormat"; import i18next from "i18next"; -export const formatDueDate = (start: string, end?: string) => { +export const formatDueDate = (start: string, end?: string | null) => { dayjs.extend(LocalizedFormat); const startDayjs = dayjs(start); const startDateString = getDateString(startDayjs); diff --git a/client/src/components/feedback/feedbackSummary.vue b/client/src/components/feedback/feedbackSummary.vue deleted file mode 100644 index bccfa7bb..00000000 --- a/client/src/components/feedback/feedbackSummary.vue +++ /dev/null @@ -1,101 +0,0 @@ - - - - - {{ $t("general.feedback_other") }} - - - - - {{ $t("feedback.circleFeedback") }} - - - - Circle: {{ feedbacks.circle.title }} - {{ $t("feedback.sentByUsers", { count: feedbacks.count }) }} - - - - - {{ $t("feedback.showDetails") }} - - - - - {{ $t("feedback.noFeedbacks") }} - - - - diff --git a/client/src/components/learningPath/LearningPathDiagram.vue b/client/src/components/learningPath/LearningPathDiagram.vue index 3ba82e82..b939cab2 100644 --- a/client/src/components/learningPath/LearningPathDiagram.vue +++ b/client/src/components/learningPath/LearningPathDiagram.vue @@ -1,30 +1,38 @@ - - - - - diff --git a/client/src/composables.ts b/client/src/composables.ts index e2a4d99c..295718f3 100644 --- a/client/src/composables.ts +++ b/client/src/composables.ts @@ -1,9 +1,27 @@ +import { graphqlClient } from "@/graphql/client"; +import { COURSE_QUERY, COURSE_SESSION_DETAIL_QUERY } from "@/graphql/queries"; +import { + circleFlatChildren, + circleFlatLearningContents, + circleFlatLearningUnits, +} from "@/services/circle"; +import { useCompletionStore } from "@/stores/completion"; import { useCourseSessionsStore } from "@/stores/courseSessions"; -import type { CourseSession, CourseSessionDetail } from "@/types"; -import { useQuery } from "@urql/vue"; - -import { COURSE_SESSION_DETAIL_QUERY } from "@/graphql/queries"; import { useUserStore } from "@/stores/user"; +import type { + ActionCompetence, + Course, + CourseCompletion, + CourseCompletionStatus, + CourseSession, + CourseSessionDetail, + LearningContentWithCompletion, + LearningPathType, + LearningUnitPerformanceCriteria, + PerformanceCriteria, +} from "@/types"; +import { useQuery } from "@urql/vue"; +import orderBy from "lodash/orderBy"; import log from "loglevel"; import type { ComputedRef } from "vue"; import { computed, ref, watchEffect } from "vue"; @@ -56,19 +74,19 @@ export function useCourseSessionDetailQuery(courSessionId?: string) { function findAssignment(learningContentId: string) { return (courseSessionDetail.value?.assignments ?? []).find((a) => { - return a.learning_content.id === learningContentId; + return a.learning_content?.id === learningContentId; }); } function findEdoniqTest(learningContentId: string) { return (courseSessionDetail.value?.edoniq_tests ?? []).find((e) => { - return e.learning_content.id === learningContentId; + return e.learning_content?.id === learningContentId; }); } function findAttendanceCourse(learningContentId: string) { return (courseSessionDetail.value?.attendance_courses ?? []).find((e) => { - return e.learning_content.id === learningContentId; + return e.learning_content?.id === learningContentId; }); } @@ -123,3 +141,273 @@ export function useCourseSessionDetailQuery(courSessionId?: string) { filterCircleExperts, }; } + +export function flatCircles(learningPath: LearningPathType) { + return learningPath.topics.flatMap((t) => t.circles); +} + +export function useCourseData(courseSlug: string) { + const learningPath = ref(undefined); + const actionCompetences = ref([]); + const course = ref(undefined); + + // urql.useQuery is not meant to be used programmatically, so we use graphqlClient.query instead + const resultPromise = graphqlClient + .query(COURSE_QUERY, { slug: `${courseSlug}` }) + .toPromise(); + + resultPromise.then((result) => { + if (result.error) { + log.error(result.error); + } + + course.value = result.data?.course as Course; + actionCompetences.value = result.data?.course + ?.action_competences as ActionCompetence[]; + learningPath.value = result.data?.course?.learning_path as LearningPathType; + + // attach circle information to learning contents + if (learningPath.value) { + flatCircles(learningPath.value).forEach((circle) => { + circle.learning_sequences.forEach((ls, lsIndex) => { + const circleData = { + id: circle.id, + slug: circle.slug, + title: circle.title, + }; + return ls.learning_units.forEach((lu, luIndex) => { + lu.circle = Object.assign({}, circleData); + lu.learning_contents.forEach((lc, lcIndex) => { + lc.circle = Object.assign({}, circleData); + lc.continueUrl = ls.frontend_url || circle.frontend_url; + lc.firstInCircle = lcIndex === 0 && luIndex === 0 && lsIndex === 0; + lc.parentLearningUnit = { + id: lu.id, + slug: lu.slug, + title: lu.title, + }; + }); + + lu.performance_criteria.forEach((luPc) => { + luPc.circle = Object.assign({}, circleData); + const pc = findPerformanceCriterion(luPc.id); + if (pc) { + pc.circle = Object.assign({}, circleData); + } + }); + }); + }); + }); + } + }); + + const circles = computed(() => { + if (learningPath.value) { + return flatCircles(learningPath.value); + } + return undefined; + }); + + function findCircle(idOrSlug: string) { + return (circles.value ?? []).find((c) => { + return c.id === idOrSlug || c.slug.endsWith(idOrSlug); + }); + } + + function findPerformanceCriterion(id: string) { + return (actionCompetences.value ?? []) + .flatMap((ac) => { + return ac.performance_criteria; + }) + .find((pc) => { + return pc.id === id; + }) as PerformanceCriteria | undefined; + } + + function findLearningContent( + learningContentIdOrSlug: string, + circleIdOrSlug?: string + ) { + let filteredCircles = circles.value ?? []; + if (circleIdOrSlug) { + filteredCircles = filteredCircles.filter((c) => { + return c.id === circleIdOrSlug || c.slug.endsWith(circleIdOrSlug); + }); + } + + return filteredCircles + .flatMap((c) => { + return circleFlatLearningContents(c); + }) + .find((lc) => { + return ( + lc.id === learningContentIdOrSlug || lc.slug.endsWith(learningContentIdOrSlug) + ); + }); + } + + function findLearningUnit(learningUnitIdOrSlug: string, circleIdOrSlug?: string) { + let filteredCircles = circles.value ?? []; + if (circleIdOrSlug) { + filteredCircles = filteredCircles.filter((c) => { + return c.id === circleIdOrSlug || c.slug.endsWith(circleIdOrSlug); + }); + } + + return filteredCircles + .flatMap((c) => { + return circleFlatLearningUnits(c); + }) + .find((lu) => { + return lu.id === learningUnitIdOrSlug || lu.slug.endsWith(learningUnitIdOrSlug); + }); + } + + const flatPerformanceCriteria = computed(() => { + return (actionCompetences.value ?? []).flatMap((ac) => { + return ac.performance_criteria; + }) as PerformanceCriteria[]; + }); + + return { + resultPromise, + course, + learningPath, + actionCompetences, + circles, + findCircle, + findLearningContent, + findLearningUnit, + flatPerformanceCriteria, + }; +} + +export function useCourseDataWithCompletion( + courseSlug?: string, + userId?: string, + courseSessionId?: string +) { + if (!courseSlug) { + courseSlug = useCurrentCourseSession().value.course.slug; + } + if (!userId) { + userId = useUserStore().id; + } + if (!courseSessionId) { + courseSessionId = useCurrentCourseSession().value.id; + } + + const courseResult = useCourseData(courseSlug); + const completionStore = useCompletionStore(); + const nextLearningContent = ref(undefined); + const loaded = ref(false); + + function updateCompletionData() { + if (userId && courseSessionId) { + return completionStore.loadCourseSessionCompletionData(courseSessionId, userId); + } + return Promise.resolve([]); + } + + function _parseCompletionData(completionData: CourseCompletion[]) { + if (courseResult.circles.value) { + courseResult.circles.value.forEach((circle) => { + circleFlatChildren(circle).forEach((lc) => { + const pageIndex = completionData.findIndex((e) => { + return e.page_id === lc.id; + }); + if (pageIndex >= 0) { + lc.completion_status = completionData[pageIndex].completion_status; + } else { + lc.completion_status = "UNKNOWN"; + } + }); + }); + } + + if (courseResult.actionCompetences.value) { + courseResult.actionCompetences.value.forEach((ac) => { + ac.performance_criteria.forEach((pc) => { + const pageIndex = completionData.findIndex((e) => { + return e.page_id === pc.id; + }); + if (pageIndex >= 0) { + pc.completion_status = completionData[pageIndex].completion_status; + } else { + pc.completion_status = "UNKNOWN"; + } + }); + }); + } + + calcNextLearningContent(completionData); + } + + function calcNextLearningContent(completionData: CourseCompletion[]) { + const flatLearningContents = (courseResult.circles.value ?? []).flatMap((c) => { + return circleFlatLearningContents(c); + }); + const lastCompleted = findLastCompletedLearningContent(completionData); + if (lastCompleted) { + const lastCompletedIndex = flatLearningContents.findIndex((lc) => { + return lc.id === lastCompleted.id; + }); + if (flatLearningContents[lastCompletedIndex + 1]) { + nextLearningContent.value = flatLearningContents[lastCompletedIndex + 1]; + } else { + nextLearningContent.value = undefined; + } + } else { + nextLearningContent.value = flatLearningContents[0]; + } + } + + function findLastCompletedLearningContent(completionData: CourseCompletion[]) { + const latestCompletion = orderBy(completionData ?? [], ["updated_at"], "desc").find( + (c: CourseCompletion) => { + return ( + c.completion_status === "SUCCESS" && + c.page_type.startsWith("learnpath.LearningContent") + ); + } + ); + if (latestCompletion) { + return courseResult.findLearningContent(latestCompletion.page_id); + } + } + + async function markCompletion( + page: LearningContentWithCompletion | LearningUnitPerformanceCriteria, + completion_status: CourseCompletionStatus = "SUCCESS" + ) { + if (userId && courseSessionId) { + page.completion_status = completion_status; + const completionData = await completionStore.markPage( + page, + userId, + courseSessionId + ); + _parseCompletionData(completionData); + } + } + + async function _start() { + return Promise.all([courseResult.resultPromise, updateCompletionData()]).then( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ([_queryResults, completionData]) => { + _parseCompletionData(completionData); + loaded.value = true; + } + ); + } + + const resultPromise = _start(); + + return { + ...courseResult, + loaded, + resultPromise, + markCompletion, + nextLearningContent, + }; +} diff --git a/client/src/constants.ts b/client/src/constants.ts index 65dee1e9..84aaefc3 100644 --- a/client/src/constants.ts +++ b/client/src/constants.ts @@ -1,9 +1,3 @@ -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)]"; diff --git a/client/src/gql/dist/.gitkeep b/client/src/gql/dist/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/client/src/gql/gql.ts b/client/src/gql/gql.ts index d971bb1d..554937b8 100644 --- a/client/src/gql/gql.ts +++ b/client/src/gql/gql.ts @@ -18,9 +18,9 @@ const documents = { "\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 needs_expert_evaluation\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_points\n evaluation_max_points\n evaluation_passed\n edoniq_extended_time_flag\n completion_data\n task_completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument, - "\n query courseQuery($courseId: ID!) {\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 evaluation_max_points\n evaluation_passed\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, + "\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 evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n": types.CompetenceCertificateQueryDocument, "\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n": types.CourseSessionDetailDocument, + "\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.CourseQueryDocument, "\n mutation SendFeedbackMutation(\n $courseSessionId: ID!\n $learningContentId: ID!\n $data: GenericScalar!\n $submitted: Boolean\n ) {\n send_feedback(\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n data: $data\n submitted: $submitted\n ) {\n feedback_response {\n id\n data\n submitted\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument, }; @@ -61,15 +61,15 @@ export function graphql(source: "\n query assignmentCompletionQuery(\n $assi /** * 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: ID!) {\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: ID!) {\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 evaluation_max_points\n evaluation_passed\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 evaluation_max_points\n evaluation_passed\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: "\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 evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\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 evaluation_max_points\n evaluation_passed\n }\n learning_content {\n ...CoursePageFields\n circle {\n id\n title\n slug\n }\n }\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query courseSessionDetail($courseSessionId: ID!) {\n course_session(id: $courseSessionId) {\n id\n title\n course {\n id\n title\n slug\n }\n users {\n id\n user_id\n first_name\n last_name\n email\n avatar_url\n role\n circles {\n id\n title\n slug\n }\n }\n attendance_courses {\n id\n location\n trainer\n due_date {\n id\n start\n end\n }\n learning_content_id\n learning_content {\n id\n title\n circle {\n id\n title\n slug\n }\n }\n }\n assignments {\n id\n submission_deadline {\n id\n start\n }\n evaluation_deadline {\n id\n start\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n edoniq_tests {\n id\n deadline {\n id\n start\n end\n }\n learning_content {\n id\n title\n content_assignment {\n id\n title\n assignment_type\n }\n }\n }\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query courseQuery($slug: String!) {\n course(slug: $slug) {\n id\n title\n slug\n category_name\n action_competences {\n competence_id\n ...CoursePageFields\n performance_criteria {\n competence_id\n learning_unit {\n id\n slug\n evaluate_url\n }\n ...CoursePageFields\n }\n }\n learning_path {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n description\n goals\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n performance_criteria {\n ...CoursePageFields\n }\n learning_contents {\n can_user_self_toggle_course_completion\n content_url\n minutes\n description\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentEdoniqTestObjectType {\n checkbox_text\n has_extended_time_test\n content_assignment {\n id\n }\n competence_certificate {\n ...CoursePageFields\n }\n }\n ... on LearningContentRichTextObjectType {\n text\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/client/src/gql/graphql.ts b/client/src/gql/graphql.ts index 9a81624b..d2ac2e1c 100644 --- a/client/src/gql/graphql.ts +++ b/client/src/gql/graphql.ts @@ -25,7 +25,7 @@ export type Scalars = { * value as specified by * [iso8601](https://en.wikipedia.org/wiki/ISO_8601). */ - DateTime: { input: any; output: any; } + DateTime: { input: string; output: string; } /** * The `GenericScalar` scalar type represents a generic * GraphQL scalar value that could be: @@ -44,7 +44,21 @@ export type Scalars = { * Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects * in fields, resolvers and input. */ - UUID: { input: any; output: any; } + UUID: { input: string; output: string; } +}; + +export type ActionCompetenceObjectType = CoursePageInterface & { + __typename?: 'ActionCompetenceObjectType'; + competence_id: Scalars['String']['output']; + content_type: Scalars['String']['output']; + course?: Maybe; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; + performance_criteria: Array; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; /** An enumeration. */ @@ -80,7 +94,7 @@ export type AssignmentCompletionObjectType = { __typename?: 'AssignmentCompletionObjectType'; additional_json_data: Scalars['JSONString']['output']; assignment: AssignmentObjectType; - assignment_user: UserType; + assignment_user: UserObjectType; completion_data?: Maybe; completion_status: AssignmentAssignmentCompletionCompletionStatusChoices; course_session: CourseSessionObjectType; @@ -90,7 +104,7 @@ export type AssignmentCompletionObjectType = { evaluation_passed?: Maybe; evaluation_points?: Maybe; evaluation_submitted_at?: Maybe; - evaluation_user?: Maybe; + evaluation_user?: Maybe; id: Scalars['UUID']['output']; learning_content_page_id?: Maybe; submitted_at?: Maybe; @@ -108,10 +122,9 @@ export type AssignmentCompletionStatus = export type AssignmentObjectType = CoursePageInterface & { __typename?: 'AssignmentObjectType'; assignment_type: AssignmentAssignmentAssignmentTypeChoices; - circle?: Maybe; competence_certificate?: Maybe; completion?: Maybe; - content_type?: Maybe; + content_type: Scalars['String']['output']; course?: Maybe; /** Zeitaufwand als Text */ effort_required: Scalars['String']['output']; @@ -120,20 +133,20 @@ export type AssignmentObjectType = CoursePageInterface & { /** URL zum Beurteilungsinstrument */ evaluation_document_url: Scalars['String']['output']; evaluation_tasks?: Maybe; - frontend_url?: Maybe; - id?: Maybe; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; /** Erläuterung der Ausgangslage */ intro_text: Scalars['String']['output']; learning_content?: Maybe; - live?: Maybe; + live: Scalars['Boolean']['output']; max_points?: Maybe; /** Muss der Auftrag durch eine Expertin oder einen Experten beurteilt werden? */ needs_expert_evaluation: Scalars['Boolean']['output']; performance_objectives?: Maybe; - slug?: Maybe; + slug: Scalars['String']['output']; tasks?: Maybe; - title?: Maybe; - translation_key?: Maybe; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; @@ -167,80 +180,52 @@ export type AttendanceUserStatus = | 'ABSENT' | 'PRESENT'; -export type CircleDocumentObjectType = { - __typename?: 'CircleDocumentObjectType'; - course_session: CourseSessionObjectType; - file_name?: Maybe; - id: Scalars['UUID']['output']; - learning_sequence: LearningSequenceObjectType; - name: Scalars['String']['output']; - url?: Maybe; +export type CircleLightObjectType = { + __typename?: 'CircleLightObjectType'; + id: Scalars['ID']['output']; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; }; export type CircleObjectType = CoursePageInterface & { __typename?: 'CircleObjectType'; - circle?: Maybe; - content_type?: Maybe; + content_type: Scalars['String']['output']; course?: Maybe; description: Scalars['String']['output']; - frontend_url?: Maybe; + frontend_url: Scalars['String']['output']; goals: Scalars['String']['output']; - id?: Maybe; - learning_sequences?: Maybe>>; - live?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + id: Scalars['ID']['output']; + learning_sequences: Array; + live: Scalars['Boolean']['output']; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; export type CompetenceCertificateListObjectType = CoursePageInterface & { __typename?: 'CompetenceCertificateListObjectType'; - circle?: Maybe; - competence_certificates?: Maybe>>; - content_type?: Maybe; + competence_certificates: Array; + content_type: Scalars['String']['output']; course?: Maybe; - depth: Scalars['Int']['output']; - draft_title: Scalars['String']['output']; - expire_at?: Maybe; - expired: Scalars['Boolean']['output']; - first_published_at?: Maybe; - frontend_url?: Maybe; - go_live_at?: Maybe; - has_unpublished_changes: Scalars['Boolean']['output']; - id?: Maybe; - last_published_at?: Maybe; - latest_revision_created_at?: Maybe; - live?: Maybe; - locked: Scalars['Boolean']['output']; - locked_at?: Maybe; - locked_by?: Maybe; - numchild: Scalars['Int']['output']; - owner?: Maybe; - 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; - title?: Maybe; - translation_key?: Maybe; - url_path: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; export type CompetenceCertificateObjectType = CoursePageInterface & { __typename?: 'CompetenceCertificateObjectType'; - assignments?: Maybe>>; - circle?: Maybe; - content_type?: Maybe; + assignments: Array; + content_type: Scalars['String']['output']; course?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; /** An enumeration. */ @@ -252,34 +237,43 @@ export type CoreUserLanguageChoices = /** Italiano */ | 'IT'; +/** An enumeration. */ +export type CourseCourseSessionUserRoleChoices = + /** Experte/Trainer */ + | 'EXPERT' + /** Teilnehmer */ + | 'MEMBER' + /** Lernbegleitung */ + | 'TUTOR'; + export type CourseObjectType = { __typename?: 'CourseObjectType'; + action_competences: Array; category_name: Scalars['String']['output']; id: Scalars['ID']['output']; - learning_path?: Maybe; + learning_path: LearningPathObjectType; slug: Scalars['String']['output']; title: Scalars['String']['output']; }; export type CoursePageInterface = { - circle?: Maybe; - content_type?: Maybe; + content_type: Scalars['String']['output']; course?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; export type CourseSessionAssignmentObjectType = { __typename?: 'CourseSessionAssignmentObjectType'; - course_session_id?: Maybe; + course_session_id: Scalars['ID']['output']; evaluation_deadline?: Maybe; id: Scalars['ID']['output']; - learning_content?: Maybe; - learning_content_id?: Maybe; + learning_content: LearningContentAssignmentObjectType; + learning_content_id: Scalars['ID']['output']; submission_deadline?: Maybe; }; @@ -289,7 +283,7 @@ export type CourseSessionAttendanceCourseObjectType = { course_session_id?: Maybe; due_date?: Maybe; id: Scalars['ID']['output']; - learning_content?: Maybe; + learning_content: LearningContentAttendanceCourseObjectType; learning_content_id?: Maybe; location: Scalars['String']['output']; trainer: Scalars['String']['output']; @@ -297,46 +291,45 @@ export type CourseSessionAttendanceCourseObjectType = { export type CourseSessionEdoniqTestObjectType = { __typename?: 'CourseSessionEdoniqTestObjectType'; - course_session_id?: Maybe; + course_session_id: Scalars['ID']['output']; deadline?: Maybe; id: Scalars['ID']['output']; - learning_content?: Maybe; - learning_content_id?: Maybe; + learning_content: LearningContentEdoniqTestObjectType; + learning_content_id: Scalars['ID']['output']; }; export type CourseSessionObjectType = { __typename?: 'CourseSessionObjectType'; - assignments?: Maybe>>; - attendance_courses?: Maybe>>; + assignments: Array; + attendance_courses: Array; course: CourseObjectType; created_at: Scalars['DateTime']['output']; - documents?: Maybe>>; - edoniq_tests?: Maybe>>; + edoniq_tests: Array; end_date?: Maybe; id: Scalars['ID']['output']; start_date?: Maybe; title: Scalars['String']['output']; updated_at: Scalars['DateTime']['output']; - users?: Maybe>>; + users: Array; }; export type CourseSessionUserExpertCircleType = { __typename?: 'CourseSessionUserExpertCircleType'; - id?: Maybe; - slug?: Maybe; - title?: Maybe; + id: Scalars['ID']['output']; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; }; export type CourseSessionUserObjectsType = { __typename?: 'CourseSessionUserObjectsType'; - avatar_url?: Maybe; - circles?: Maybe>>; - email?: Maybe; - first_name?: Maybe; + avatar_url: Scalars['String']['output']; + circles: Array; + email: Scalars['String']['output']; + first_name: Scalars['String']['output']; id: Scalars['UUID']['output']; - last_name?: Maybe; - role?: Maybe; - user_id?: Maybe; + last_name: Scalars['String']['output']; + role: CourseCourseSessionUserRoleChoices; + user_id: Scalars['UUID']['output']; }; export type DueDateObjectType = { @@ -374,247 +367,241 @@ export type FeedbackResponseObjectType = { submitted: Scalars['Boolean']['output']; }; -export type LearningContentAssignmentObjectType = LearningContentInterface & { +export type LearningContentAssignmentObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentAssignmentObjectType'; assignment_type: LearnpathLearningContentAssignmentAssignmentTypeChoices; - circle?: Maybe; - content?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + circle?: Maybe; + competence_certificate?: Maybe; content_assignment: AssignmentObjectType; - content_type?: Maybe; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; -export type LearningContentAttendanceCourseObjectType = LearningContentInterface & { +export type LearningContentAttendanceCourseObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentAttendanceCourseObjectType'; - circle?: Maybe; - content?: Maybe; - content_type?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + circle?: Maybe; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; -export type LearningContentDocumentListObjectType = LearningContentInterface & { +export type LearningContentDocumentListObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentDocumentListObjectType'; - circle?: Maybe; - content?: Maybe; - content_type?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + circle?: Maybe; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; -export type LearningContentEdoniqTestObjectType = LearningContentInterface & { +export type LearningContentEdoniqTestObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentEdoniqTestObjectType'; - circle?: Maybe; - content?: Maybe; - content_assignment?: Maybe; - content_type?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + checkbox_text: Scalars['String']['output']; + circle?: Maybe; + competence_certificate?: Maybe; + content_assignment: AssignmentObjectType; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + has_extended_time_test: Scalars['Boolean']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; -export type LearningContentFeedbackObjectType = LearningContentInterface & { +export type LearningContentFeedbackObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentFeedbackObjectType'; - circle?: Maybe; - content?: Maybe; - content_type?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + circle?: Maybe; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; export type LearningContentInterface = { - circle?: Maybe; - content?: Maybe; - content_type?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + circle?: Maybe; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; -export type LearningContentLearningModuleObjectType = LearningContentInterface & { +export type LearningContentLearningModuleObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentLearningModuleObjectType'; - circle?: Maybe; - content?: Maybe; - content_type?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + circle?: Maybe; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; -export type LearningContentMediaLibraryObjectType = LearningContentInterface & { +export type LearningContentMediaLibraryObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentMediaLibraryObjectType'; - circle?: Maybe; - content?: Maybe; - content_type?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + circle?: Maybe; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; -export type LearningContentPlaceholderObjectType = LearningContentInterface & { +export type LearningContentPlaceholderObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentPlaceholderObjectType'; - circle?: Maybe; - content?: Maybe; - content_type?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + circle?: Maybe; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; -export type LearningContentRichTextObjectType = LearningContentInterface & { +export type LearningContentRichTextObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentRichTextObjectType'; - circle?: Maybe; - content?: Maybe; - content_type?: Maybe; + can_user_self_toggle_course_completion: Scalars['Boolean']['output']; + circle?: Maybe; + content_type: Scalars['String']['output']; + content_url: Scalars['String']['output']; course?: Maybe; - description?: Maybe; - frontend_url?: Maybe; - id?: Maybe; - live?: Maybe; + description: Scalars['String']['output']; + frontend_url: Scalars['String']['output']; + id: Scalars['ID']['output']; + live: Scalars['Boolean']['output']; minutes?: Maybe; - slug?: Maybe; - title?: Maybe; - translation_key?: Maybe; + slug: Scalars['String']['output']; + text: Scalars['String']['output']; + title: Scalars['String']['output']; + translation_key: Scalars['String']['output']; }; -export type LearningContentVideoObjectType = LearningContentInterface & { +export type LearningContentVideoObjectType = CoursePageInterface & LearningContentInterface & { __typename?: 'LearningContentVideoObjectType'; - circle?: Maybe; - content?: Maybe; - content_type?: Maybe
{{ $t("feedback.noFeedbacks") }}