Refactor CirclePage
This commit is contained in:
parent
2eddb93be5
commit
627e4f6873
|
|
@ -1,9 +1,8 @@
|
||||||
|
import { COURSE_SESSION_DETAIL_QUERY, LEARNING_PATH_QUERY } from "@/graphql/queries";
|
||||||
import { useCourseSessionsStore } from "@/stores/courseSessions";
|
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 { useUserStore } from "@/stores/user";
|
||||||
|
import type { CourseSession, CourseSessionDetail, LearningPathType } from "@/types";
|
||||||
|
import { useQuery } from "@urql/vue";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import type { ComputedRef } from "vue";
|
import type { ComputedRef } from "vue";
|
||||||
import { computed, ref, watchEffect } from "vue";
|
import { computed, ref, watchEffect } from "vue";
|
||||||
|
|
@ -123,3 +122,31 @@ export function useCourseSessionDetailQuery(courSessionId?: string) {
|
||||||
filterCircleExperts,
|
filterCircleExperts,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useLearningPathQuery(courseSlug: string) {
|
||||||
|
const queryResult = useQuery({
|
||||||
|
query: LEARNING_PATH_QUERY,
|
||||||
|
variables: {
|
||||||
|
slug: `${courseSlug}-lp`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const learningPath = computed(() => {
|
||||||
|
return queryResult.data.value?.learning_path as LearningPathType | undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
const circles = computed(() => {
|
||||||
|
if (learningPath.value) {
|
||||||
|
return learningPath.value.topics.flatMap((t) => t.circles);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
function findCircle(slug: string) {
|
||||||
|
return (circles.value ?? []).find((c) => {
|
||||||
|
return c.slug.endsWith(slug);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...queryResult, learningPath, circles, findCircle };
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ const 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 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 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 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 ...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 ...CoursePageFields\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 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 learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.LearningPathQueryDocument,
|
"\n query learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\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 competence_certificate {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n }\n }\n }\n": types.LearningPathQueryDocument,
|
||||||
"\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,
|
"\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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ export function graphql(source: "\n query courseSessionDetail($courseSessionId:
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* 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 learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\n ...CoursePageFields\n ... on LearningContentAssignmentObjectType {\n assignment_type\n content_assignment {\n id\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"];
|
export function graphql(source: "\n query learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\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 competence_certificate {\n ...CoursePageFields\n }\n }\n }\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query learningPathQuery($slug: String!) {\n learning_path(slug: $slug) {\n ...CoursePageFields\n topics {\n is_visible\n ...CoursePageFields\n circles {\n ...CoursePageFields\n learning_sequences {\n icon\n ...CoursePageFields\n learning_units {\n evaluate_url\n ...CoursePageFields\n learning_contents {\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 competence_certificate {\n ...CoursePageFields\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.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -22,46 +22,15 @@ type Query {
|
||||||
|
|
||||||
type LearningPathObjectType implements CoursePageInterface {
|
type LearningPathObjectType implements CoursePageInterface {
|
||||||
id: ID!
|
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: UserObjectType
|
|
||||||
title: String!
|
title: String!
|
||||||
draft_title: String!
|
|
||||||
slug: String!
|
slug: String!
|
||||||
content_type: String!
|
content_type: String!
|
||||||
url_path: String!
|
live: Boolean!
|
||||||
owner: UserObjectType
|
translation_key: String!
|
||||||
|
|
||||||
"""
|
|
||||||
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!
|
frontend_url: String!
|
||||||
circle: CircleObjectType
|
circle: CircleObjectType
|
||||||
course: CourseObjectType
|
course: CourseObjectType
|
||||||
topics: [TopicObjectType]
|
topics: [TopicObjectType!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CoursePageInterface {
|
interface CoursePageInterface {
|
||||||
|
|
@ -88,7 +57,7 @@ type CircleObjectType implements CoursePageInterface {
|
||||||
frontend_url: String!
|
frontend_url: String!
|
||||||
circle: CircleObjectType
|
circle: CircleObjectType
|
||||||
course: CourseObjectType
|
course: CourseObjectType
|
||||||
learning_sequences: [LearningSequenceObjectType]
|
learning_sequences: [LearningSequenceObjectType!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type CourseObjectType {
|
type CourseObjectType {
|
||||||
|
|
@ -109,10 +78,11 @@ type LearningSequenceObjectType implements CoursePageInterface {
|
||||||
frontend_url: String!
|
frontend_url: String!
|
||||||
circle: CircleObjectType
|
circle: CircleObjectType
|
||||||
course: CourseObjectType
|
course: CourseObjectType
|
||||||
learning_units: [LearningUnitObjectType]
|
learning_units: [LearningUnitObjectType!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type LearningUnitObjectType implements CoursePageInterface {
|
type LearningUnitObjectType implements CoursePageInterface {
|
||||||
|
title_hidden: Boolean!
|
||||||
id: ID!
|
id: ID!
|
||||||
title: String!
|
title: String!
|
||||||
slug: String!
|
slug: String!
|
||||||
|
|
@ -141,44 +111,6 @@ interface LearningContentInterface {
|
||||||
content: String
|
content: String
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
|
||||||
The `DateTime` scalar type represents a DateTime
|
|
||||||
value as specified by
|
|
||||||
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
|
|
||||||
"""
|
|
||||||
scalar DateTime
|
|
||||||
|
|
||||||
type UserObjectType {
|
|
||||||
"""
|
|
||||||
Erforderlich. 150 Zeichen oder weniger. Nur Buchstaben, Ziffern und @/./+/-/_.
|
|
||||||
"""
|
|
||||||
username: String!
|
|
||||||
first_name: String!
|
|
||||||
last_name: String!
|
|
||||||
id: UUID!
|
|
||||||
avatar_url: String!
|
|
||||||
email: String!
|
|
||||||
language: CoreUserLanguageChoices!
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects
|
|
||||||
in fields, resolvers and input.
|
|
||||||
"""
|
|
||||||
scalar UUID
|
|
||||||
|
|
||||||
"""An enumeration."""
|
|
||||||
enum CoreUserLanguageChoices {
|
|
||||||
"""Deutsch"""
|
|
||||||
DE
|
|
||||||
|
|
||||||
"""Français"""
|
|
||||||
FR
|
|
||||||
|
|
||||||
"""Italiano"""
|
|
||||||
IT
|
|
||||||
}
|
|
||||||
|
|
||||||
type TopicObjectType implements CoursePageInterface {
|
type TopicObjectType implements CoursePageInterface {
|
||||||
is_visible: Boolean!
|
is_visible: Boolean!
|
||||||
id: ID!
|
id: ID!
|
||||||
|
|
@ -190,7 +122,7 @@ type TopicObjectType implements CoursePageInterface {
|
||||||
frontend_url: String!
|
frontend_url: String!
|
||||||
circle: CircleObjectType
|
circle: CircleObjectType
|
||||||
course: CourseObjectType
|
course: CourseObjectType
|
||||||
circles: [CircleObjectType]
|
circles: [CircleObjectType!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type LearningContentMediaLibraryObjectType implements CoursePageInterface & LearningContentInterface {
|
type LearningContentMediaLibraryObjectType implements CoursePageInterface & LearningContentInterface {
|
||||||
|
|
@ -223,6 +155,7 @@ type LearningContentAssignmentObjectType implements CoursePageInterface & Learni
|
||||||
minutes: Int
|
minutes: Int
|
||||||
description: String
|
description: String
|
||||||
content: String
|
content: String
|
||||||
|
competence_certificate: CompetenceCertificateObjectType!
|
||||||
}
|
}
|
||||||
|
|
||||||
type AssignmentObjectType implements CoursePageInterface {
|
type AssignmentObjectType implements CoursePageInterface {
|
||||||
|
|
@ -316,6 +249,44 @@ type AssignmentCompletionObjectType {
|
||||||
learning_content_page_id: ID
|
learning_content_page_id: ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Leverages the internal Python implementation of UUID (uuid.UUID) to provide native UUID objects
|
||||||
|
in fields, resolvers and input.
|
||||||
|
"""
|
||||||
|
scalar UUID
|
||||||
|
|
||||||
|
"""
|
||||||
|
The `DateTime` scalar type represents a DateTime
|
||||||
|
value as specified by
|
||||||
|
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
|
||||||
|
"""
|
||||||
|
scalar DateTime
|
||||||
|
|
||||||
|
type UserObjectType {
|
||||||
|
"""
|
||||||
|
Erforderlich. 150 Zeichen oder weniger. Nur Buchstaben, Ziffern und @/./+/-/_.
|
||||||
|
"""
|
||||||
|
username: String!
|
||||||
|
first_name: String!
|
||||||
|
last_name: String!
|
||||||
|
id: UUID!
|
||||||
|
avatar_url: String!
|
||||||
|
email: String!
|
||||||
|
language: CoreUserLanguageChoices!
|
||||||
|
}
|
||||||
|
|
||||||
|
"""An enumeration."""
|
||||||
|
enum CoreUserLanguageChoices {
|
||||||
|
"""Deutsch"""
|
||||||
|
DE
|
||||||
|
|
||||||
|
"""Français"""
|
||||||
|
FR
|
||||||
|
|
||||||
|
"""Italiano"""
|
||||||
|
IT
|
||||||
|
}
|
||||||
|
|
||||||
type CourseSessionObjectType {
|
type CourseSessionObjectType {
|
||||||
id: ID!
|
id: ID!
|
||||||
created_at: DateTime!
|
created_at: DateTime!
|
||||||
|
|
@ -428,6 +399,7 @@ type CourseSessionEdoniqTestObjectType {
|
||||||
}
|
}
|
||||||
|
|
||||||
type LearningContentEdoniqTestObjectType implements CoursePageInterface & LearningContentInterface {
|
type LearningContentEdoniqTestObjectType implements CoursePageInterface & LearningContentInterface {
|
||||||
|
checkbox_text: String!
|
||||||
content_assignment: AssignmentObjectType
|
content_assignment: AssignmentObjectType
|
||||||
id: ID!
|
id: ID!
|
||||||
title: String!
|
title: String!
|
||||||
|
|
@ -441,6 +413,7 @@ type LearningContentEdoniqTestObjectType implements CoursePageInterface & Learni
|
||||||
minutes: Int
|
minutes: Int
|
||||||
description: String
|
description: String
|
||||||
content: String
|
content: String
|
||||||
|
competence_certificate: CompetenceCertificateObjectType!
|
||||||
}
|
}
|
||||||
|
|
||||||
type CourseSessionUserObjectsType {
|
type CourseSessionUserObjectsType {
|
||||||
|
|
@ -612,42 +585,11 @@ type LearningContentDocumentListObjectType implements CoursePageInterface & Lear
|
||||||
|
|
||||||
type CompetenceCertificateListObjectType implements CoursePageInterface {
|
type CompetenceCertificateListObjectType implements CoursePageInterface {
|
||||||
id: ID!
|
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: UserObjectType
|
|
||||||
title: String!
|
title: String!
|
||||||
draft_title: String!
|
|
||||||
slug: String!
|
slug: String!
|
||||||
content_type: String!
|
content_type: String!
|
||||||
url_path: String!
|
live: Boolean!
|
||||||
owner: UserObjectType
|
translation_key: String!
|
||||||
|
|
||||||
"""
|
|
||||||
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!
|
frontend_url: String!
|
||||||
circle: CircleObjectType
|
circle: CircleObjectType
|
||||||
course: CourseObjectType
|
course: CourseObjectType
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,15 @@ export const LEARNING_PATH_QUERY = graphql(`
|
||||||
content_assignment {
|
content_assignment {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
competence_certificate {
|
||||||
|
...CoursePageFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on LearningContentEdoniqTestObjectType {
|
||||||
|
checkbox_text
|
||||||
|
competence_certificate {
|
||||||
|
...CoursePageFields
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCircleStore } from "@/stores/circle";
|
|
||||||
import type { CourseSessionUser } from "@/types";
|
import type { CourseSessionUser } from "@/types";
|
||||||
import { humanizeDuration } from "@/utils/humanizeDuration";
|
|
||||||
import sumBy from "lodash/sumBy";
|
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed, onMounted } from "vue";
|
import { computed, watch } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import CircleDiagram from "./CircleDiagram.vue";
|
import CircleDiagram from "./CircleDiagram.vue";
|
||||||
import CircleOverview from "./CircleOverview.vue";
|
import CircleOverview from "./CircleOverview.vue";
|
||||||
import DocumentSection from "./DocumentSection.vue";
|
import DocumentSection from "./DocumentSection.vue";
|
||||||
import LearningSequence from "./LearningSequence.vue";
|
import { useCourseSessionDetailQuery, useLearningPathQuery } from "@/composables";
|
||||||
import { useCourseSessionDetailQuery } from "@/composables";
|
import { stringifyParse } from "@/utils/utils";
|
||||||
|
import { useCircleStore } from "@/stores/circle";
|
||||||
|
import LearningSequence from "@/pages/learningPath/circlePage/LearningSequence.vue";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
courseSlug: string;
|
courseSlug: string;
|
||||||
|
|
@ -28,81 +27,79 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
profileUser: undefined,
|
profileUser: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
log.debug("CirclePage created", props.readonly, props.profileUser);
|
log.debug("CirclePage created", stringifyParse(props));
|
||||||
|
|
||||||
const circleExperts = computed(() => {
|
const circleExperts = computed(() => {
|
||||||
if (circleStore.circle) {
|
if (circle.value) {
|
||||||
return courseSessionDetailResult.filterCircleExperts(circleStore.circle.slug);
|
return courseSessionDetailResult.filterCircleExperts(circle.value.slug);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
const duration = computed(() => {
|
const duration = computed(() => {
|
||||||
if (circleStore.circle) {
|
// if (circleStore.circle) {
|
||||||
const minutes = sumBy(circleStore.circle.learningSequences, "minutes");
|
// const minutes = sumBy(circleStore.circle.learningSequences, "minutes");
|
||||||
return humanizeDuration(minutes);
|
// return humanizeDuration(minutes);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
|
|
||||||
const showDuration = computed(() => {
|
const showDuration = computed(() => {
|
||||||
return (
|
// return (
|
||||||
circleStore.circle && sumBy(circleStore.circle.learningSequences, "minutes") > 0
|
// circleStore.circle && sumBy(circleStore.circle.learningSequences, "minutes") > 0
|
||||||
);
|
// );
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
const lpQueryResult = useLearningPathQuery(props.courseSlug);
|
||||||
log.debug(
|
|
||||||
"CirclePage mounted",
|
|
||||||
props.courseSlug,
|
|
||||||
props.circleSlug,
|
|
||||||
props.profileUser
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
const circle = computed(() => {
|
||||||
if (props.profileUser) {
|
return lpQueryResult.findCircle(props.circleSlug);
|
||||||
await circleStore.loadCircle(
|
});
|
||||||
props.courseSlug,
|
|
||||||
props.circleSlug,
|
|
||||||
props.profileUser.user_id
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
await circleStore.loadCircle(props.courseSlug, props.circleSlug);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route.hash.startsWith("#ls-") || route.hash.startsWith("#lu-")) {
|
watch(
|
||||||
const slugEnd = route.hash.replace("#", "");
|
() => circle.value,
|
||||||
let wagtailPage = null;
|
() => {
|
||||||
|
if (circle.value) {
|
||||||
|
log.debug("circle loaded", circle);
|
||||||
|
|
||||||
if (slugEnd.startsWith("ls-")) {
|
try {
|
||||||
wagtailPage = circleStore.circle?.learningSequences.find((ls) => {
|
if (route.hash.startsWith("#ls-") || route.hash.startsWith("#lu-")) {
|
||||||
return ls.slug.endsWith(slugEnd);
|
const slugEnd = route.hash.replace("#", "");
|
||||||
});
|
|
||||||
} else if (slugEnd.startsWith("lu-")) {
|
if (circle.value) {
|
||||||
const learningUnits = circleStore.circle?.learningSequences.flatMap(
|
let wagtailPage = null;
|
||||||
(ls) => ls.learningUnits
|
if (slugEnd.startsWith("ls-")) {
|
||||||
);
|
wagtailPage = circle.value.learning_sequences.find((ls) => {
|
||||||
if (learningUnits) {
|
return ls.slug.endsWith(slugEnd);
|
||||||
wagtailPage = learningUnits.find((lu) => {
|
});
|
||||||
return lu.slug.endsWith(slugEnd);
|
} else if (slugEnd.startsWith("lu-")) {
|
||||||
});
|
const learningUnits = circle.value.learning_sequences.flatMap(
|
||||||
|
(ls) => ls.learning_units
|
||||||
|
);
|
||||||
|
if (learningUnits) {
|
||||||
|
wagtailPage = learningUnits.find((lu) => {
|
||||||
|
return lu.slug.endsWith(slugEnd);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wagtailPage) {
|
||||||
|
document
|
||||||
|
.getElementById(wagtailPage.slug)
|
||||||
|
?.scrollIntoView({ behavior: "smooth" });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (error) {
|
||||||
if (wagtailPage) {
|
log.error(error);
|
||||||
document
|
|
||||||
.getElementById(wagtailPage.slug)
|
|
||||||
?.scrollIntoView({ behavior: "smooth" });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
log.error(error);
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div v-if="circle">
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<CircleOverview
|
<CircleOverview
|
||||||
:circle="circleStore.circle"
|
:circle="circleStore.circle"
|
||||||
|
|
@ -145,7 +142,7 @@ onMounted(async () => {
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<h1 class="text-blue-dark text-4xl lg:text-6xl" data-cy="circle-title">
|
<h1 class="text-blue-dark text-4xl lg:text-6xl" data-cy="circle-title">
|
||||||
{{ circleStore.circle?.title }}
|
{{ circle?.title }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div v-if="showDuration" class="mt-2">
|
<div v-if="showDuration" class="mt-2">
|
||||||
|
|
@ -176,7 +173,7 @@ onMounted(async () => {
|
||||||
{{ $t("circlePage.circleContentBoxTitle") }}
|
{{ $t("circlePage.circleContentBoxTitle") }}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="mt-4 leading-relaxed">
|
<div class="mt-4 leading-relaxed">
|
||||||
{{ circleStore.circle?.description }}
|
{{ circle?.description }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|
@ -192,7 +189,7 @@ onMounted(async () => {
|
||||||
<div class="mt-4 leading-relaxed">
|
<div class="mt-4 leading-relaxed">
|
||||||
{{
|
{{
|
||||||
$t("circlePage.contactExpertDescription", {
|
$t("circlePage.contactExpertDescription", {
|
||||||
circleName: circleStore.circle?.title,
|
circleName: circle?.title,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -220,9 +217,8 @@ onMounted(async () => {
|
||||||
|
|
||||||
<ol class="flex-auto bg-gray-200 px-4 py-8 lg:px-24">
|
<ol class="flex-auto bg-gray-200 px-4 py-8 lg:px-24">
|
||||||
<li
|
<li
|
||||||
v-for="learningSequence in circleStore.circle?.learningSequences ||
|
v-for="learningSequence in circle?.learning_sequences ?? []"
|
||||||
[]"
|
:key="learningSequence.id"
|
||||||
:key="learningSequence.translation_key"
|
|
||||||
>
|
>
|
||||||
<LearningSequence
|
<LearningSequence
|
||||||
:learning-sequence="learningSequence"
|
:learning-sequence="learningSequence"
|
||||||
|
|
@ -239,15 +235,6 @@ onMounted(async () => {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="postcss" scoped>
|
<style lang="postcss" scoped>
|
||||||
.circle-container {
|
|
||||||
/*background: linear-gradient(to right, white 0%, white 50%, theme(colors.gray.200) 50%, theme(colors.gray.200) 100%);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.circle {
|
|
||||||
/*max-width: 1440px;*/
|
|
||||||
/*margin: 0 auto;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.v-enter-active,
|
.v-enter-active,
|
||||||
.v-leave-active {
|
.v-leave-active {
|
||||||
transition: opacity 0.3s ease;
|
transition: opacity 0.3s ease;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,13 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
|
||||||
import LearningContentBadge from "@/pages/learningPath/LearningContentTypeBadge.vue";
|
import LearningContentBadge from "@/pages/learningPath/LearningContentTypeBadge.vue";
|
||||||
import { showIcon } from "@/pages/learningPath/circlePage/learningSequenceUtils";
|
import { showIcon } from "@/pages/learningPath/circlePage/learningSequenceUtils";
|
||||||
import { useCircleStore } from "@/stores/circle";
|
import { useCircleStore } from "@/stores/circle";
|
||||||
import type {
|
import type {
|
||||||
CourseCompletionStatus,
|
|
||||||
LearningContent,
|
LearningContent,
|
||||||
LearningContentAssignment,
|
LearningContentAssignment,
|
||||||
LearningContentEdoniqTest,
|
LearningContentEdoniqTest,
|
||||||
LearningContentInterface,
|
|
||||||
LearningSequence,
|
LearningSequence,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
import findLast from "lodash/findLast";
|
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { humanizeDuration } from "../../../utils/humanizeDuration";
|
import { humanizeDuration } from "../../../utils/humanizeDuration";
|
||||||
import {
|
import {
|
||||||
|
|
@ -30,52 +26,52 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
|
|
||||||
const circleStore = useCircleStore();
|
const circleStore = useCircleStore();
|
||||||
|
|
||||||
function toggleCompleted(learningContent: LearningContentInterface) {
|
function toggleCompleted(learningContent: LearningContent) {
|
||||||
let completionStatus: CourseCompletionStatus = "SUCCESS";
|
// let completionStatus: CourseCompletionStatus = "SUCCESS";
|
||||||
if (learningContent.completion_status === "SUCCESS") {
|
// if (learningContent.completion_status === "SUCCESS") {
|
||||||
completionStatus = "FAIL";
|
// completionStatus = "FAIL";
|
||||||
}
|
// }
|
||||||
circleStore.markCompletion(learningContent, completionStatus);
|
// circleStore.markCompletion(learningContent, completionStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
const someFinished = computed(() => {
|
const someFinished = computed(() => {
|
||||||
if (props.learningSequence && circleStore.circle) {
|
// if (props.learningSequence && circleStore.circle) {
|
||||||
return circleStore.circle.someFinishedInLearningSequence(
|
// return circleStore.circle.someFinishedInLearningSequence(
|
||||||
props.learningSequence.translation_key
|
// props.learningSequence.translation_key
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
const allFinished = computed(() => {
|
const allFinished = computed(() => {
|
||||||
if (props.learningSequence && circleStore.circle) {
|
// if (props.learningSequence && circleStore.circle) {
|
||||||
return circleStore.circle.allFinishedInLearningSequence(
|
// return circleStore.circle.allFinishedInLearningSequence(
|
||||||
props.learningSequence.translation_key
|
// props.learningSequence.translation_key
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
const continueTranslationKeyTuple = computed(() => {
|
const continueTranslationKeyTuple = computed(() => {
|
||||||
if (props.learningSequence && circleStore.circle) {
|
// if (props.learningSequence && circleStore.circle) {
|
||||||
const lastFinished = findLast(
|
// const lastFinished = findLast(
|
||||||
circleStore.circle.flatLearningContents,
|
// circleStore.circle.flatLearningContents,
|
||||||
(learningContent) => {
|
// (learningContent) => {
|
||||||
return learningContent.completion_status === "SUCCESS";
|
// return learningContent.completion_status === "SUCCESS";
|
||||||
}
|
// }
|
||||||
);
|
// );
|
||||||
|
//
|
||||||
if (!lastFinished) {
|
// if (!lastFinished) {
|
||||||
// must be the first
|
// // must be the first
|
||||||
return [circleStore.circle.flatLearningContents[0].translation_key, true];
|
// return [circleStore.circle.flatLearningContents[0].translation_key, true];
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (lastFinished && lastFinished.nextLearningContent) {
|
// if (lastFinished && lastFinished.nextLearningContent) {
|
||||||
return [lastFinished.nextLearningContent.translation_key, false];
|
// return [lastFinished.nextLearningContent.translation_key, false];
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
});
|
});
|
||||||
|
|
@ -97,8 +93,8 @@ const learningSequenceBorderClass = computed(() => {
|
||||||
|
|
||||||
function belongsToCompetenceCertificate(lc: LearningContent) {
|
function belongsToCompetenceCertificate(lc: LearningContent) {
|
||||||
return (
|
return (
|
||||||
(lc.content_type === "learnpath.LearningContentAssignment" ||
|
(lc.__typename === "LearningContentAssignmentObjectType" ||
|
||||||
lc.content_type === "learnpath.LearningContentEdoniqTest") &&
|
lc.__typename === "LearningContentEdoniqTestObjectType") &&
|
||||||
lc.competence_certificate?.frontend_url
|
lc.competence_certificate?.frontend_url
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +132,7 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
|
||||||
|
|
||||||
<ol class="border bg-white px-4 lg:px-6" :class="learningSequenceBorderClass">
|
<ol class="border bg-white px-4 lg:px-6" :class="learningSequenceBorderClass">
|
||||||
<li
|
<li
|
||||||
v-for="learningUnit in learningSequence.learningUnits"
|
v-for="learningUnit in learningSequence.learning_units"
|
||||||
:id="learningUnit.slug"
|
:id="learningUnit.slug"
|
||||||
:key="learningUnit.id"
|
:key="learningUnit.id"
|
||||||
class="pt-3 lg:pt-6"
|
class="pt-3 lg:pt-6"
|
||||||
|
|
@ -154,7 +150,7 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
|
||||||
</div>
|
</div>
|
||||||
<ol>
|
<ol>
|
||||||
<li
|
<li
|
||||||
v-for="learningContent in learningUnit.learningContents"
|
v-for="learningContent in learningUnit.learning_contents"
|
||||||
:key="learningContent.id"
|
:key="learningContent.id"
|
||||||
>
|
>
|
||||||
<div class="pb-6">
|
<div class="pb-6">
|
||||||
|
|
@ -181,15 +177,15 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
|
||||||
"
|
"
|
||||||
@toggle="toggleCompleted(learningContent)"
|
@toggle="toggleCompleted(learningContent)"
|
||||||
@click="
|
@click="
|
||||||
(event: MouseEvent) => {
|
(event: MouseEvent) => {
|
||||||
// when disabled open the learning content directly
|
// when disabled open the learning content directly
|
||||||
if (!learningContent.can_user_self_toggle_course_completion) {
|
if (!learningContent.can_user_self_toggle_course_completion) {
|
||||||
circleStore.openLearningContent(learningContent);
|
circleStore.openLearningContent(learningContent);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="flex flex-auto flex-col gap-4 xl:flex-row xl:justify-between"
|
class="flex flex-auto flex-col gap-4 xl:flex-row xl:justify-between"
|
||||||
|
|
@ -258,31 +254,31 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<div
|
<!-- <div-->
|
||||||
v-if="learningUnit.children.length"
|
<!-- v-if="learningUnit.children.length"-->
|
||||||
:class="{ 'cursor-pointer': !props.readonly }"
|
<!-- :class="{ 'cursor-pointer': !props.readonly }"-->
|
||||||
:data-cy="`${learningUnit.slug}`"
|
<!-- :data-cy="`${learningUnit.slug}`"-->
|
||||||
@click="!props.readonly && circleStore.openSelfEvaluation(learningUnit)"
|
<!-- @click="!props.readonly && circleStore.openSelfEvaluation(learningUnit)"-->
|
||||||
>
|
<!-- >-->
|
||||||
<div
|
<!-- <div-->
|
||||||
v-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'SUCCESS'"
|
<!-- v-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'SUCCESS'"-->
|
||||||
class="self-evaluation-success flex items-center gap-4 pb-6"
|
<!-- class="self-evaluation-success flex items-center gap-4 pb-6"-->
|
||||||
>
|
<!-- >-->
|
||||||
<it-icon-smiley-happy class="mr-4 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>{{ $t("selfEvaluation.selfEvaluationYes") }}</div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div
|
<!-- <div-->
|
||||||
v-else-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'FAIL'"
|
<!-- v-else-if="circleStore.calcSelfEvaluationStatus(learningUnit) === 'FAIL'"-->
|
||||||
class="self-evaluation-fail flex items-center gap-4 pb-6"
|
<!-- class="self-evaluation-fail flex items-center gap-4 pb-6"-->
|
||||||
>
|
<!-- >-->
|
||||||
<it-icon-smiley-thinking class="mr-4 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>{{ $t("selfEvaluation.selfEvaluationNo") }}</div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div v-else class="self-evaluation-unknown flex items-center gap-4 pb-6">
|
<!-- <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" />
|
<!-- <it-icon-smiley-neutral class="mr-4 h-8 w-8 flex-none" data-cy="unknown" />-->
|
||||||
<div>{{ $t("a.Selbsteinschätzung") }}</div>
|
<!-- <div>{{ $t("a.Selbsteinschätzung") }}</div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
|
|
||||||
<hr v-if="!learningUnit.last" class="-mx-4 text-gray-500" />
|
<hr v-if="!learningUnit.last" class="-mx-4 text-gray-500" />
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import LearningContentContainer from "@/pages/learningPath/learningContentPage/L
|
||||||
import DocumentListBlock from "@/pages/learningPath/learningContentPage/blocks/DocumentListBlock.vue";
|
import DocumentListBlock from "@/pages/learningPath/learningContentPage/blocks/DocumentListBlock.vue";
|
||||||
import EdoniqTestBlock from "@/pages/learningPath/learningContentPage/blocks/EdoniqTestBlock.vue";
|
import EdoniqTestBlock from "@/pages/learningPath/learningContentPage/blocks/EdoniqTestBlock.vue";
|
||||||
import { useCircleStore } from "@/stores/circle";
|
import { useCircleStore } from "@/stores/circle";
|
||||||
import type { LearningContent, LearningContentType } from "@/types";
|
import type { LearningContent, LearningContentContentType } from "@/types";
|
||||||
import eventBus from "@/utils/eventBus";
|
import eventBus from "@/utils/eventBus";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import type { Component } from "vue";
|
import type { Component } from "vue";
|
||||||
|
|
@ -29,7 +29,7 @@ log.debug("LearningContentParent setup", props.learningContent);
|
||||||
const previousRoute = getPreviousRoute();
|
const previousRoute = getPreviousRoute();
|
||||||
|
|
||||||
// can't use the type as component name, as some are reserved HTML components, e.g. video
|
// can't use the type as component name, as some are reserved HTML components, e.g. video
|
||||||
const COMPONENTS: Record<LearningContentType, Component> = {
|
const COMPONENTS: Record<LearningContentContentType, Component> = {
|
||||||
"learnpath.LearningContentAssignment": AssignmentBlock,
|
"learnpath.LearningContentAssignment": AssignmentBlock,
|
||||||
"learnpath.LearningContentAttendanceCourse": AttendanceCourseBlock,
|
"learnpath.LearningContentAttendanceCourse": AttendanceCourseBlock,
|
||||||
"learnpath.LearningContentDocumentList": DocumentListBlock,
|
"learnpath.LearningContentDocumentList": DocumentListBlock,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,25 @@
|
||||||
import type {
|
import type {
|
||||||
AssignmentCompletionObjectType,
|
AssignmentCompletionObjectType,
|
||||||
AssignmentCompletionStatus as AssignmentCompletionStatusGenerated,
|
AssignmentCompletionStatus as AssignmentCompletionStatusGenerated,
|
||||||
|
CircleObjectType,
|
||||||
CourseCourseSessionUserRoleChoices,
|
CourseCourseSessionUserRoleChoices,
|
||||||
CourseSessionObjectType,
|
CourseSessionObjectType,
|
||||||
CourseSessionUserObjectsType,
|
CourseSessionUserObjectsType,
|
||||||
|
LearningContentAssignmentObjectType,
|
||||||
|
LearningContentAttendanceCourseObjectType,
|
||||||
|
LearningContentDocumentListObjectType,
|
||||||
|
LearningContentEdoniqTestObjectType,
|
||||||
|
LearningContentFeedbackObjectType,
|
||||||
|
LearningContentLearningModuleObjectType,
|
||||||
|
LearningContentMediaLibraryObjectType,
|
||||||
|
LearningContentPlaceholderObjectType,
|
||||||
|
LearningContentRichTextObjectType,
|
||||||
|
LearningContentVideoObjectType,
|
||||||
|
LearningPathObjectType,
|
||||||
|
LearningSequenceObjectType,
|
||||||
|
LearningUnitObjectType,
|
||||||
|
TopicObjectType,
|
||||||
} from "@/gql/graphql";
|
} from "@/gql/graphql";
|
||||||
import type { Circle } from "@/services/circle";
|
|
||||||
import type { Component } from "vue";
|
import type { Component } from "vue";
|
||||||
|
|
||||||
export type LoginMethod = "local" | "sso";
|
export type LoginMethod = "local" | "sso";
|
||||||
|
|
@ -29,101 +43,98 @@ export interface CircleLight {
|
||||||
readonly title: string;
|
readonly title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// refine generated types
|
||||||
|
export type LearningContentAssignment = LearningContentAssignmentObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentAssignment";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LearningContentAttendanceCourse =
|
||||||
|
LearningContentAttendanceCourseObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentAttendanceCourse";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LearningContentDocumentList = LearningContentDocumentListObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentDocumentList";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LearningContentEdoniqTest = LearningContentEdoniqTestObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentEdoniqTest";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LearningContentFeedback = LearningContentFeedbackObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentFeedback";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LearningContentLearningModule = LearningContentLearningModuleObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentLearningModule";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LearningContentMediaLibrary = LearningContentMediaLibraryObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentMediaLibrary";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LearningContentPlaceholder = LearningContentPlaceholderObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentPlaceholder";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LearningContentRichText = LearningContentRichTextObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentRichText";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LearningContentVideo = LearningContentVideoObjectType & {
|
||||||
|
readonly content_type: "learnpath.LearningContentVideo";
|
||||||
|
};
|
||||||
|
|
||||||
export type LearningContent =
|
export type LearningContent =
|
||||||
| LearningContentAssignment
|
| LearningContentAssignment
|
||||||
| LearningContentAttendanceCourse
|
| LearningContentAttendanceCourse
|
||||||
| LearningContentDocumentList
|
| LearningContentDocumentList
|
||||||
|
| LearningContentEdoniqTest
|
||||||
| LearningContentFeedback
|
| LearningContentFeedback
|
||||||
| LearningContentLearningModule
|
| LearningContentLearningModule
|
||||||
| LearningContentMediaLibrary
|
| LearningContentMediaLibrary
|
||||||
| LearningContentPlaceholder
|
| LearningContentPlaceholder
|
||||||
| LearningContentRichText
|
| LearningContentRichText
|
||||||
| LearningContentEdoniqTest
|
|
||||||
| LearningContentVideo;
|
| LearningContentVideo;
|
||||||
|
|
||||||
export type LearningContentType = LearningContent["content_type"];
|
export type LearningContentContentType = LearningContent["content_type"];
|
||||||
|
|
||||||
export interface LearningContentInterface extends BaseCourseWagtailPage {
|
export type LearningUnit = Omit<
|
||||||
readonly content_type: LearningContentType;
|
LearningUnitObjectType,
|
||||||
readonly minutes: number;
|
"content_type" | "learning_contents"
|
||||||
readonly description: string;
|
> & {
|
||||||
readonly content_url: string;
|
content_type: "learnpath.LearningUnit";
|
||||||
readonly can_user_self_toggle_course_completion: boolean;
|
learning_contents: LearningContent[];
|
||||||
parentCircle: Circle;
|
};
|
||||||
parentLearningSequence?: LearningSequence;
|
|
||||||
parentLearningUnit?: LearningUnit;
|
|
||||||
nextLearningContent?: LearningContent;
|
|
||||||
previousLearningContent?: LearningContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningContentAssignment extends LearningContentInterface {
|
export type LearningSequence = Omit<
|
||||||
readonly content_type: "learnpath.LearningContentAssignment";
|
LearningSequenceObjectType,
|
||||||
readonly content_assignment_id: string;
|
"content_type" | "learning_units"
|
||||||
readonly assignment_type: AssignmentType;
|
> & {
|
||||||
readonly competence_certificate?: {
|
content_type: "learnpath.LearningSequence";
|
||||||
id: string;
|
learning_units: LearningUnit[];
|
||||||
title: string;
|
};
|
||||||
slug: string;
|
|
||||||
content_type: string;
|
|
||||||
translation_key: string;
|
|
||||||
frontend_url: string;
|
|
||||||
} | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningContentAttendanceCourse extends LearningContentInterface {
|
export type CircleType = Omit<
|
||||||
readonly content_type: "learnpath.LearningContentAttendanceCourse";
|
CircleObjectType,
|
||||||
}
|
"content_type" | "learning_sequences"
|
||||||
|
> & {
|
||||||
|
content_type: "learnpath.Circle";
|
||||||
|
learning_sequences: LearningSequence[];
|
||||||
|
};
|
||||||
|
|
||||||
export interface LearningContentDocument {
|
export type TopicType = Omit<TopicObjectType, "content_type" | "circles"> & {
|
||||||
readonly type: "document";
|
content_type: "learnpath.Topic";
|
||||||
readonly id: string;
|
circles: CircleType[];
|
||||||
readonly value: MediaLibraryContentBlockValue;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningContentDocumentList extends LearningContentInterface {
|
export type LearningPathType = Omit<
|
||||||
readonly content_type: "learnpath.LearningContentDocumentList";
|
LearningPathObjectType,
|
||||||
readonly documents: LearningContentDocument[];
|
"content_type" | "topics"
|
||||||
}
|
> & {
|
||||||
|
content_type: "learnpath.LearningPath";
|
||||||
export interface LearningContentFeedback extends LearningContentInterface {
|
topics: TopicType[];
|
||||||
readonly content_type: "learnpath.LearningContentFeedback";
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningContentLearningModule extends LearningContentInterface {
|
|
||||||
readonly content_type: "learnpath.LearningContentLearningModule";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningContentMediaLibrary extends LearningContentInterface {
|
|
||||||
readonly content_type: "learnpath.LearningContentMediaLibrary";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningContentPlaceholder extends LearningContentInterface {
|
|
||||||
readonly content_type: "learnpath.LearningContentPlaceholder";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningContentRichText extends LearningContentInterface {
|
|
||||||
readonly content_type: "learnpath.LearningContentRichText";
|
|
||||||
readonly text: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningContentEdoniqTest extends LearningContentInterface {
|
|
||||||
readonly content_type: "learnpath.LearningContentEdoniqTest";
|
|
||||||
readonly checkbox_text: string;
|
|
||||||
readonly has_extended_time_test: boolean;
|
|
||||||
readonly content_assignment_id: string;
|
|
||||||
readonly competence_certificate?: {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
slug: string;
|
|
||||||
content_type: string;
|
|
||||||
translation_key: string;
|
|
||||||
frontend_url: string;
|
|
||||||
} | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningContentVideo extends LearningContentInterface {
|
|
||||||
readonly content_type: "learnpath.LearningContentVideo";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningUnitPerformanceCriteria extends BaseCourseWagtailPage {
|
export interface LearningUnitPerformanceCriteria extends BaseCourseWagtailPage {
|
||||||
readonly content_type: "competence.PerformanceCriteria";
|
readonly content_type: "competence.PerformanceCriteria";
|
||||||
|
|
@ -132,66 +143,6 @@ export interface LearningUnitPerformanceCriteria extends BaseCourseWagtailPage {
|
||||||
parentLearningUnit?: LearningUnit;
|
parentLearningUnit?: LearningUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LearningUnit extends BaseCourseWagtailPage {
|
|
||||||
readonly content_type: "learnpath.LearningUnit";
|
|
||||||
readonly evaluate_url: string;
|
|
||||||
readonly course_category: CourseCategory;
|
|
||||||
readonly title_hidden: boolean;
|
|
||||||
children: LearningUnitPerformanceCriteria[];
|
|
||||||
|
|
||||||
// additional frontend fields
|
|
||||||
learningContents: LearningContent[];
|
|
||||||
minutes: number;
|
|
||||||
parentLearningSequence?: LearningSequence;
|
|
||||||
parentCircle?: Circle;
|
|
||||||
last?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningSequence extends BaseCourseWagtailPage {
|
|
||||||
readonly content_type: "learnpath.LearningSequence";
|
|
||||||
icon: string;
|
|
||||||
learningUnits: LearningUnit[];
|
|
||||||
minutes: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CircleChild = LearningContentInterface | LearningUnit | LearningSequence;
|
|
||||||
|
|
||||||
export interface WagtailLearningPath extends BaseCourseWagtailPage {
|
|
||||||
readonly content_type: "learnpath.LearningPath";
|
|
||||||
course: Course;
|
|
||||||
children: LearningPathChild[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CircleGoal {
|
|
||||||
type: "goal";
|
|
||||||
value: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CircleJobSituation {
|
|
||||||
type: "job_situation";
|
|
||||||
value: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WagtailCircle extends BaseCourseWagtailPage {
|
|
||||||
readonly content_type: "learnpath.Circle";
|
|
||||||
readonly description: string;
|
|
||||||
readonly goal_description: string;
|
|
||||||
readonly goals: CircleGoal[];
|
|
||||||
readonly job_situation_description: string;
|
|
||||||
readonly job_situations: CircleJobSituation[];
|
|
||||||
readonly children: CircleChild[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Topic extends BaseCourseWagtailPage {
|
|
||||||
readonly content_type: "learnpath.Topic";
|
|
||||||
readonly is_visible: boolean;
|
|
||||||
circles: Circle[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LearningPathChild = Topic | WagtailCircle;
|
|
||||||
|
|
||||||
export interface CourseCompletion {
|
export interface CourseCompletion {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,10 @@ export function assertUnreachable(msg: string): never {
|
||||||
throw new Error("Didn't expect to get here, " + msg);
|
throw new Error("Didn't expect to get here, " + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function stringifyParse(obj: any): any {
|
||||||
|
return JSON.parse(JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
|
||||||
function createCourseUrl(courseSlug: string | undefined, specificSub: string): string {
|
function createCourseUrl(courseSlug: string | undefined, specificSub: string): string {
|
||||||
if (!courseSlug) {
|
if (!courseSlug) {
|
||||||
return "/";
|
return "/";
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ class CompetenceCertificateListObjectType(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CompetenceCertificateList
|
model = CompetenceCertificateList
|
||||||
interfaces = (CoursePageInterface,)
|
interfaces = (CoursePageInterface,)
|
||||||
|
fields = []
|
||||||
|
|
||||||
def resolve_competence_certificates(self, info):
|
def resolve_competence_certificates(self, info):
|
||||||
return CompetenceCertificate.objects.child_of(self)
|
return CompetenceCertificate.objects.child_of(self)
|
||||||
|
|
|
||||||
|
|
@ -124,15 +124,21 @@ class LearningContentMediaLibraryObjectType(DjangoObjectType):
|
||||||
|
|
||||||
|
|
||||||
class LearningContentEdoniqTestObjectType(DjangoObjectType):
|
class LearningContentEdoniqTestObjectType(DjangoObjectType):
|
||||||
|
competence_certificate = graphene.Field(
|
||||||
|
"vbv_lernwelt.competence.graphql.types.CompetenceCertificateObjectType",
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = LearningContentEdoniqTest
|
model = LearningContentEdoniqTest
|
||||||
interfaces = (
|
interfaces = (
|
||||||
CoursePageInterface,
|
CoursePageInterface,
|
||||||
LearningContentInterface,
|
LearningContentInterface,
|
||||||
)
|
)
|
||||||
fields = [
|
fields = ["content_assignment", "checkbox_text", "has_extended_time_test"]
|
||||||
"content_assignment",
|
|
||||||
]
|
@staticmethod
|
||||||
|
def resolve_competence_certificate(root: LearningContentEdoniqTest, info):
|
||||||
|
return root.content_assignment.competence_certificate
|
||||||
|
|
||||||
|
|
||||||
class LearningContentRichTextObjectType(DjangoObjectType):
|
class LearningContentRichTextObjectType(DjangoObjectType):
|
||||||
|
|
@ -146,6 +152,10 @@ class LearningContentRichTextObjectType(DjangoObjectType):
|
||||||
|
|
||||||
|
|
||||||
class LearningContentAssignmentObjectType(DjangoObjectType):
|
class LearningContentAssignmentObjectType(DjangoObjectType):
|
||||||
|
competence_certificate = graphene.Field(
|
||||||
|
"vbv_lernwelt.competence.graphql.types.CompetenceCertificateObjectType",
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = LearningContentAssignment
|
model = LearningContentAssignment
|
||||||
interfaces = (
|
interfaces = (
|
||||||
|
|
@ -157,6 +167,10 @@ class LearningContentAssignmentObjectType(DjangoObjectType):
|
||||||
"assignment_type",
|
"assignment_type",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_competence_certificate(root: LearningContentAssignment, info):
|
||||||
|
return root.content_assignment.competence_certificate
|
||||||
|
|
||||||
|
|
||||||
class LearningContentDocumentListObjectType(DjangoObjectType):
|
class LearningContentDocumentListObjectType(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -177,7 +191,7 @@ class LearningUnitObjectType(DjangoObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = LearningUnit
|
model = LearningUnit
|
||||||
interfaces = (CoursePageInterface,)
|
interfaces = (CoursePageInterface,)
|
||||||
fields = ["evaluate_url"]
|
fields = ["evaluate_url", "title_hidden"]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_evaluate_url(root: LearningUnit, info, **kwargs):
|
def resolve_evaluate_url(root: LearningUnit, info, **kwargs):
|
||||||
|
|
@ -207,7 +221,9 @@ class LearningUnitObjectType(DjangoObjectType):
|
||||||
|
|
||||||
|
|
||||||
class LearningSequenceObjectType(DjangoObjectType):
|
class LearningSequenceObjectType(DjangoObjectType):
|
||||||
learning_units = graphene.List(LearningUnitObjectType)
|
learning_units = graphene.List(
|
||||||
|
graphene.NonNull(LearningUnitObjectType), required=True
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = LearningSequence
|
model = LearningSequence
|
||||||
|
|
@ -236,7 +252,9 @@ class LearningSequenceObjectType(DjangoObjectType):
|
||||||
|
|
||||||
|
|
||||||
class CircleObjectType(DjangoObjectType):
|
class CircleObjectType(DjangoObjectType):
|
||||||
learning_sequences = graphene.List(LearningSequenceObjectType)
|
learning_sequences = graphene.List(
|
||||||
|
graphene.NonNull(LearningSequenceObjectType), required=True
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Circle
|
model = Circle
|
||||||
|
|
@ -273,7 +291,7 @@ class CircleObjectType(DjangoObjectType):
|
||||||
|
|
||||||
|
|
||||||
class TopicObjectType(DjangoObjectType):
|
class TopicObjectType(DjangoObjectType):
|
||||||
circles = graphene.List(CircleObjectType)
|
circles = graphene.List(graphene.NonNull(CircleObjectType), required=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Topic
|
model = Topic
|
||||||
|
|
@ -305,11 +323,12 @@ class TopicObjectType(DjangoObjectType):
|
||||||
|
|
||||||
|
|
||||||
class LearningPathObjectType(DjangoObjectType):
|
class LearningPathObjectType(DjangoObjectType):
|
||||||
topics = graphene.List(TopicObjectType)
|
topics = graphene.List(graphene.NonNull(TopicObjectType), required=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = LearningPath
|
model = LearningPath
|
||||||
interfaces = (CoursePageInterface,)
|
interfaces = (CoursePageInterface,)
|
||||||
|
fields = []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def resolve_topics(root: LearningPath, info, **kwargs):
|
def resolve_topics(root: LearningPath, info, **kwargs):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue