fix(backend): Diverse bugfixes omtrent LearningPathPage

This commit is contained in:
Gerald Schmittinger 2025-03-31 23:12:03 +02:00
parent 27b9cdf833
commit 12b9f31f5f
9 changed files with 34 additions and 33 deletions

View file

@ -1,6 +1,5 @@
<script setup lang="ts" generic="T">
import {RemoteResource} from "@/services/api-client/remote-resource.ts";
import {computed, type MaybeRefOrGetter} from "vue";
import {computed} from "vue";
import {useI18n} from "vue-i18n";
import type {UseQueryReturnType} from "@tanstack/vue-query";
@ -8,13 +7,12 @@
queryResult: UseQueryReturnType<T, Error>
}>()
const { isLoading, isError, isSuccess, data, error } = props.queryResult;
const { t } = useI18n();
const isLoading = computed(() => props.queryResult.isFetching);
const data = computed(() => props.queryResult.data);
const error = computed(() => props.queryResult.error);
const errorMessage = computed(() => {
let errorWithMessage = (error.value as {message: string}) || null;
let errorWithMessage = (error as {message: string}) || null;
return errorWithMessage?.message || JSON.stringify(errorWithMessage)
});
</script>
@ -23,14 +21,14 @@
<div class="loading-div" v-if="isLoading">
<v-progress-circular indeterminate></v-progress-circular>
</div>
<div v-if="error">
<div v-if="isError">
<v-empty-state
icon="mdi-alert-circle-outline"
:text="errorMessage"
:title="t('error_title')"
></v-empty-state>
</div>
<slot v-if="data" :data="data!"></slot>
<slot v-if="isSuccess && data" :data="data"></slot>
</template>
<style scoped>

View file

@ -1,41 +1,47 @@
import { apiConfig } from "@/config.ts";
import apiClient from "@/services/api-client/api-client.ts";
import type {AxiosResponse, ResponseType} from "axios";
import {HttpErrorResponseException} from "@/exception/http-error-response-exception.ts";
export abstract class BaseController {
protected baseUrl: string;
protected basePath: string;
protected constructor(basePath: string) {
this.baseUrl = `${apiConfig.baseUrl}/${basePath}`;
this.basePath = basePath;
}
private assertSuccessResponse(response: AxiosResponse<unknown, unknown>) {
if (response.status / 200 !== 2) {
if (response.status / 100 !== 2) {
throw new HttpErrorResponseException(response);
}
}
private absolutePathFor(path: string) {
return "/" + this.basePath + path;
}
protected async get<T>(path: string, queryParams?: Record<string, any>, responseType?: ResponseType): Promise<T> {
let response = await apiClient.get<T>(path, {params: queryParams, responseType});
let response = await apiClient.get<T>(
this.absolutePathFor(path),
{params: queryParams, responseType}
);
this.assertSuccessResponse(response);
return response.data;
}
protected async post<T>(path: string, body: unknown): Promise<T> {
let response = await apiClient.post<T>(path, body);
let response = await apiClient.post<T>(this.absolutePathFor(path), body);
this.assertSuccessResponse(response);
return response.data;
}
protected async delete<T>(path: string): Promise<T> {
let response = await apiClient.delete<T>(path)
let response = await apiClient.delete<T>(this.absolutePathFor(path))
this.assertSuccessResponse(response);
return response.data;
}
protected async put<T>(path: string, body: unknown): Promise<T> {
let response = await apiClient.put<T>(path, body);
let response = await apiClient.put<T>(this.absolutePathFor(path), body);
this.assertSuccessResponse(response);
return response.data;
}

View file

@ -8,10 +8,10 @@ export class LearningObjectController extends BaseController {
}
async getMetadata(hruid: string, language: Language, version: number): Promise<LearningObject> {
return this.get<LearningObject>(`/learningObject/${hruid}`, {language, version});
return this.get<LearningObject>(`/${hruid}`, {language, version});
}
async getHTML(hruid: string, language: Language, version: number): Promise<Document> {
return this.get<Document>(`/learningObject/${hruid}/html`, {language, version}, "document");
return this.get<Document>(`/${hruid}/html`, {language, version}, "document");
}
}

View file

@ -2,6 +2,7 @@ import {BaseController} from "@/controllers/base-controller.ts";
import {LearningPath} from "@/data-objects/learning-path.ts";
import type {LearningPathDTO} from "@/data-objects/learning-path.ts";
import type {Language} from "@/data-objects/language.ts";
import {single} from "@/utils/response-assertions.ts";
export class LearningPathController extends BaseController {
constructor() {
@ -18,6 +19,6 @@ export class LearningPathController extends BaseController {
forGroup: options?.forGroup,
forStudent: options?.forStudent
});
return dtos.map(dto => LearningPath.fromDTO(dto))
return LearningPath.fromDTO(single(dtos));
}
}

View file

@ -1,7 +1,9 @@
import type {AxiosResponse} from "axios";
export class HttpErrorResponseException extends Error {
public statusCode: number;
constructor(public response: AxiosResponse<unknown, unknown>) {
super(response.statusText);
super((response.data as {message: string})?.message || JSON.stringify(response.data));
this.statusCode = response.status;
}
}

View file

@ -47,10 +47,10 @@ export function useLearningObjectListForPathQuery(
let learningObjects = [];
for (let node of toValue(learningPath).nodesAsList) {
learningObjects.push(
learningObjectController.getHTML(node.learningobjectHruid, node.language, node.version)
learningObjectController.getMetadata(node.learningobjectHruid, node.language, node.version)
);
}
return learningObjects;
return Promise.all(learningObjects);
},
enabled: () => Boolean(toValue(learningPath)),
});

View file

@ -12,7 +12,6 @@ import UserClasses from "@/views/classes/UserClasses.vue";
import UserAssignments from "@/views/classes/UserAssignments.vue";
import authState from "@/services/auth/auth-service.ts";
import LearningPathPage from "@/views/learning-paths/LearningPathPage.vue";
import path from "path";
import LearningPathSearchPage from "@/views/learning-paths/LearningPathSearchPage.vue";
import UserHomePage from "@/views/homepage/UserHomePage.vue";
import SingleTheme from "@/views/SingleTheme.vue";
@ -109,16 +108,15 @@ const router = createRouter({
},
{
path: "/learningPath",
component: MenuBar,
children: [
{
path: "/search",
path: "search",
name: "LearningPathSearchPage",
component: LearningPathSearchPage,
meta: { requiresAuth: true }
},
{
path: "/:hruid/:language",
path: ":hruid/:language",
name: "LearningPath",
component: LearningPathPage,
props: true,

View file

@ -6,7 +6,7 @@ import UsingQueryResult from "@/components/UsingQueryResult.vue";
const props = defineProps<{hruid: string, language: Language, version: number}>()
const learningObjectHtmlQueryResult: UseQueryReturnType<Document, Error> = useLearningObjectHTMLQuery(props.hruid, props.language, props.version);
const learningObjectHtmlQueryResult: UseQueryReturnType<Document, Error> = useLearningObjectHTMLQuery(() => props.hruid, () => props.language, () => props.version);
</script>

View file

@ -27,10 +27,10 @@
const learningPathQueryResult = useGetLearningPathQuery(props.hruid, props.language, typedQuery.value);
const learningObjectListQueryResult = useLearningObjectListForPathQuery(learningPathQueryResult.data.value);
const learningObjectListQueryResult = useLearningObjectListForPathQuery(learningPathQueryResult.data);
const nodesList: ComputedRef<LearningPathNode[] | null> = computed(() =>
(!learningPathQueryResult.isPending && !learningPathQueryResult.isError) ? learningPathQueryResult.data.value?.nodesAsList : null
learningPathQueryResult.isSuccess ? learningPathQueryResult.data.value?.nodesAsList : null
);
const currentNode = computed(() => {
@ -107,7 +107,6 @@
</script>
<template>
<v-main>
<using-query-result
:query-result="learningPathQueryResult"
v-slot="learningPath: {data: LearningPath}"
@ -125,7 +124,6 @@
</template>
</v-list-item>
<v-divider></v-divider>
<div v-if="props.learningObjectHruid">
<using-query-result
:query-result="learningObjectListQueryResult"
@ -160,7 +158,6 @@
<learning-path-search-field></learning-path-search-field>
</div>
</div>
<learning-object-view
:hruid="currentNode.learningobjectHruid"
:language="currentNode.language"
@ -186,7 +183,6 @@
</v-btn>
</div>
</using-query-result>
</v-main>
</template>
<style scoped>