Merged in feature/VBV-451-anwesenheitskontrolle-frontend (pull request #150)
VBV-451 Anwesenheitskontrolle frontend & neues Cockpit * Regenerate graphql types after rebase * Fix grading progress * Fix cypress tests * Fix circle selection and add CourseSessionAssignment for Fahrzeug Vorbereitungsauftrag * Use `LearningContentAssignment` explictly * Improve type safety without `as` * Disable feedback details button when no feedback * Extend submission overview titles after review * Improve attendance check state handling * Minor translation/wording fixes Approved-by: Daniel Egger
This commit is contained in:
parent
65d527d894
commit
b970597a81
|
|
@ -11078,7 +11078,7 @@
|
||||||
"integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==",
|
"integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.3.1"
|
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/diff-sequences": {
|
"node_modules/diff-sequences": {
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,7 @@ const keydown = (e: KeyboardEvent) => {
|
||||||
toggle();
|
toggle();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const input = (e: Event) => {
|
const input = () => {
|
||||||
const target = e.target as HTMLInputElement;
|
|
||||||
log.debug("input", e.type, target.checked, target.value);
|
|
||||||
emit("toggle");
|
emit("toggle");
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ defineProps<{
|
||||||
<template>
|
<template>
|
||||||
<ItRow>
|
<ItRow>
|
||||||
<template #firstRow>
|
<template #firstRow>
|
||||||
|
<slot name="leading"></slot>
|
||||||
<img class="mr-2 h-[45px] rounded-full" :src="avatarUrl" />
|
<img class="mr-2 h-[45px] rounded-full" :src="avatarUrl" />
|
||||||
<p class="text-bold lg:leading-[45px]">{{ name }}</p>
|
<p class="text-bold lg:leading-[45px]">{{ name }}</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
|
||||||
*/
|
*/
|
||||||
const documents = {
|
const documents = {
|
||||||
"\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument,
|
"\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n": types.SendFeedbackMutationDocument,
|
||||||
|
"\n mutation AttendanceCheckMutation(\n $attendanceCourseId: ID!\n $attendanceUserList: [AttendanceUserInputType]!\n ) {\n update_course_session_attendance_course_users(\n id: $attendanceCourseId\n attendance_user_list: $attendanceUserList\n ) {\n course_session_attendance_course {\n id\n attendance_user_list {\n user_id\n first_name\n last_name\n email\n status\n }\n }\n }\n }\n": types.AttendanceCheckMutationDocument,
|
||||||
"\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n": types.UpsertAssignmentCompletionDocument,
|
"\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n": types.UpsertAssignmentCompletionDocument,
|
||||||
|
"\n query attendanceCheckQuery($courseSessionId: ID!) {\n course_session_attendance_course(id: $courseSessionId) {\n id\n attendance_user_list {\n user_id\n status\n }\n }\n }\n": types.AttendanceCheckQueryDocument,
|
||||||
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
|
"\n query assignmentCompletionQuery(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n ) {\n assignment(id: $assignmentId) {\n assignment_type\n content_type\n effort_required\n evaluation_description\n evaluation_document_url\n evaluation_tasks\n id\n intro_text\n performance_objectives\n slug\n tasks\n title\n translation_key\n }\n assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n assignment_user_id: $assignmentUserId\n learning_content_page_id: $learningContentId\n ) {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_user {\n id\n }\n assignment_user {\n id\n }\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n": types.AssignmentCompletionQueryDocument,
|
||||||
"\n query courseQuery($courseId: Int!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n": types.CourseQueryDocument,
|
"\n query courseQuery($courseId: Int!) {\n course(id: $courseId) {\n id\n slug\n title\n category_name\n learning_path {\n id\n }\n }\n }\n": types.CourseQueryDocument,
|
||||||
};
|
};
|
||||||
|
|
@ -37,10 +39,18 @@ export function graphql(source: string): unknown;
|
||||||
* 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 mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n"): (typeof documents)["\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n"];
|
export function graphql(source: "\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n"): (typeof documents)["\n mutation SendFeedbackMutation($input: SendFeedbackInput!) {\n send_feedback(input: $input) {\n feedback_response {\n id\n }\n errors {\n field\n messages\n }\n }\n }\n"];
|
||||||
|
/**
|
||||||
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
|
*/
|
||||||
|
export function graphql(source: "\n mutation AttendanceCheckMutation(\n $attendanceCourseId: ID!\n $attendanceUserList: [AttendanceUserInputType]!\n ) {\n update_course_session_attendance_course_users(\n id: $attendanceCourseId\n attendance_user_list: $attendanceUserList\n ) {\n course_session_attendance_course {\n id\n attendance_user_list {\n user_id\n first_name\n last_name\n email\n status\n }\n }\n }\n }\n"): (typeof documents)["\n mutation AttendanceCheckMutation(\n $attendanceCourseId: ID!\n $attendanceUserList: [AttendanceUserInputType]!\n ) {\n update_course_session_attendance_course_users(\n id: $attendanceCourseId\n attendance_user_list: $attendanceUserList\n ) {\n course_session_attendance_course {\n id\n attendance_user_list {\n user_id\n first_name\n last_name\n email\n status\n }\n }\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* 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 mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"): (typeof documents)["\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"];
|
export function graphql(source: "\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"): (typeof documents)["\n mutation UpsertAssignmentCompletion(\n $assignmentId: ID!\n $courseSessionId: ID!\n $learningContentId: ID\n $assignmentUserId: UUID\n $completionStatus: AssignmentCompletionStatus!\n $completionDataString: String!\n $evaluationGrade: Float\n $evaluationPoints: Float\n ) {\n upsert_assignment_completion(\n assignment_id: $assignmentId\n course_session_id: $courseSessionId\n learning_content_page_id: $learningContentId\n assignment_user_id: $assignmentUserId\n completion_status: $completionStatus\n completion_data_string: $completionDataString\n evaluation_grade: $evaluationGrade\n evaluation_points: $evaluationPoints\n ) {\n assignment_completion {\n id\n completion_status\n submitted_at\n evaluation_submitted_at\n evaluation_grade\n evaluation_points\n completion_data\n }\n }\n }\n"];
|
||||||
|
/**
|
||||||
|
* 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 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"): (typeof documents)["\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"];
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -329,6 +329,14 @@ export type SendFeedbackMutationMutationVariables = Exact<{
|
||||||
|
|
||||||
export type SendFeedbackMutationMutation = { __typename?: 'Mutation', send_feedback?: { __typename?: 'SendFeedbackPayload', feedback_response?: { __typename?: 'FeedbackResponse', id: string } | null, errors?: Array<{ __typename?: 'ErrorType', field: string, messages: Array<string> } | null> | null } | null };
|
export type SendFeedbackMutationMutation = { __typename?: 'Mutation', send_feedback?: { __typename?: 'SendFeedbackPayload', feedback_response?: { __typename?: 'FeedbackResponse', id: string } | null, errors?: Array<{ __typename?: 'ErrorType', field: string, messages: Array<string> } | null> | null } | null };
|
||||||
|
|
||||||
|
export type AttendanceCheckMutationMutationVariables = Exact<{
|
||||||
|
attendanceCourseId: Scalars['ID']['input'];
|
||||||
|
attendanceUserList: Array<InputMaybe<AttendanceUserInputType>> | InputMaybe<AttendanceUserInputType>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type AttendanceCheckMutationMutation = { __typename?: 'Mutation', update_course_session_attendance_course_users?: { __typename?: 'AttendanceCourseUserMutation', course_session_attendance_course?: { __typename?: 'CourseSessionAttendanceCourseType', id: string, attendance_user_list?: Array<{ __typename?: 'AttendanceUserType', user_id: any, first_name?: string | null, last_name?: string | null, email?: string | null, status: AttendanceUserStatus } | null> | null } | null } | null };
|
||||||
|
|
||||||
export type UpsertAssignmentCompletionMutationVariables = Exact<{
|
export type UpsertAssignmentCompletionMutationVariables = Exact<{
|
||||||
assignmentId: Scalars['ID']['input'];
|
assignmentId: Scalars['ID']['input'];
|
||||||
courseSessionId: Scalars['ID']['input'];
|
courseSessionId: Scalars['ID']['input'];
|
||||||
|
|
@ -343,6 +351,13 @@ export type UpsertAssignmentCompletionMutationVariables = Exact<{
|
||||||
|
|
||||||
export type UpsertAssignmentCompletionMutation = { __typename?: 'Mutation', upsert_assignment_completion?: { __typename?: 'AssignmentCompletionMutation', assignment_completion?: { __typename?: 'AssignmentCompletionObjectType', id: any, completion_status: AssignmentAssignmentCompletionCompletionStatusChoices, submitted_at?: any | null, evaluation_submitted_at?: any | null, evaluation_grade?: number | null, evaluation_points?: number | null, completion_data?: any | null } | null } | null };
|
export type UpsertAssignmentCompletionMutation = { __typename?: 'Mutation', upsert_assignment_completion?: { __typename?: 'AssignmentCompletionMutation', assignment_completion?: { __typename?: 'AssignmentCompletionObjectType', id: any, completion_status: AssignmentAssignmentCompletionCompletionStatusChoices, submitted_at?: any | null, evaluation_submitted_at?: any | null, evaluation_grade?: number | null, evaluation_points?: number | null, completion_data?: any | null } | null } | null };
|
||||||
|
|
||||||
|
export type AttendanceCheckQueryQueryVariables = Exact<{
|
||||||
|
courseSessionId: Scalars['ID']['input'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type AttendanceCheckQueryQuery = { __typename?: 'Query', course_session_attendance_course?: { __typename?: 'CourseSessionAttendanceCourseType', id: string, attendance_user_list?: Array<{ __typename?: 'AttendanceUserType', user_id: any, status: AttendanceUserStatus } | null> | null } | null };
|
||||||
|
|
||||||
export type AssignmentCompletionQueryQueryVariables = Exact<{
|
export type AssignmentCompletionQueryQueryVariables = Exact<{
|
||||||
assignmentId: Scalars['ID']['input'];
|
assignmentId: Scalars['ID']['input'];
|
||||||
courseSessionId: Scalars['ID']['input'];
|
courseSessionId: Scalars['ID']['input'];
|
||||||
|
|
@ -362,6 +377,8 @@ export type CourseQueryQuery = { __typename?: 'Query', course?: { __typename?: '
|
||||||
|
|
||||||
|
|
||||||
export const SendFeedbackMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendFeedbackMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SendFeedbackInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"send_feedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feedback_response"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"messages"}}]}}]}}]}}]} as unknown as DocumentNode<SendFeedbackMutationMutation, SendFeedbackMutationMutationVariables>;
|
export const SendFeedbackMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SendFeedbackMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SendFeedbackInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"send_feedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feedback_response"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"messages"}}]}}]}}]}}]} as unknown as DocumentNode<SendFeedbackMutationMutation, SendFeedbackMutationMutationVariables>;
|
||||||
|
export const AttendanceCheckMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AttendanceCheckMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"attendanceCourseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"attendanceUserList"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AttendanceUserInputType"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"update_course_session_attendance_course_users"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"attendanceCourseId"}}},{"kind":"Argument","name":{"kind":"Name","value":"attendance_user_list"},"value":{"kind":"Variable","name":{"kind":"Name","value":"attendanceUserList"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course_session_attendance_course"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"attendance_user_list"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user_id"}},{"kind":"Field","name":{"kind":"Name","value":"first_name"}},{"kind":"Field","name":{"kind":"Name","value":"last_name"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]}}]} as unknown as DocumentNode<AttendanceCheckMutationMutation, AttendanceCheckMutationMutationVariables>;
|
||||||
export const UpsertAssignmentCompletionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpsertAssignmentCompletion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AssignmentCompletionStatus"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"upsert_assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_data_string"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_grade"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_points"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]}}]} as unknown as DocumentNode<UpsertAssignmentCompletionMutation, UpsertAssignmentCompletionMutationVariables>;
|
export const UpsertAssignmentCompletionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpsertAssignmentCompletion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"AssignmentCompletionStatus"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"upsert_assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionStatus"}}},{"kind":"Argument","name":{"kind":"Name","value":"completion_data_string"},"value":{"kind":"Variable","name":{"kind":"Name","value":"completionDataString"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_grade"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationGrade"}}},{"kind":"Argument","name":{"kind":"Name","value":"evaluation_points"},"value":{"kind":"Variable","name":{"kind":"Name","value":"evaluationPoints"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]}}]} as unknown as DocumentNode<UpsertAssignmentCompletionMutation, UpsertAssignmentCompletionMutationVariables>;
|
||||||
|
export const AttendanceCheckQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"attendanceCheckQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course_session_attendance_course"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"attendance_user_list"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user_id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]} as unknown as DocumentNode<AttendanceCheckQueryQuery, AttendanceCheckQueryQueryVariables>;
|
||||||
export const AssignmentCompletionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"assignmentCompletionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"effort_required"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_description"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_document_url"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_tasks"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"intro_text"}},{"kind":"Field","name":{"kind":"Name","value":"performance_objectives"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tasks"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"translation_key"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]} as unknown as DocumentNode<AssignmentCompletionQueryQuery, AssignmentCompletionQueryQueryVariables>;
|
export const AssignmentCompletionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"assignmentCompletionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"assignment_type"}},{"kind":"Field","name":{"kind":"Name","value":"content_type"}},{"kind":"Field","name":{"kind":"Name","value":"effort_required"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_description"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_document_url"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_tasks"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"intro_text"}},{"kind":"Field","name":{"kind":"Name","value":"performance_objectives"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tasks"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"translation_key"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_completion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"assignment_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentId"}}},{"kind":"Argument","name":{"kind":"Name","value":"course_session_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseSessionId"}}},{"kind":"Argument","name":{"kind":"Name","value":"assignment_user_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"assignmentUserId"}}},{"kind":"Argument","name":{"kind":"Name","value":"learning_content_page_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"learningContentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"completion_status"}},{"kind":"Field","name":{"kind":"Name","value":"submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_submitted_at"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"assignment_user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_grade"}},{"kind":"Field","name":{"kind":"Name","value":"evaluation_points"}},{"kind":"Field","name":{"kind":"Name","value":"completion_data"}}]}}]}}]} as unknown as DocumentNode<AssignmentCompletionQueryQuery, AssignmentCompletionQueryQueryVariables>;
|
||||||
export const CourseQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"courseQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"category_name"}},{"kind":"Field","name":{"kind":"Name","value":"learning_path"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<CourseQueryQuery, CourseQueryQueryVariables>;
|
export const CourseQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"courseQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"course"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"category_name"}},{"kind":"Field","name":{"kind":"Name","value":"learning_path"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<CourseQueryQuery, CourseQueryQueryVariables>;
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import schema from "../gql/minifiedSchema.json";
|
|
||||||
|
|
||||||
import { devtoolsExchange } from "@urql/devtools";
|
import { devtoolsExchange } from "@urql/devtools";
|
||||||
import { cacheExchange } from "@urql/exchange-graphcache";
|
import { cacheExchange } from "@urql/exchange-graphcache";
|
||||||
import { Client, fetchExchange } from "@urql/vue";
|
import { Client, fetchExchange } from "@urql/vue";
|
||||||
|
import schema from "../gql/minifiedSchema.json";
|
||||||
import {
|
import {
|
||||||
AssignmentCompletionMutation,
|
AssignmentCompletionMutation,
|
||||||
AssignmentCompletionObjectType,
|
AssignmentCompletionObjectType,
|
||||||
|
|
@ -16,6 +15,9 @@ export const graphqlClient = new Client({
|
||||||
devtoolsExchange,
|
devtoolsExchange,
|
||||||
cacheExchange({
|
cacheExchange({
|
||||||
schema: schema,
|
schema: schema,
|
||||||
|
keys: {
|
||||||
|
AttendanceUserType: (data) => data?.user_id?.toString() ?? null,
|
||||||
|
},
|
||||||
updates: {
|
updates: {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,28 @@
|
||||||
import { graphql } from "@/gql";
|
import { graphql } from "@/gql";
|
||||||
|
|
||||||
|
export const ATTENDANCE_CHECK_MUTATION = graphql(`
|
||||||
|
mutation AttendanceCheckMutation(
|
||||||
|
$attendanceCourseId: ID!
|
||||||
|
$attendanceUserList: [AttendanceUserInputType]!
|
||||||
|
) {
|
||||||
|
update_course_session_attendance_course_users(
|
||||||
|
id: $attendanceCourseId
|
||||||
|
attendance_user_list: $attendanceUserList
|
||||||
|
) {
|
||||||
|
course_session_attendance_course {
|
||||||
|
id
|
||||||
|
attendance_user_list {
|
||||||
|
user_id
|
||||||
|
first_name
|
||||||
|
last_name
|
||||||
|
email
|
||||||
|
status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
export const UPSERT_ASSIGNMENT_COMPLETION_MUTATION = graphql(`
|
export const UPSERT_ASSIGNMENT_COMPLETION_MUTATION = graphql(`
|
||||||
mutation UpsertAssignmentCompletion(
|
mutation UpsertAssignmentCompletion(
|
||||||
$assignmentId: ID!
|
$assignmentId: ID!
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,17 @@
|
||||||
import { graphql } from "@/gql";
|
import { graphql } from "@/gql";
|
||||||
|
|
||||||
|
export const ATTENDANCE_CHECK_QUERY = graphql(`
|
||||||
|
query attendanceCheckQuery($courseSessionId: ID!) {
|
||||||
|
course_session_attendance_course(id: $courseSessionId) {
|
||||||
|
id
|
||||||
|
attendance_user_list {
|
||||||
|
user_id
|
||||||
|
status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
export const ASSIGNMENT_COMPLETION_QUERY = graphql(`
|
export const ASSIGNMENT_COMPLETION_QUERY = graphql(`
|
||||||
query assignmentCompletionQuery(
|
query assignmentCompletionQuery(
|
||||||
$assignmentId: ID!
|
$assignmentId: ID!
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export function i18nextInit() {
|
||||||
"7518c269-cbf7-4d25-bc5c-6ceba2a8b74b",
|
"7518c269-cbf7-4d25-bc5c-6ceba2a8b74b",
|
||||||
apiKey: import.meta.env.DEV ? import.meta.env.VITE_LOCIZE_API_KEY : undefined,
|
apiKey: import.meta.env.DEV ? import.meta.env.VITE_LOCIZE_API_KEY : undefined,
|
||||||
fallbackLng: "de",
|
fallbackLng: "de",
|
||||||
allowedAddOrUpdateHosts: ["localhost"],
|
allowedAddOrUpdateHosts: ["localhost", "127.0.0.1"],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,21 @@
|
||||||
{
|
{
|
||||||
|
"Anwesenheit Präsenzkurse": "Anwesenheit Präsenzkurse",
|
||||||
|
"Anwesenheit bestätigen": "Anwesenheit bestätigen",
|
||||||
|
"Anwesenheit prüfen": "Anwesenheit prüfen",
|
||||||
|
"Anwesenheitskontrolle Präsenzkurse": "Anwesenheitskontrolle Präsenzkurse",
|
||||||
"Benutzername": "Benutzername",
|
"Benutzername": "Benutzername",
|
||||||
|
"Ergebnisse anschauen": "Ergebnisse anschauen",
|
||||||
|
"Feedback": "Feedback",
|
||||||
|
"Feedback anschauen": "Feedback anschauen",
|
||||||
|
"Hier überprüfst und bestätigst du die Anwesenheit deiner Teilnehmenden": [],
|
||||||
"MS Teams öffnen": "MS Teams öffnen",
|
"MS Teams öffnen": "MS Teams öffnen",
|
||||||
|
"Nächste Termine": "Nächste Termine",
|
||||||
"Passwort": "Passwort",
|
"Passwort": "Passwort",
|
||||||
|
"Status anschauen": "Status anschauen",
|
||||||
|
"TODO: Nächste Termine": "TODO: Nächste Termine",
|
||||||
"Trainerunterlagen": "Trainerunterlagen",
|
"Trainerunterlagen": "Trainerunterlagen",
|
||||||
|
"Vorbereitungsauftrag": "Vorbereitungsauftrag",
|
||||||
|
"Wissens - und Verständnisfragen": "Wissens - und Verständnisfragen",
|
||||||
"Zur Zeit sind keine Termine vorhanden": "Zur Zeit sind keine Termine vorhanden",
|
"Zur Zeit sind keine Termine vorhanden": "Zur Zeit sind keine Termine vorhanden",
|
||||||
"assignment": {
|
"assignment": {
|
||||||
"acceptConditionsDisclaimer": "Bedingungen akzeptieren und Ergebnisse abgeben",
|
"acceptConditionsDisclaimer": "Bedingungen akzeptieren und Ergebnisse abgeben",
|
||||||
|
|
@ -243,5 +256,9 @@
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"emailNotifications": "Email Benachrichtigungen"
|
"emailNotifications": "Email Benachrichtigungen"
|
||||||
}
|
},
|
||||||
|
"x von y Bewertungen freigegeben": "{{x}} von {{y}} Bewertungen freigegeben",
|
||||||
|
"x von y Ergebnisse abgegeben": "{{x}} von {{y}} Ergebnisse abgegeben",
|
||||||
|
"x von y Feedbacks abgegeben": "{{x}} von {{y}} Feedbacks abgegeben",
|
||||||
|
"x von y abgeschlossen": "{{x}} von {{y}} abgeschlossen"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,19 @@
|
||||||
:ratio="0.2"
|
:ratio="0.2"
|
||||||
/>
|
/>
|
||||||
<OpenFeedback
|
<OpenFeedback
|
||||||
v-else-if="openKeys.includes(question.key)"
|
v-else-if="
|
||||||
|
openKeys.includes(question.key) && feedbackData.questions[question.key]
|
||||||
|
"
|
||||||
class="mb-8 bg-white"
|
class="mb-8 bg-white"
|
||||||
:title="`${$t('feedback.questionTitle')} ${i + 1}`"
|
:title="`${$t('feedback.questionTitle')} ${i + 1}`"
|
||||||
:text="question.question"
|
:text="question.question"
|
||||||
:answers="feedbackData.questions[question.key].filter((a: string) => a !== '')"
|
:answers="feedbackData.questions[question.key].filter((a: string) => a !== '')"
|
||||||
></OpenFeedback>
|
></OpenFeedback>
|
||||||
<HorizontalBarChart
|
<HorizontalBarChart
|
||||||
v-else-if="horizontalChartKeys.includes(question.key)"
|
v-else-if="
|
||||||
|
horizontalChartKeys.includes(question.key) &&
|
||||||
|
feedbackData.questions[question.key]
|
||||||
|
"
|
||||||
class="mb-8 bg-white"
|
class="mb-8 bg-white"
|
||||||
:title="`${$t('feedback.questionTitle')} ${i}`"
|
:title="`${$t('feedback.questionTitle')} ${i}`"
|
||||||
:text="question.question"
|
:text="question.question"
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
||||||
import type { StatusCount, StatusCountKey } from "@/components/ui/ItProgress.vue";
|
import type { StatusCount } from "@/components/ui/ItProgress.vue";
|
||||||
import AssignmentSubmissionProgress from "@/pages/cockpit/assignmentsPage/AssignmentSubmissionProgress.vue";
|
import type { GradedUser } from "@/services/assignmentService";
|
||||||
import {
|
import {
|
||||||
findAssignmentDetail,
|
findAssignmentDetail,
|
||||||
loadAssignmentCompletionStatusData,
|
loadAssignmentCompletionStatusData,
|
||||||
} from "@/services/assignmentService";
|
} from "@/services/assignmentService";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
import type {
|
import type {
|
||||||
AssignmentCompletionStatus,
|
|
||||||
CourseSession,
|
CourseSession,
|
||||||
|
CourseSessionUser,
|
||||||
LearningContentAssignment,
|
LearningContentAssignment,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed, onMounted, reactive } from "vue";
|
import { computed, onMounted, reactive } from "vue";
|
||||||
|
import AssignmentSubmissionProgress from "@/pages/cockpit/cockpitPage/AssignmentSubmissionProgress.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSession: CourseSession;
|
courseSession: CourseSession;
|
||||||
|
|
@ -29,59 +30,53 @@ log.debug(
|
||||||
const cockpitStore = useCockpitStore();
|
const cockpitStore = useCockpitStore();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
statusByUser: [] as {
|
|
||||||
userStatus: AssignmentCompletionStatus;
|
|
||||||
progressStatus: StatusCountKey;
|
|
||||||
userId: string;
|
|
||||||
grade: number | null;
|
|
||||||
}[],
|
|
||||||
progressStatusCount: {} as StatusCount,
|
progressStatusCount: {} as StatusCount,
|
||||||
|
gradedUsers: [] as GradedUser[],
|
||||||
|
assignmentSubmittedUsers: [] as CourseSessionUser[],
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
state.statusByUser = await loadAssignmentCompletionStatusData(
|
const { gradedUsers, assignmentSubmittedUsers } =
|
||||||
props.learningContentAssignment.content_assignment_id,
|
await loadAssignmentCompletionStatusData(
|
||||||
props.courseSession.id
|
props.learningContentAssignment.content_assignment_id,
|
||||||
);
|
props.courseSession.id
|
||||||
|
);
|
||||||
|
state.gradedUsers = gradedUsers;
|
||||||
|
state.assignmentSubmittedUsers = assignmentSubmittedUsers;
|
||||||
});
|
});
|
||||||
|
|
||||||
function submissionStatusForUser(userId: string) {
|
|
||||||
return state.statusByUser.find((s) => s.userId === userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const assignmentDetail = computed(() =>
|
const assignmentDetail = computed(() =>
|
||||||
findAssignmentDetail(props.learningContentAssignment.content_assignment_id)
|
findAssignmentDetail(props.learningContentAssignment.content_assignment_id)
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="state.statusByUser.length">
|
<div>
|
||||||
<div class="text-large font-bold">
|
<h2 class="heading-2 font-bold">
|
||||||
{{ props.learningContentAssignment.title }}
|
{{ learningContentAssignment.title }}
|
||||||
|
</h2>
|
||||||
|
<div class="pt-1 underline">
|
||||||
|
Circle «{{ learningContentAssignment.parentCircle.title }}»
|
||||||
</div>
|
</div>
|
||||||
<div v-if="assignmentDetail">
|
<div v-if="assignmentDetail">
|
||||||
<span>
|
<span>
|
||||||
Abgabetermin:
|
{{ $t("Abgabetermin Ergebnisse:") }}
|
||||||
{{ dayjs(assignmentDetail.submission_deadline_start).format("DD.MM.YYYY") }}
|
{{ dayjs(assignmentDetail.submission_deadline_start).format("DD.MM.YYYY") }}
|
||||||
</span>
|
</span>
|
||||||
-
|
<template v-if="assignmentDetail.evaluation_deadline_start">
|
||||||
<span>
|
<br />
|
||||||
Freigabetermin:
|
<span v-if="assignmentDetail.evaluation_deadline_start">
|
||||||
{{ dayjs(assignmentDetail.evaluation_deadline_start).format("DD.MM.YYYY") }}
|
{{ $t("Freigabetermin Bewertungen:") }}
|
||||||
</span>
|
{{ dayjs(assignmentDetail.evaluation_deadline_start).format("DD.MM.YYYY") }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else>
|
||||||
<div>
|
{{ $t("Keine Auftragsdetails verfügbar.") }}
|
||||||
<a
|
|
||||||
:href="props.learningContentAssignment.frontend_url"
|
|
||||||
class="link"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Im Circle anzeigen
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
|
<!-- how to determine assignment-type? how to get AssignmentLearningContent? -->
|
||||||
<AssignmentSubmissionProgress
|
<AssignmentSubmissionProgress
|
||||||
:course-session="courseSession"
|
:course-session="courseSession"
|
||||||
:learning-content-assignment="learningContentAssignment"
|
:learning-content-assignment="learningContentAssignment"
|
||||||
|
|
@ -102,9 +97,7 @@ const assignmentDetail = computed(() =>
|
||||||
<section class="flex w-full justify-between px-8">
|
<section class="flex w-full justify-between px-8">
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
['EVALUATION_SUBMITTED'].includes(
|
state.gradedUsers.map((gradedUser) => gradedUser.user).includes(csu)
|
||||||
submissionStatusForUser(csu.user_id)?.userStatus ?? ''
|
|
||||||
)
|
|
||||||
"
|
"
|
||||||
class="flex items-center"
|
class="flex items-center"
|
||||||
>
|
>
|
||||||
|
|
@ -116,11 +109,7 @@ const assignmentDetail = computed(() =>
|
||||||
<div class="ml-2">Bewertung freigegeben</div>
|
<div class="ml-2">Bewertung freigegeben</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else-if="
|
v-else-if="state.assignmentSubmittedUsers.includes(csu)"
|
||||||
['EVALUATION_IN_PROGRESS', 'SUBMITTED'].includes(
|
|
||||||
submissionStatusForUser(csu.user_id)?.userStatus ?? ''
|
|
||||||
)
|
|
||||||
"
|
|
||||||
class="flex items-center"
|
class="flex items-center"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
@ -130,21 +119,27 @@ const assignmentDetail = computed(() =>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-2">Ergebnisse abgegeben</div>
|
<div class="ml-2">Ergebnisse abgegeben</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else></div>
|
|
||||||
|
|
||||||
<div v-if="submissionStatusForUser(csu.user_id)?.grade">
|
<div
|
||||||
Note: {{ submissionStatusForUser(csu.user_id)?.grade }}
|
v-if="
|
||||||
|
state.gradedUsers.map((gradedUser) => gradedUser.user).includes(csu)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Note:
|
||||||
|
{{
|
||||||
|
state.gradedUsers.find((u) => u.user.user_id === csu.user_id)?.grade
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<template #link>
|
<template #link>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="submissionStatusForUser(csu.user_id)?.progressStatus === 'SUCCESS'"
|
v-if="state.assignmentSubmittedUsers.includes(csu)"
|
||||||
:to="`/course/${props.courseSession.course.slug}/cockpit/assignment/${learningContentAssignment.content_assignment_id}/${csu.user_id}`"
|
:to="`/course/${props.courseSession.course.slug}/cockpit/assignment/${learningContentAssignment.content_assignment_id}/${csu.user_id}`"
|
||||||
class="w-full text-right underline"
|
class="w-full text-right underline"
|
||||||
data-cy="show-results"
|
data-cy="show-results"
|
||||||
>
|
>
|
||||||
Ergebnisse anzeigen
|
{{ $t("Ergebnisse anzeigen") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
</ItPersonRow>
|
</ItPersonRow>
|
||||||
|
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import type { StatusCount, StatusCountKey } from "@/components/ui/ItProgress.vue";
|
|
||||||
import ItProgress from "@/components/ui/ItProgress.vue";
|
|
||||||
import { loadAssignmentCompletionStatusData } from "@/services/assignmentService";
|
|
||||||
import type {
|
|
||||||
AssignmentCompletionStatus,
|
|
||||||
CourseSession,
|
|
||||||
LearningContentAssignment,
|
|
||||||
} from "@/types";
|
|
||||||
import { countBy } from "lodash";
|
|
||||||
import log from "loglevel";
|
|
||||||
import { onMounted, reactive } from "vue";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
courseSession: CourseSession;
|
|
||||||
learningContentAssignment: LearningContentAssignment;
|
|
||||||
showTitle: boolean;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
log.debug(
|
|
||||||
"AssignmentSubmissionProgress created",
|
|
||||||
props.learningContentAssignment.content_assignment_id
|
|
||||||
);
|
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
statusByUser: [] as {
|
|
||||||
userStatus: AssignmentCompletionStatus;
|
|
||||||
progressStatus: StatusCountKey;
|
|
||||||
userId: string;
|
|
||||||
}[],
|
|
||||||
progressStatusCount: {} as StatusCount,
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
state.statusByUser = await loadAssignmentCompletionStatusData(
|
|
||||||
props.learningContentAssignment.content_assignment_id,
|
|
||||||
props.courseSession.id
|
|
||||||
);
|
|
||||||
|
|
||||||
state.progressStatusCount = countBy(
|
|
||||||
state.statusByUser,
|
|
||||||
"progressStatus"
|
|
||||||
) as StatusCount;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div v-if="state.statusByUser.length">
|
|
||||||
<div v-if="showTitle">
|
|
||||||
{{ props.learningContentAssignment.title }}
|
|
||||||
</div>
|
|
||||||
<div><ItProgress :status-count="state.progressStatusCount" /></div>
|
|
||||||
<div class="text-gray-900" :class="{ 'text-gray-900': showTitle }">
|
|
||||||
{{ state.progressStatusCount.SUCCESS || 0 }} von
|
|
||||||
{{
|
|
||||||
(state.progressStatusCount.SUCCESS || 0) +
|
|
||||||
(state.progressStatusCount.UNKNOWN || 0)
|
|
||||||
}}
|
|
||||||
Lernenden haben ihre Ergebnisse eingereicht.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
|
|
@ -1,30 +1,31 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue";
|
import AssignmentDetails from "@/pages/cockpit/assignmentsPage/AssignmentDetails.vue";
|
||||||
import { calcLearningContentAssignments } from "@/services/assignmentService";
|
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
|
||||||
import { useUserStore } from "@/stores/user";
|
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { computed, onMounted } from "vue";
|
import { computed, onMounted } from "vue";
|
||||||
|
import { useUserStore } from "@/stores/user";
|
||||||
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
|
import { calcLearningContentAssignments } from "@/services/assignmentService";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSlug: string;
|
courseSlug: string;
|
||||||
|
assignmentId: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
log.debug("AssignmentsPage created", props.courseSlug);
|
log.debug("AssignmentsPage created", props.courseSlug);
|
||||||
|
|
||||||
const learningPathStore = useLearningPathStore();
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const courseSession = useCurrentCourseSession();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const learningPathStore = useLearningPathStore();
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("AssignmentsPage mounted");
|
log.debug("AssignmentsPage mounted");
|
||||||
});
|
});
|
||||||
|
|
||||||
const learningContentAssignments = computed(() => {
|
const learningContentAssignment = computed(() => {
|
||||||
return calcLearningContentAssignments(
|
return calcLearningContentAssignments(
|
||||||
learningPathStore.learningPathForUser(courseSession.value.course.slug, userStore.id)
|
learningPathStore.learningPathForUser(courseSession.value.course.slug, userStore.id)
|
||||||
);
|
).filter((lc) => lc.id.toString() === props.assignmentId)[0];
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -40,20 +41,13 @@ const learningContentAssignments = computed(() => {
|
||||||
<span>{{ $t("general.back") }}</span>
|
<span>{{ $t("general.back") }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</nav>
|
</nav>
|
||||||
<header>
|
|
||||||
<h2 class="heading-2 mb-4 flex items-center gap-2">
|
|
||||||
<it-icon-assignment-large class="h-16 w-16"></it-icon-assignment-large>
|
|
||||||
<div>Geleitete Fallarbeiten</div>
|
|
||||||
</h2>
|
|
||||||
</header>
|
|
||||||
<main>
|
<main>
|
||||||
<div v-for="lca in learningContentAssignments" :key="lca.id">
|
<div class="bg-white p-6">
|
||||||
<div class="bg-white p-6">
|
<AssignmentDetails
|
||||||
<AssignmentDetails
|
v-if="learningContentAssignment"
|
||||||
:course-session="courseSession"
|
:course-session="courseSession"
|
||||||
:learning-content-assignment="lca"
|
:learning-content-assignment="learningContentAssignment"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
|
||||||
|
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||||
|
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
|
import type { AttendanceUserStatus } from "@/gql/graphql";
|
||||||
|
import { ATTENDANCE_CHECK_MUTATION } from "@/graphql/mutations";
|
||||||
|
import { ATTENDANCE_CHECK_QUERY } from "@/graphql/queries";
|
||||||
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
|
import type { DropdownSelectable } from "@/types";
|
||||||
|
import { useMutation, useQuery } from "@urql/vue";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import log from "loglevel";
|
||||||
|
import { computed, reactive, watch } from "vue";
|
||||||
|
import { useTranslation } from "i18next-vue";
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const cockpitStore = useCockpitStore();
|
||||||
|
const courseSession = useCurrentCourseSession();
|
||||||
|
const attendanceMutation = useMutation(ATTENDANCE_CHECK_MUTATION);
|
||||||
|
|
||||||
|
const attendanceCourses = computed(() => {
|
||||||
|
return courseSession.value.attendance_courses;
|
||||||
|
});
|
||||||
|
|
||||||
|
const presenceCoursesDropdownOptions = computed(() => {
|
||||||
|
return attendanceCourses.value.map(
|
||||||
|
(attendanceCourse) =>
|
||||||
|
({
|
||||||
|
id: attendanceCourse.id,
|
||||||
|
name: `${t("Präsenzkurs")} ${dayjs(attendanceCourse.start).format(
|
||||||
|
"DD.MM.YYYY"
|
||||||
|
)}`,
|
||||||
|
} as DropdownSelectable)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const attendanceCourseSelected = computed(
|
||||||
|
() => state.attendanceCourseSelected.id != "-1"
|
||||||
|
);
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
userPresence: new Map<string, boolean>(),
|
||||||
|
attendanceCourseSelected: presenceCoursesDropdownOptions.value[0],
|
||||||
|
disclaimerConfirmed: false,
|
||||||
|
attendanceSaved: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const attendanceQuery = useQuery({
|
||||||
|
query: ATTENDANCE_CHECK_QUERY,
|
||||||
|
pause: true,
|
||||||
|
variables: {
|
||||||
|
courseSessionId: state.attendanceCourseSelected.id.toString(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
type UserPresence = {
|
||||||
|
user_id: string;
|
||||||
|
status: AttendanceUserStatus;
|
||||||
|
};
|
||||||
|
const attendanceUserList: UserPresence[] = Array.from(state.userPresence.keys()).map(
|
||||||
|
(key) => ({
|
||||||
|
user_id: key,
|
||||||
|
status: state.userPresence.get(key) ? "PRESENT" : "ABSENT",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const res = await attendanceMutation.executeMutation({
|
||||||
|
attendanceCourseId: state.attendanceCourseSelected.id.toString(),
|
||||||
|
attendanceUserList: attendanceUserList,
|
||||||
|
});
|
||||||
|
if (res.error) {
|
||||||
|
log.error("Could not submit attendance check: ", res.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.disclaimerConfirmed = false;
|
||||||
|
state.attendanceSaved = true;
|
||||||
|
log.info("Attendance check submitted: ", res);
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadAttendanceData = async () => {
|
||||||
|
const res = await attendanceQuery.executeQuery();
|
||||||
|
const attendanceUserList =
|
||||||
|
res?.data?.value?.course_session_attendance_course?.attendance_user_list ?? [];
|
||||||
|
for (const user of attendanceUserList) {
|
||||||
|
if (!user) continue;
|
||||||
|
state.userPresence.set(user.user_id.toString(), user.status === "PRESENT");
|
||||||
|
}
|
||||||
|
if (attendanceUserList.length !== 0) {
|
||||||
|
state.attendanceSaved = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadAttendanceData();
|
||||||
|
watch(state.attendanceCourseSelected, () => {
|
||||||
|
loadAttendanceData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="bg-gray-200">
|
||||||
|
<div class="container-large">
|
||||||
|
<nav class="py-4 pb-4">
|
||||||
|
<router-link
|
||||||
|
class="btn-text inline-flex items-center pl-0"
|
||||||
|
:to="`/course/${courseSession.course.slug}/cockpit`"
|
||||||
|
>
|
||||||
|
<it-icon-arrow-left />
|
||||||
|
<span>{{ $t("general.back") }}</span>
|
||||||
|
</router-link>
|
||||||
|
</nav>
|
||||||
|
<div class="pb-4 text-xl font-bold">{{ $t("Anwesenheit Präsenzkurse") }}</div>
|
||||||
|
<div class="flex flex-row justify-between bg-white p-6">
|
||||||
|
<ItDropdownSelect
|
||||||
|
v-model="state.attendanceCourseSelected"
|
||||||
|
:items="presenceCoursesDropdownOptions ?? []"
|
||||||
|
></ItDropdownSelect>
|
||||||
|
<div v-if="!state.attendanceSaved" class="flex flex-row items-center">
|
||||||
|
<ItCheckbox
|
||||||
|
:disabled="!attendanceCourseSelected"
|
||||||
|
:checkbox-item="{
|
||||||
|
value: true,
|
||||||
|
checked: state.disclaimerConfirmed,
|
||||||
|
}"
|
||||||
|
@toggle="state.disclaimerConfirmed = !state.disclaimerConfirmed"
|
||||||
|
></ItCheckbox>
|
||||||
|
<p class="w-64 pr-4 text-sm">
|
||||||
|
{{
|
||||||
|
$t(
|
||||||
|
"Ich will die Anwesenheit der untenstehenden Personen definitiv bestätigen."
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
class="btn-primary"
|
||||||
|
:disabled="!state.disclaimerConfirmed"
|
||||||
|
@click="onSubmit"
|
||||||
|
>
|
||||||
|
{{ $t("Anwesenheit bestätigen") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div v-else class="self-center">
|
||||||
|
<p class="text-base">
|
||||||
|
{{ $t("Die Anwesenheit wurde definitiv bestätigt.") }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 flex flex-col bg-white p-6">
|
||||||
|
<div
|
||||||
|
v-for="(csu, index) in cockpitStore.courseSessionUsers"
|
||||||
|
:key="csu.user_id + csu.session_title"
|
||||||
|
>
|
||||||
|
<ItPersonRow
|
||||||
|
:name="`${csu.first_name} ${csu.last_name}`"
|
||||||
|
:avatar-url="csu.avatar_url"
|
||||||
|
:class="0 === index ? 'border-none' : ''"
|
||||||
|
>
|
||||||
|
<template #leading>
|
||||||
|
<ItCheckbox
|
||||||
|
:disabled="!attendanceCourseSelected || state.attendanceSaved"
|
||||||
|
:checkbox-item="{
|
||||||
|
value: true,
|
||||||
|
checked: state.userPresence.get(csu.user_id.toString()) as boolean,
|
||||||
|
}"
|
||||||
|
@toggle="
|
||||||
|
state.userPresence.set(
|
||||||
|
csu.user_id.toString(),
|
||||||
|
!state.userPresence.get(csu.user_id.toString())
|
||||||
|
)
|
||||||
|
"
|
||||||
|
></ItCheckbox>
|
||||||
|
</template>
|
||||||
|
</ItPersonRow>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { StatusCount, StatusCountKey } from "@/components/ui/ItProgress.vue";
|
||||||
|
import ItProgress from "@/components/ui/ItProgress.vue";
|
||||||
|
import { loadAssignmentCompletionStatusData } from "@/services/assignmentService";
|
||||||
|
import type {
|
||||||
|
AssignmentCompletionStatus,
|
||||||
|
CourseSession,
|
||||||
|
LearningContentAssignment,
|
||||||
|
} from "@/types";
|
||||||
|
import log from "loglevel";
|
||||||
|
import { onMounted, reactive } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
courseSession: CourseSession;
|
||||||
|
learningContentAssignment: LearningContentAssignment;
|
||||||
|
showTitle: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
log.debug(
|
||||||
|
"AssignmentSubmissionProgress created",
|
||||||
|
props.learningContentAssignment.content_assignment_id
|
||||||
|
);
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
statusByUser: [] as {
|
||||||
|
userStatus: AssignmentCompletionStatus;
|
||||||
|
progressStatus: StatusCountKey;
|
||||||
|
userId: number;
|
||||||
|
}[],
|
||||||
|
submissionProgressStatusCount: {} as StatusCount,
|
||||||
|
gradingProgressStatusCount: {} as StatusCount,
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const { assignmentSubmittedUsers, gradedUsers, total } =
|
||||||
|
await loadAssignmentCompletionStatusData(
|
||||||
|
props.learningContentAssignment.content_assignment_id,
|
||||||
|
props.courseSession.id
|
||||||
|
);
|
||||||
|
|
||||||
|
state.submissionProgressStatusCount = {
|
||||||
|
SUCCESS: assignmentSubmittedUsers.length,
|
||||||
|
UNKNOWN: total - assignmentSubmittedUsers.length,
|
||||||
|
FAIL: 0,
|
||||||
|
};
|
||||||
|
state.gradingProgressStatusCount = {
|
||||||
|
SUCCESS: gradedUsers.length,
|
||||||
|
UNKNOWN: total - gradedUsers.length,
|
||||||
|
FAIL: 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const doneCount = (status: StatusCount) => {
|
||||||
|
return status.SUCCESS || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const totalCount = (status: StatusCount) => {
|
||||||
|
return doneCount(status) + status.UNKNOWN || 0;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="showTitle">
|
||||||
|
{{ props.learningContentAssignment.title }}
|
||||||
|
</div>
|
||||||
|
<ItProgress :status-count="state.submissionProgressStatusCount" />
|
||||||
|
<div class="text-gray-900">
|
||||||
|
<div v-if="props.learningContentAssignment.assignment_type === 'CASEWORK'">
|
||||||
|
{{
|
||||||
|
$t("x von y Ergebnisse abgegeben", {
|
||||||
|
x: doneCount(state.submissionProgressStatusCount),
|
||||||
|
y: totalCount(state.submissionProgressStatusCount),
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
<br />
|
||||||
|
{{
|
||||||
|
$t("x von y Bewertungen freigegeben", {
|
||||||
|
x: doneCount(state.gradingProgressStatusCount),
|
||||||
|
y: totalCount(state.gradingProgressStatusCount),
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="
|
||||||
|
props.learningContentAssignment.assignment_type === 'PREP_ASSIGNMENT'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
$t("x von y abgeschlossen", {
|
||||||
|
x: doneCount(state.submissionProgressStatusCount),
|
||||||
|
y: totalCount(state.submissionProgressStatusCount),
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div v-else-if="props.learningContentAssignment.assignment_type === 'REFLECTION'">
|
||||||
|
{{
|
||||||
|
$t("x von y abgeschlossen", {
|
||||||
|
x: doneCount(state.submissionProgressStatusCount),
|
||||||
|
y: totalCount(state.submissionProgressStatusCount),
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import AssignmentSubmissionProgress from "@/pages/cockpit/assignmentsPage/AssignmentSubmissionProgress.vue";
|
|
||||||
import { calcLearningContentAssignments } from "@/services/assignmentService";
|
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
|
||||||
import { useUserStore } from "@/stores/user";
|
|
||||||
import type { CourseSession } from "@/types";
|
|
||||||
import log from "loglevel";
|
|
||||||
import { computed } from "vue";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
courseSession: CourseSession;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
log.debug("AssignmentsTile created", props.courseSession.id);
|
|
||||||
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const cockpitStore = useCockpitStore();
|
|
||||||
const learningPathStore = useLearningPathStore();
|
|
||||||
|
|
||||||
const learningContentAssignments = computed(() => {
|
|
||||||
// TODO: filter by selected circle
|
|
||||||
return calcLearningContentAssignments(
|
|
||||||
learningPathStore.learningPathForUser(props.courseSession.course.slug, userStore.id)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="bg-white px-6 py-5">
|
|
||||||
<div v-if="cockpitStore.courseSessionUsers">
|
|
||||||
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
|
||||||
<it-icon-assignment-large class="h-16 w-16"></it-icon-assignment-large>
|
|
||||||
<div>Geleitete Fallarbeiten</div>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div v-for="lca in learningContentAssignments" :key="lca.id" class="mb-4">
|
|
||||||
<AssignmentSubmissionProgress
|
|
||||||
:show-title="true"
|
|
||||||
:course-session="props.courseSession"
|
|
||||||
:learning-content-assignment="lca"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-6">
|
|
||||||
<router-link
|
|
||||||
:to="`/course/${props.courseSession.course.slug}/cockpit/assignment`"
|
|
||||||
class="link"
|
|
||||||
>
|
|
||||||
Alle anzeigen
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
|
import type { Dayjs } from "dayjs";
|
||||||
|
import type { DueDate } from "@/types";
|
||||||
|
|
||||||
|
const courseSession = useCurrentCourseSession();
|
||||||
|
const dueDates = courseSession.value.due_dates.slice(0, 2);
|
||||||
|
|
||||||
|
const formatDate = (date: Dayjs) => {
|
||||||
|
return date.format("DD.MM.YYYY");
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDateLine = (dueDate: DueDate) => {
|
||||||
|
let line = `${formatDate(dueDate.start)} - ${dueDate.learning_content_description}`;
|
||||||
|
if (dueDate.description.length !== 0) {
|
||||||
|
line += `: ${dueDate.description}`;
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex flex-col space-y-2">
|
||||||
|
<h3 class="heading-3">{{ $t("Nächste Termine") }}</h3>
|
||||||
|
<div
|
||||||
|
v-for="dueDate in dueDates"
|
||||||
|
:key="dueDate.id"
|
||||||
|
class="border-t border-gray-500 pt-2"
|
||||||
|
>
|
||||||
|
{{ formatDateLine(dueDate) }}
|
||||||
|
</div>
|
||||||
|
<div v-if="dueDates.length === 0">{{ $t("dueDates.noDueDatesAvailable") }}</div>
|
||||||
|
<a class="border-t border-gray-500 pt-8 underline" href="">
|
||||||
|
{{ $t("dueDates.showAllDueDates") }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import FeedbackSummary from "@/components/feedback/feedbackSummary.vue";
|
|
||||||
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
import LearningPathDiagram from "@/components/learningPath/LearningPathDiagram.vue";
|
||||||
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
import ItPersonRow from "@/components/ui/ItPersonRow.vue";
|
||||||
import type { LearningPath } from "@/services/learningPath";
|
import type { LearningPath } from "@/services/learningPath";
|
||||||
|
|
||||||
import { useCurrentCourseSession } from "@/composables";
|
import { useCurrentCourseSession } from "@/composables";
|
||||||
import AssignmentsTile from "@/pages/cockpit/cockpitPage/AssignmentsTile.vue";
|
import SubmissionsOverview from "@/pages/cockpit/cockpitPage/SubmissionsOverview.vue";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
import { useCompetenceStore } from "@/stores/competence";
|
import { useCompetenceStore } from "@/stores/competence";
|
||||||
import { useLearningPathStore } from "@/stores/learningPath";
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
|
|
@ -13,6 +12,7 @@ import { useUserStore } from "@/stores/user";
|
||||||
import groupBy from "lodash/groupBy";
|
import groupBy from "lodash/groupBy";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
import CockpitDates from "@/pages/cockpit/cockpitPage/CockpitDates.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSlug: string;
|
courseSlug: string;
|
||||||
|
|
@ -60,7 +60,7 @@ const circles = computed(() => {
|
||||||
const selectedCirclesTitles = computed(() => {
|
const selectedCirclesTitles = computed(() => {
|
||||||
return circles.value
|
return circles.value
|
||||||
.filter((c) => cockpitStore.selectedCircles.includes(c.translation_key))
|
.filter((c) => cockpitStore.selectedCircles.includes(c.translation_key))
|
||||||
.map((c) => c.title);
|
.map((c) => c.title) as string[];
|
||||||
});
|
});
|
||||||
|
|
||||||
function setActiveClasses(translationKey: string) {
|
function setActiveClasses(translationKey: string) {
|
||||||
|
|
@ -73,26 +73,29 @@ function setActiveClasses(translationKey: string) {
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-gray-200">
|
<div class="bg-gray-200">
|
||||||
<div class="container-large">
|
<div class="container-large">
|
||||||
<div class="mb-9 flex items-center lg:flex-row">
|
<div class="mb-9 flex items-end justify-between">
|
||||||
<h1 class="heading-3">{{ $t("general.circles") }}:</h1>
|
<h1>Cockpit</h1>
|
||||||
<ul class="ml-4 flex flex-row text-base font-bold leading-7">
|
<div class="flex flex-row">
|
||||||
<li
|
<p class="text-base">{{ $t("general.circles") }}:</p>
|
||||||
v-for="circle in circles"
|
<ul class="ml-4 flex flex-row text-base font-bold leading-7">
|
||||||
:key="circle.translation_key"
|
<li
|
||||||
class="mr-4 last:mr-0"
|
v-for="circle in circles"
|
||||||
>
|
:key="circle.translation_key"
|
||||||
<button
|
class="mr-4 last:mr-0"
|
||||||
class="mr-4 rounded-full border-2 border-blue-900 px-4 last:mr-0"
|
|
||||||
:class="setActiveClasses(circle.translation_key)"
|
|
||||||
@click="cockpitStore.toggleCircleSelection(circle.translation_key)"
|
|
||||||
>
|
>
|
||||||
{{ circle.title }}
|
<button
|
||||||
</button>
|
class="mr-4 rounded-full border-2 border-blue-900 px-4 last:mr-0"
|
||||||
</li>
|
:class="setActiveClasses(circle.translation_key)"
|
||||||
</ul>
|
@click="cockpitStore.toggleCircleSelection(circle.translation_key)"
|
||||||
|
>
|
||||||
|
{{ circle.title }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Status -->
|
<!-- Status -->
|
||||||
<div class="mb-4 grid grid-rows-2 gap-4 lg:grid-cols-2 lg:grid-rows-none">
|
<div class="mb-4 grid grid-rows-3 gap-4 lg:grid-cols-3 lg:grid-rows-none">
|
||||||
<div class="flex flex-col justify-between bg-white px-6 py-5">
|
<div class="flex flex-col justify-between bg-white px-6 py-5">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
||||||
|
|
@ -112,21 +115,39 @@ function setActiveClasses(translationKey: string) {
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AssignmentsTile :course-session="courseSession" />
|
<div class="flex flex-col justify-between bg-white p-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="heading-3 mb-4 flex items-center gap-2">
|
||||||
|
{{ $t("Anwesenheitskontrolle Präsenzkurse") }}
|
||||||
|
</h3>
|
||||||
|
<div class="mb-4">
|
||||||
|
{{
|
||||||
|
$t(
|
||||||
|
"Hier überprüfst und bestätigst du die Anwesenheit deiner Teilnehmenden."
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<router-link
|
||||||
|
:to="`/course/${props.courseSlug}/cockpit/attendanceCheck`"
|
||||||
|
class="btn-secondary min-w-min"
|
||||||
|
>
|
||||||
|
{{ $t("Anwesenheit prüfen") }}
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white p-6">
|
||||||
|
<CockpitDates></CockpitDates>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Feedback -->
|
<SubmissionsOverview
|
||||||
<FeedbackSummary
|
:course-session="courseSession"
|
||||||
:selcted-circles="cockpitStore.selectedCircles || []"
|
:selected-circles="selectedCirclesTitles"
|
||||||
:circles="
|
></SubmissionsOverview>
|
||||||
learningPathStore.learningPathForUser(props.courseSlug, userStore.id)
|
<div class="pt-4">
|
||||||
?.circles || []
|
|
||||||
"
|
|
||||||
:course-id="courseSession.course.id"
|
|
||||||
:url="courseSession.course_url || ''"
|
|
||||||
></FeedbackSummary>
|
|
||||||
<div>
|
|
||||||
<!-- progress -->
|
<!-- progress -->
|
||||||
<div v-if="cockpitStore.courseSessionUsers?.length" class="bg-white p-6">
|
<div v-if="cockpitStore.courseSessionUsers" class="bg-white p-6">
|
||||||
<h1 class="heading-3 mb-5">{{ $t("cockpit.progress") }}</h1>
|
<h1 class="heading-3 mb-5">{{ $t("cockpit.progress") }}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
<ItPersonRow
|
<ItPersonRow
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { CourseSession } from "@/types";
|
||||||
|
import log from "loglevel";
|
||||||
|
import { computed, onMounted, ref } from "vue";
|
||||||
|
import ItProgress from "@/components/ui/ItProgress.vue";
|
||||||
|
import { itGet } from "@/fetchHelpers";
|
||||||
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
courseSession: CourseSession;
|
||||||
|
circleId: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
log.debug("FeedbackSubmissionProgress created");
|
||||||
|
|
||||||
|
const cockpitStore = useCockpitStore();
|
||||||
|
|
||||||
|
const completeFeedbacks = ref(0);
|
||||||
|
|
||||||
|
const numFeedbacks = computed(() => {
|
||||||
|
return cockpitStore.courseSessionUsers?.length ?? 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const data = await itGet(
|
||||||
|
`/api/core/feedback/${props.courseSession.course.id}/${props.circleId}/`
|
||||||
|
);
|
||||||
|
completeFeedbacks.value = data.amount;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ItProgress
|
||||||
|
:status-count="{
|
||||||
|
SUCCESS: completeFeedbacks,
|
||||||
|
UNKNOWN: numFeedbacks - completeFeedbacks,
|
||||||
|
FAIL: 0,
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div class="text-gray-900">
|
||||||
|
{{
|
||||||
|
$t("x von y Feedbacks abgegeben", {
|
||||||
|
x: completeFeedbacks,
|
||||||
|
y: numFeedbacks,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,163 @@
|
||||||
|
2
|
||||||
|
<script setup lang="ts">
|
||||||
|
import AssignmentSubmissionProgress from "@/pages/cockpit/cockpitPage/AssignmentSubmissionProgress.vue";
|
||||||
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
|
import { useLearningPathStore } from "@/stores/learningPath";
|
||||||
|
import { useUserStore } from "@/stores/user";
|
||||||
|
import type {
|
||||||
|
CourseSession,
|
||||||
|
LearningContent,
|
||||||
|
LearningContentAssignment,
|
||||||
|
} from "@/types";
|
||||||
|
import log from "loglevel";
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { useTranslation } from "i18next-vue";
|
||||||
|
import FeedbackSubmissionProgress from "@/pages/cockpit/cockpitPage/FeedbackSubmissionProgress.vue";
|
||||||
|
import { learningContentTypeData } from "@/utils/typeMaps";
|
||||||
|
|
||||||
|
interface Submittable {
|
||||||
|
id: number;
|
||||||
|
circleName: string;
|
||||||
|
frontendUrl: string;
|
||||||
|
title: string;
|
||||||
|
showDetailsText: string;
|
||||||
|
detailsLink: string;
|
||||||
|
content: LearningContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
courseSession: CourseSession;
|
||||||
|
selectedCircles: string[];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
log.debug("SubmissionsOverview created", props.courseSession.id);
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const cockpitStore = useCockpitStore();
|
||||||
|
const learningPathStore = useLearningPathStore();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const submittables = computed(() => {
|
||||||
|
const learningPath = learningPathStore.learningPathForUser(
|
||||||
|
props.courseSession.course.slug,
|
||||||
|
userStore.id
|
||||||
|
);
|
||||||
|
if (!learningPath) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return learningPath.circles
|
||||||
|
.filter((circle) => props.selectedCircles.includes(circle.title))
|
||||||
|
.flatMap((circle) => {
|
||||||
|
const learningContents = circle.flatLearningContents.filter(
|
||||||
|
(lc) =>
|
||||||
|
lc.content_type === "learnpath.LearningContentAssignment" ||
|
||||||
|
lc.content_type === "learnpath.LearningContentFeedback"
|
||||||
|
);
|
||||||
|
|
||||||
|
return learningContents.map((lc) => {
|
||||||
|
return {
|
||||||
|
id: lc.id,
|
||||||
|
circleName: circle.title,
|
||||||
|
frontendUrl: lc.frontend_url,
|
||||||
|
title: getLearningContentType(lc),
|
||||||
|
showDetailsText: getShowDetailsText(lc),
|
||||||
|
detailsLink: getDetailsLink(lc),
|
||||||
|
content: lc,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}) as Submittable[];
|
||||||
|
});
|
||||||
|
|
||||||
|
const isFeedback = (lc: LearningContent) => {
|
||||||
|
return lc.content_type === "learnpath.LearningContentFeedback";
|
||||||
|
};
|
||||||
|
|
||||||
|
const isAssignment = (lc: LearningContent) => {
|
||||||
|
return lc.content_type === "learnpath.LearningContentAssignment";
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLearningContentType = (lc: LearningContent) => {
|
||||||
|
if (isAssignment(lc)) {
|
||||||
|
const lcTypeData = learningContentTypeData(lc);
|
||||||
|
if ((lc as LearningContentAssignment).assignment_type === "REFLECTION") {
|
||||||
|
return lcTypeData.title;
|
||||||
|
}
|
||||||
|
return `${lcTypeData.title}: ${lc.title}`;
|
||||||
|
}
|
||||||
|
return t("Feedback: Feedback zum Lehrgang");
|
||||||
|
};
|
||||||
|
|
||||||
|
const getShowDetailsText = (lc: LearningContent) => {
|
||||||
|
if (isAssignment(lc)) {
|
||||||
|
const assignmentType = (lc as LearningContentAssignment).assignment_type;
|
||||||
|
if (assignmentType === "CASEWORK" || assignmentType === "REFLECTION") {
|
||||||
|
return t("Ergebnisse anschauen");
|
||||||
|
} else if (assignmentType === "PREP_ASSIGNMENT") {
|
||||||
|
return t("Status anschauen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t("Feedback anschauen");
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDetailsLink = (lc: LearningContent) => {
|
||||||
|
if (isFeedback(lc)) {
|
||||||
|
return `cockpit/feedback/${lc.parentCircle.id}`;
|
||||||
|
}
|
||||||
|
return `cockpit/assignment/${lc.id}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getIconName = (lc: LearningContent) => {
|
||||||
|
if (isAssignment(lc)) {
|
||||||
|
const assignmentType = (lc as LearningContentAssignment).assignment_type;
|
||||||
|
if (assignmentType === "PREP_ASSIGNMENT" || assignmentType === "CASEWORK") {
|
||||||
|
return "it-icon-assignment-large";
|
||||||
|
} else if (assignmentType === "REFLECTION") {
|
||||||
|
return "it-icon-test-large";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "it-icon-feedback-large";
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="bg-white px-6 py-2">
|
||||||
|
<div v-if="cockpitStore.courseSessionUsers" class="divide-y divide-gray-500">
|
||||||
|
<div
|
||||||
|
v-for="submittable in submittables"
|
||||||
|
:key="submittable.id"
|
||||||
|
class="flex flex-row justify-between py-4"
|
||||||
|
>
|
||||||
|
<div class="flex w-1/3 flex-row items-center space-x-4 pr-2">
|
||||||
|
<component :is="getIconName(submittable.content)" class="h-9 w-9"></component>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<h3 class="text-bold flex items-center gap-2">{{ submittable.title }}</h3>
|
||||||
|
<p class="text-gray-800">Circle «{{ submittable.circleName }}»</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<AssignmentSubmissionProgress
|
||||||
|
v-if="isAssignment(submittable.content)"
|
||||||
|
:course-session="props.courseSession"
|
||||||
|
:learning-content-assignment="submittable.content as LearningContentAssignment"
|
||||||
|
:show-title="false"
|
||||||
|
class="grow pr-8"
|
||||||
|
/>
|
||||||
|
<FeedbackSubmissionProgress
|
||||||
|
v-if="isFeedback(submittable.content)"
|
||||||
|
:course-session="props.courseSession"
|
||||||
|
:circle-id="submittable.content.parentCircle.id"
|
||||||
|
class="grow pr-8"
|
||||||
|
></FeedbackSubmissionProgress>
|
||||||
|
<div class="flex w-1/4 items-center justify-end">
|
||||||
|
<button class="btn-primary">
|
||||||
|
<router-link
|
||||||
|
:to="submittable.detailsLink"
|
||||||
|
:data-cy="`show-details-btn-${submittable.content.slug}`"
|
||||||
|
>
|
||||||
|
{{ submittable.showDetailsText }}
|
||||||
|
</router-link>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -23,6 +23,7 @@ import dayjs from "dayjs";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { computed, onMounted, reactive } from "vue";
|
import { computed, onMounted, reactive } from "vue";
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
|
import { learningContentTypeData } from "@/utils/typeMaps";
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const courseSession = useCurrentCourseSession();
|
const courseSession = useCurrentCourseSession();
|
||||||
|
|
@ -175,12 +176,7 @@ const assignmentType = computed(() => {
|
||||||
|
|
||||||
const subTitle = computed(() => {
|
const subTitle = computed(() => {
|
||||||
if (assignment.value) {
|
if (assignment.value) {
|
||||||
let prefix = "Geleitete Fallarbeit";
|
const prefix = learningContentTypeData(props.learningContent).title;
|
||||||
if (assignmentType.value === "PREP_ASSIGNMENT") {
|
|
||||||
prefix = "Vorbereitungsauftrag";
|
|
||||||
} else if (assignmentType.value === "REFLECTION") {
|
|
||||||
prefix = "Reflexion";
|
|
||||||
}
|
|
||||||
return `${prefix}: ${assignment.value?.title ?? ""}`;
|
return `${prefix}: ${assignment.value?.title ?? ""}`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ const router = createRouter({
|
||||||
props: true,
|
props: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "assignment",
|
path: "assignment/:assignmentId",
|
||||||
component: () =>
|
component: () =>
|
||||||
import("@/pages/cockpit/assignmentsPage/AssignmentsPage.vue"),
|
import("@/pages/cockpit/assignmentsPage/AssignmentsPage.vue"),
|
||||||
props: true,
|
props: true,
|
||||||
|
|
@ -155,6 +155,12 @@ const router = createRouter({
|
||||||
),
|
),
|
||||||
props: true,
|
props: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "attendanceCheck",
|
||||||
|
component: () =>
|
||||||
|
import("@/pages/cockpit/attendanceCheckPage/AttendanceCheckPage.vue"),
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import type { StatusCountKey } from "@/components/ui/ItProgress.vue";
|
|
||||||
import { itGet } from "@/fetchHelpers";
|
import { itGet } from "@/fetchHelpers";
|
||||||
import type { LearningPath } from "@/services/learningPath";
|
import type { LearningPath } from "@/services/learningPath";
|
||||||
import { useCockpitStore } from "@/stores/cockpit";
|
import { useCockpitStore } from "@/stores/cockpit";
|
||||||
|
|
@ -8,7 +7,6 @@ import { useUserStore } from "@/stores/user";
|
||||||
import type {
|
import type {
|
||||||
Assignment,
|
Assignment,
|
||||||
AssignmentCompletion,
|
AssignmentCompletion,
|
||||||
AssignmentCompletionStatus,
|
|
||||||
CourseSessionUser,
|
CourseSessionUser,
|
||||||
LearningContentAssignment,
|
LearningContentAssignment,
|
||||||
UserAssignmentCompletionStatus,
|
UserAssignmentCompletionStatus,
|
||||||
|
|
@ -16,15 +14,18 @@ import type {
|
||||||
import { sum } from "d3";
|
import { sum } from "d3";
|
||||||
import pick from "lodash/pick";
|
import pick from "lodash/pick";
|
||||||
|
|
||||||
|
export interface GradedUser {
|
||||||
|
user: CourseSessionUser;
|
||||||
|
grade: number;
|
||||||
|
}
|
||||||
|
|
||||||
export function calcLearningContentAssignments(learningPath?: LearningPath) {
|
export function calcLearningContentAssignments(learningPath?: LearningPath) {
|
||||||
// TODO: filter by circle
|
// TODO: filter by circle
|
||||||
if (!learningPath) return [];
|
if (!learningPath) return [];
|
||||||
|
|
||||||
return learningPath.circles.flatMap((circle) => {
|
return learningPath.circles.flatMap((circle) => {
|
||||||
return circle.flatLearningContents.filter(
|
return circle.flatLearningContents.filter(
|
||||||
(lc) =>
|
(lc) => lc.content_type === "learnpath.LearningContentAssignment"
|
||||||
lc.content_type === "learnpath.LearningContentAssignment" &&
|
|
||||||
lc.assignment_type === "CASEWORK"
|
|
||||||
) as LearningContentAssignment[];
|
) as LearningContentAssignment[];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -41,40 +42,31 @@ export async function loadAssignmentCompletionStatusData(
|
||||||
|
|
||||||
const courseSessionUsers = await cockpitStore.loadCourseSessionUsers(courseSessionId);
|
const courseSessionUsers = await cockpitStore.loadCourseSessionUsers(courseSessionId);
|
||||||
|
|
||||||
return calcUserAssignmentCompletionStatus(
|
const gradedUsers: GradedUser[] = [];
|
||||||
courseSessionUsers,
|
const assignmentSubmittedUsers: CourseSessionUser[] = [];
|
||||||
assignmentCompletionData
|
for (const csu of courseSessionUsers) {
|
||||||
);
|
const userAssignmentStatus = assignmentCompletionData.find(
|
||||||
}
|
(s) => s.assignment_user_id === csu.user_id
|
||||||
|
|
||||||
export function calcUserAssignmentCompletionStatus(
|
|
||||||
courseSessionUsers: CourseSessionUser[],
|
|
||||||
assignmentCompletionStatusData: UserAssignmentCompletionStatus[]
|
|
||||||
) {
|
|
||||||
return courseSessionUsers.map((u) => {
|
|
||||||
let userStatus = "unknown" as AssignmentCompletionStatus;
|
|
||||||
const userAssignmentStatus = assignmentCompletionStatusData?.find(
|
|
||||||
(s) => s.assignment_user_id === u.user_id
|
|
||||||
);
|
);
|
||||||
if (userAssignmentStatus) {
|
|
||||||
userStatus = userAssignmentStatus.completion_status;
|
|
||||||
}
|
|
||||||
let progressStatus: StatusCountKey = "UNKNOWN";
|
|
||||||
if (
|
if (
|
||||||
["SUBMITTED", "EVALUATION_IN_PROGRESS", "EVALUATION_SUBMITTED"].includes(
|
userAssignmentStatus?.completion_status === "SUBMITTED" ||
|
||||||
userStatus
|
userAssignmentStatus?.completion_status === "EVALUATION_IN_PROGRESS" ||
|
||||||
)
|
userAssignmentStatus?.completion_status === "EVALUATION_SUBMITTED"
|
||||||
) {
|
) {
|
||||||
progressStatus = "SUCCESS";
|
assignmentSubmittedUsers.push(csu);
|
||||||
}
|
}
|
||||||
|
if (userAssignmentStatus?.completion_status === "EVALUATION_SUBMITTED") {
|
||||||
return {
|
gradedUsers.push({
|
||||||
userId: u.user_id,
|
user: csu,
|
||||||
userStatus,
|
grade: userAssignmentStatus.evaluation_grade ?? 0,
|
||||||
progressStatus,
|
});
|
||||||
grade: userAssignmentStatus?.evaluation_grade ?? null,
|
}
|
||||||
};
|
}
|
||||||
});
|
return {
|
||||||
|
assignmentSubmittedUsers: assignmentSubmittedUsers,
|
||||||
|
gradedUsers: gradedUsers,
|
||||||
|
total: courseSessionUsers.length,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findAssignmentDetail(assignmentId: number) {
|
export function findAssignmentDetail(assignmentId: number) {
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,12 @@ export const useCockpitStore = defineStore({
|
||||||
this.cockpitSessionUser = currentUser as ExpertSessionUser;
|
this.cockpitSessionUser = currentUser as ExpertSessionUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.cockpitSessionUser && this.cockpitSessionUser.circles?.length > 0) {
|
if (this.selectedCircles.length === 0) {
|
||||||
this.selectedCircles = [this.cockpitSessionUser.circles[0].translation_key];
|
// workaround to select first circle by default, when nothing is selected...
|
||||||
|
// TODO: is this the right place to do this?
|
||||||
|
if (this.cockpitSessionUser && this.cockpitSessionUser.circles?.length > 0) {
|
||||||
|
this.selectedCircles = [this.cockpitSessionUser.circles[0].translation_key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.courseSessionUsers) {
|
if (!this.courseSessionUsers) {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@ describe("assignmentTrainer.cy.js", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can open cockpit assignment page and open user assignment", () => {
|
it("can open cockpit assignment page and open user assignment", () => {
|
||||||
cy.visit("/course/test-lehrgang/cockpit/assignment");
|
cy.visit("/course/test-lehrgang/cockpit");
|
||||||
|
cy.get(
|
||||||
|
'[data-cy="show-details-btn-test-lehrgang-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice"]'
|
||||||
|
).click();
|
||||||
|
|
||||||
cy.get('[data-cy="Student1"]').should("contain", "Ergebnisse abgegeben");
|
cy.get('[data-cy="Student1"]').should("contain", "Ergebnisse abgegeben");
|
||||||
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
||||||
|
|
@ -18,7 +21,10 @@ describe("assignmentTrainer.cy.js", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can start evaluation and store evaluation results", () => {
|
it("can start evaluation and store evaluation results", () => {
|
||||||
cy.visit("/course/test-lehrgang/cockpit/assignment");
|
cy.visit("/course/test-lehrgang/cockpit");
|
||||||
|
cy.get(
|
||||||
|
'[data-cy="show-details-btn-test-lehrgang-lp-circle-fahrzeug-lc-überprüfen-einer-motorfahrzeug-versicherungspolice"]'
|
||||||
|
).click();
|
||||||
|
|
||||||
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
cy.get('[data-cy="Student1"]').find('[data-cy="show-results"]').click();
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.13 on 2023-07-19 14:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("assignment", "0003_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="assignmentcompletion",
|
||||||
|
name="additional_json_data",
|
||||||
|
field=models.JSONField(blank=True, default=dict),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -291,7 +291,7 @@ class AssignmentCompletion(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
completion_data = models.JSONField(default=dict)
|
completion_data = models.JSONField(default=dict)
|
||||||
additional_json_data = models.JSONField(default=dict)
|
additional_json_data = models.JSONField(default=dict, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import wagtail_factories
|
import wagtail_factories
|
||||||
from dateutil.relativedelta import relativedelta, TH, TU
|
from dateutil.relativedelta import MO, relativedelta, TH, TU
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from slugify import slugify
|
from slugify import slugify
|
||||||
|
|
@ -140,6 +140,20 @@ def create_test_course(include_uk=True, include_vv=True, with_sessions=False):
|
||||||
)
|
)
|
||||||
csa.evaluation_deadline.save()
|
csa.evaluation_deadline.save()
|
||||||
|
|
||||||
|
csa = CourseSessionAssignment.objects.create(
|
||||||
|
course_session=cs_bern,
|
||||||
|
learning_content=LearningContentAssignment.objects.get(
|
||||||
|
slug=f"test-lehrgang-lp-circle-fahrzeug-lc-fahrzeug-mein-erstes-auto"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
next_monday = datetime.now() + relativedelta(weekday=MO(2))
|
||||||
|
csa.submission_deadline.start = timezone.make_aware(
|
||||||
|
(next_monday + relativedelta(weeks=1)).replace(
|
||||||
|
hour=23, minute=59, second=59, microsecond=0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
csa.submission_deadline.save()
|
||||||
|
|
||||||
cs_zurich = CourseSession.objects.create(
|
cs_zurich = CourseSession.objects.create(
|
||||||
course_id=COURSE_TEST_ID,
|
course_id=COURSE_TEST_ID,
|
||||||
title="Test Zürich 2022 a",
|
title="Test Zürich 2022 a",
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import random
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import djclick as click
|
import djclick as click
|
||||||
from dateutil.relativedelta import relativedelta, TH, TU
|
from dateutil.relativedelta import MO, relativedelta, TH, TU
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from vbv_lernwelt.assignment.creators.create_assignments import (
|
from vbv_lernwelt.assignment.creators.create_assignments import (
|
||||||
|
|
@ -285,6 +285,20 @@ def create_course_uk_de():
|
||||||
)
|
)
|
||||||
csa.evaluation_deadline.save()
|
csa.evaluation_deadline.save()
|
||||||
|
|
||||||
|
csa = CourseSessionAssignment.objects.create(
|
||||||
|
course_session=cs,
|
||||||
|
learning_content=LearningContentAssignment.objects.get(
|
||||||
|
slug=f"{course.slug}-lp-circle-fahrzeug-lc-fahrzeug-mein-erstes-auto"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
next_monday = datetime.now() + relativedelta(weekday=MO(2))
|
||||||
|
csa.submission_deadline.start = timezone.make_aware(
|
||||||
|
(next_monday + relativedelta(weeks=1)).replace(
|
||||||
|
hour=23, minute=59, second=59, microsecond=0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
csa.submission_deadline.save()
|
||||||
|
|
||||||
# figma demo users and data
|
# figma demo users and data
|
||||||
csu = CourseSessionUser.objects.create(
|
csu = CourseSessionUser.objects.create(
|
||||||
course_session=cs,
|
course_session=cs,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.13 on 2023-07-19 14:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("course", "0002_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="coursecompletion",
|
||||||
|
name="additional_json_data",
|
||||||
|
field=models.JSONField(blank=True, default=dict),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -182,7 +182,7 @@ class CourseCompletion(models.Model):
|
||||||
choices=[(status, status.value) for status in CourseCompletionStatus],
|
choices=[(status, status.value) for status in CourseCompletionStatus],
|
||||||
default=CourseCompletionStatus.UNKNOWN.value,
|
default=CourseCompletionStatus.UNKNOWN.value,
|
||||||
)
|
)
|
||||||
additional_json_data = models.JSONField(default=dict)
|
additional_json_data = models.JSONField(default=dict, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
constraints = [
|
constraints = [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue