Merge branch 'dev' into fix/questions-toon-enkel-groep

This commit is contained in:
Tibo De Peuter 2025-05-20 16:37:34 +02:00
commit 73ca508ff3
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
5 changed files with 118 additions and 62 deletions

View file

@ -1,12 +1,13 @@
import { getAssignmentRepository, getGroupRepository, getSubmissionRepository } from '../data/repositories.js';
import { getSubmissionRepository } from '../data/repositories.js';
import { LearningObjectIdentifier } from '../entities/content/learning-object-identifier.js';
import { NotFoundException } from '../exceptions/not-found-exception.js';
import { mapToSubmission, mapToSubmissionDTO } from '../interfaces/submission.js';
import { SubmissionDTO } from '@dwengo-1/common/interfaces/submission';
import { fetchStudent } from './students.js';
import { getExistingGroupFromGroupDTO } from './groups.js';
import { fetchGroup, getExistingGroupFromGroupDTO } from './groups.js';
import { Submission } from '../entities/assignments/submission.entity.js';
import { Language } from '@dwengo-1/common/util/language';
import { fetchAssignment } from './assignments.js';
export async function fetchSubmission(loId: LearningObjectIdentifier, submissionNumber: number): Promise<Submission> {
const submissionRepository = getSubmissionRepository();
@ -64,15 +65,18 @@ export async function getSubmissionsForLearningObjectAndAssignment(
groupId?: number
): Promise<SubmissionDTO[]> {
const loId = new LearningObjectIdentifier(learningObjectHruid, language, version);
const assignment = await getAssignmentRepository().findByClassIdAndAssignmentId(classId, assignmentId);
let submissions: Submission[];
if (groupId !== undefined) {
const group = await getGroupRepository().findByAssignmentAndGroupNumber(assignment!, groupId);
submissions = await getSubmissionRepository().findAllSubmissionsForLearningObjectAndGroup(loId, group!);
} else {
submissions = await getSubmissionRepository().findAllSubmissionsForLearningObjectAndAssignment(loId, assignment!);
try {
let submissions: Submission[];
if (groupId !== undefined) {
const group = await fetchGroup(classId, assignmentId, groupId);
submissions = await getSubmissionRepository().findAllSubmissionsForLearningObjectAndGroup(loId, group);
} else {
const assignment = await fetchAssignment(classId, assignmentId);
submissions = await getSubmissionRepository().findAllSubmissionsForLearningObjectAndAssignment(loId, assignment);
}
return submissions.map((s) => mapToSubmissionDTO(s));
} catch (_) {
return [];
}
return submissions.map((s) => mapToSubmissionDTO(s));
}

View file

@ -34,19 +34,21 @@
</template>
</v-list-item>
<v-divider></v-divider>
<v-expansion-panels v-model="expanded">
<using-query-result
:query-result="allLearningPathsResult"
v-slot="learningPaths: { data: LearningPath[] }"
>
<DiscussionSideBarElement
v-for="learningPath in learningPaths.data"
:path="learningPath"
:activeObjectId="'' as string"
:key="learningPath.hruid"
/>
</using-query-result>
</v-expansion-panels>
<div class="nav-scroll-area">
<v-expansion-panels v-model="expanded">
<using-query-result
:query-result="allLearningPathsResult"
v-slot="learningPaths: { data: LearningPath[] }"
>
<DiscussionSideBarElement
v-for="learningPath in learningPaths.data"
:path="learningPath"
:activeObjectId="'' as string"
:key="learningPath.hruid"
/>
</using-query-result>
</v-expansion-panels>
</div>
</div>
</v-navigation-drawer>
<div class="control-bar-above-content">
@ -67,4 +69,10 @@
padding-top: 2%;
font-size: 36px;
}
.nav-scroll-area {
overflow-y: auto;
flex-grow: 1;
min-height: 0;
}
</style>

View file

@ -13,7 +13,7 @@
import authService from "@/services/auth/auth-service.ts";
import { LearningPathNode } from "@/data-objects/learning-paths/learning-path-node.ts";
import LearningPathGroupSelector from "@/views/learning-paths/LearningPathGroupSelector.vue";
import { useQuestionsGroupQuery, useQuestionsQuery } from "@/queries/questions";
import { useQuestionsQuery } from "@/queries/questions";
import type { QuestionsResponse } from "@/controllers/questions";
import type { LearningObjectIdentifierDTO } from "@dwengo-1/common/interfaces/learning-content";
import QandA from "@/components/QandA.vue";
@ -163,11 +163,6 @@
});
}
const loID: LearningObjectIdentifierDTO = {
hruid: props.learningObjectHruid as string,
language: props.language,
};
const discussionLink = computed(
() =>
"/discussion" +
@ -237,7 +232,7 @@
</template>
</v-list-item>
<v-divider></v-divider>
<div>
<div class="nav-scroll-area">
<using-query-result
:query-result="learningObjectListQueryResult"
v-slot="learningObjects: { data: LearningObject[] }"
@ -430,4 +425,10 @@
.discussion-link a:hover {
text-decoration: underline;
}
.nav-scroll-area {
overflow-y: auto;
flex-grow: 1;
min-height: 0;
}
</style>

View file

@ -18,6 +18,15 @@
version: number;
group: { forGroup: number; assignmentNo: number; classId: string };
}>();
function parseContent(content: string): SubmissionData {
if (content === "") {
return [];
}
return JSON.parse(content);
}
const emit = defineEmits<(e: "update:submissionData", value: SubmissionData) => void>();
const submissionQuery = useSubmissionsQuery(
@ -35,7 +44,7 @@
}
function emitSubmission(submission: SubmissionDTO): void {
emitSubmissionData(JSON.parse(submission.content));
emitSubmissionData(parseContent(submission.content));
}
watch(submissionQuery.data, () => {
@ -47,12 +56,13 @@
}
});
const lastSubmission = computed<SubmissionData>(() => {
const lastSubmission = computed<SubmissionData | undefined>(() => {
const submissions = submissionQuery.data.value;
if (!submissions || submissions.length === 0) {
return undefined;
}
return JSON.parse(submissions[submissions.length - 1].content);
return parseContent(submissions[submissions.length - 1].content);
});
const showSubmissionTable = computed(() => props.submissionData !== undefined && props.submissionData.length > 0);

View file

@ -89,6 +89,15 @@
props.selectedLearningPath.language !== parsedLearningPath.value.language),
);
const selectedLearningPathLink = computed(() => {
if (!props.selectedLearningPath) {
return undefined;
}
const { hruid, language } = props.selectedLearningPath;
const startNode = props.selectedLearningPath.nodes.find((it) => it.start_node);
return `/learningPath/${hruid}/${language}/${startNode.learningobject_hruid}`;
});
function getErrorMessage(): string | null {
if (postError.value) {
return t(extractErrorMessage(postError.value));
@ -104,7 +113,43 @@
</script>
<template>
<v-card :title="props.selectedLearningPath ? t('editLearningPath') : t('newLearningPath')">
<v-card>
<template v-slot:title>
<div class="title-container">
<span class="title">{{
props.selectedLearningPath ? t("editLearningPath") : t("newLearningPath")
}}</span>
<span class="actions">
<v-btn
@click="uploadLearningPath"
prependIcon="mdi mdi-check"
:loading="isPostPending || isPutPending"
:disabled="parsedLearningPath.hruid === DEFAULT_LEARNING_PATH.hruid || isIdModified"
variant="text"
>
{{ props.selectedLearningPath ? t("saveChanges") : t("create") }}
</v-btn>
<button-with-confirmation
@confirm="deleteLearningPath"
:disabled="!props.selectedLearningPath"
:text="t('delete')"
color="red"
prependIcon="mdi mdi-delete"
:confirmQueryText="t('learningPathDeleteQuery')"
variant="text"
/>
<v-btn
:href="selectedLearningPathLink"
target="_blank"
prepend-icon="mdi mdi-open-in-new"
:disabled="!props.selectedLearningPath"
variant="text"
>
{{ t("open") }}
</v-btn>
</span>
</div>
</template>
<template v-slot:text>
<json-editor-vue v-model="learningPath"></json-editor-vue>
<v-alert
@ -115,33 +160,21 @@
:text="getErrorMessage()!"
></v-alert>
</template>
<template v-slot:actions>
<v-btn
@click="uploadLearningPath"
prependIcon="mdi mdi-check"
:loading="isPostPending || isPutPending"
:disabled="parsedLearningPath.hruid === DEFAULT_LEARNING_PATH.hruid || isIdModified"
>
{{ props.selectedLearningPath ? t("saveChanges") : t("create") }}
</v-btn>
<button-with-confirmation
@confirm="deleteLearningPath"
:disabled="!props.selectedLearningPath"
:text="t('delete')"
color="red"
prependIcon="mdi mdi-delete"
:confirmQueryText="t('learningPathDeleteQuery')"
/>
<v-btn
:href="`/learningPath/${props.selectedLearningPath?.hruid}/${props.selectedLearningPath?.language}/start`"
target="_blank"
prepend-icon="mdi mdi-open-in-new"
:disabled="!props.selectedLearningPath"
>
{{ t("open") }}
</v-btn>
</template>
</v-card>
</template>
<style scoped></style>
<style scoped>
.title-container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.title {
flex: 1;
}
.actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
</style>