From 4d98be78c198e0fab710991d7a7b50c217139fe9 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 1 Apr 2025 15:00:47 +0200 Subject: [PATCH] fix(frontend): Linting errors/warnings opgelost --- .../components/LearningPathSearchField.vue | 4 +- frontend/src/components/LearningPathsGrid.vue | 3 +- frontend/src/components/UsingQueryResult.vue | 2 +- frontend/src/controllers/base-controller.ts | 30 ++-- frontend/src/controllers/learning-objects.ts | 2 +- frontend/src/controllers/learning-paths.ts | 16 +-- .../learning-objects/educational-goal.ts | 4 + .../{ => learning-objects}/learning-object.ts | 12 +- .../learning-objects/return-value.ts | 4 + frontend/src/data-objects/learning-path.ts | 128 ------------------ .../learning-paths/learning-path-dto.ts | 17 +++ .../learning-paths/learning-path-node.ts | 57 ++++++++ .../learning-paths/learning-path.ts | 94 +++++++++++++ .../exception/invalid-response-exception.ts | 5 + frontend/src/exception/not-found-exception.ts | 5 + frontend/src/queries/learning-objects.ts | 14 +- frontend/src/queries/learning-paths.ts | 10 +- frontend/src/router/index.ts | 18 +-- .../src/services/api-client/api-exceptions.ts | 22 --- frontend/src/utils/response-assertions.ts | 3 +- frontend/src/views/CallbackPage.vue | 11 +- frontend/src/views/HomePage.vue | 2 - frontend/src/views/SingleTheme.vue | 4 +- .../learning-paths/LearningObjectView.vue | 2 +- .../views/learning-paths/LearningPathPage.vue | 56 +++----- .../learning-paths/LearningPathSearchPage.vue | 5 +- 26 files changed, 272 insertions(+), 258 deletions(-) create mode 100644 frontend/src/data-objects/learning-objects/educational-goal.ts rename frontend/src/data-objects/{ => learning-objects}/learning-object.ts (76%) create mode 100644 frontend/src/data-objects/learning-objects/return-value.ts delete mode 100644 frontend/src/data-objects/learning-path.ts create mode 100644 frontend/src/data-objects/learning-paths/learning-path-dto.ts create mode 100644 frontend/src/data-objects/learning-paths/learning-path-node.ts create mode 100644 frontend/src/data-objects/learning-paths/learning-path.ts create mode 100644 frontend/src/exception/invalid-response-exception.ts create mode 100644 frontend/src/exception/not-found-exception.ts delete mode 100644 frontend/src/services/api-client/api-exceptions.ts diff --git a/frontend/src/components/LearningPathSearchField.vue b/frontend/src/components/LearningPathSearchField.vue index d9e9f85d..2d89c192 100644 --- a/frontend/src/components/LearningPathSearchField.vue +++ b/frontend/src/components/LearningPathSearchField.vue @@ -10,12 +10,12 @@ const query = computed({ get: () => route.query.query as string | null, - set: (newValue) => router.push({path: SEARCH_PATH, query: {query: newValue}}) + set: async (newValue) => router.push({path: SEARCH_PATH, query: {query: newValue}}) }); const queryInput = ref(query.value); - function search() { + function search(): void { query.value = queryInput.value; } diff --git a/frontend/src/components/LearningPathsGrid.vue b/frontend/src/components/LearningPathsGrid.vue index aeaf5003..11aab575 100644 --- a/frontend/src/components/LearningPathsGrid.vue +++ b/frontend/src/components/LearningPathsGrid.vue @@ -1,7 +1,7 @@ diff --git a/frontend/src/controllers/base-controller.ts b/frontend/src/controllers/base-controller.ts index d05f579e..ab2b3af6 100644 --- a/frontend/src/controllers/base-controller.ts +++ b/frontend/src/controllers/base-controller.ts @@ -9,40 +9,42 @@ export abstract class BaseController { this.basePath = basePath; } - private assertSuccessResponse(response: AxiosResponse) { + private static assertSuccessResponse(response: AxiosResponse): void { if (response.status / 100 !== 2) { throw new HttpErrorResponseException(response); } } - private absolutePathFor(path: string) { - return "/" + this.basePath + path; - } - - protected async get(path: string, queryParams?: Record, responseType?: ResponseType): Promise { - let response = await apiClient.get( + protected async get(path: string, queryParams?: QueryParams, responseType?: ResponseType): Promise { + const response = await apiClient.get( this.absolutePathFor(path), {params: queryParams, responseType} ); - this.assertSuccessResponse(response); + BaseController.assertSuccessResponse(response); return response.data; } protected async post(path: string, body: unknown): Promise { - let response = await apiClient.post(this.absolutePathFor(path), body); - this.assertSuccessResponse(response); + const response = await apiClient.post(this.absolutePathFor(path), body); + BaseController.assertSuccessResponse(response); return response.data; } protected async delete(path: string): Promise { - let response = await apiClient.delete(this.absolutePathFor(path)) - this.assertSuccessResponse(response); + const response = await apiClient.delete(this.absolutePathFor(path)) + BaseController.assertSuccessResponse(response); return response.data; } protected async put(path: string, body: unknown): Promise { - let response = await apiClient.put(this.absolutePathFor(path), body); - this.assertSuccessResponse(response); + const response = await apiClient.put(this.absolutePathFor(path), body); + BaseController.assertSuccessResponse(response); return response.data; } + + private absolutePathFor(path: string): string { + return "/" + this.basePath + path; + } } + +type QueryParams = Record; diff --git a/frontend/src/controllers/learning-objects.ts b/frontend/src/controllers/learning-objects.ts index df70326b..35a4f755 100644 --- a/frontend/src/controllers/learning-objects.ts +++ b/frontend/src/controllers/learning-objects.ts @@ -1,6 +1,6 @@ import {BaseController} from "@/controllers/base-controller.ts"; import type {Language} from "@/data-objects/language.ts"; -import type {LearningObject} from "@/data-objects/learning-object.ts"; +import type {LearningObject} from "@/data-objects/learning-objects/learning-object.ts"; export class LearningObjectController extends BaseController { constructor() { diff --git a/frontend/src/controllers/learning-paths.ts b/frontend/src/controllers/learning-paths.ts index c729c7e9..3add1175 100644 --- a/frontend/src/controllers/learning-paths.ts +++ b/frontend/src/controllers/learning-paths.ts @@ -1,19 +1,19 @@ 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 {LearningPath} from "@/data-objects/learning-paths/learning-path.ts"; import type {Language} from "@/data-objects/language.ts"; import {single} from "@/utils/response-assertions.ts"; +import type {LearningPathDTO} from "@/data-objects/learning-paths/learning-path-dto.ts"; export class LearningPathController extends BaseController { constructor() { super("learningPath"); } - async search(query: string) { - let dtos = await this.get("/", {search: query}); + async search(query: string): Promise { + const dtos = await this.get("/", {search: query}); return dtos.map(dto => LearningPath.fromDTO(dto)); } - async getBy(hruid: string, language: Language, options?: {forGroup?: string, forStudent?: string}) { - let dtos = await this.get("/", { + async getBy(hruid: string, language: Language, options?: {forGroup?: string, forStudent?: string}): Promise { + const dtos = await this.get("/", { hruid, language, forGroup: options?.forGroup, @@ -21,8 +21,8 @@ export class LearningPathController extends BaseController { }); return LearningPath.fromDTO(single(dtos)); } - async getAllByTheme(theme: string) { - let dtos = await this.get("/", {theme}); + async getAllByTheme(theme: string): Promise { + const dtos = await this.get("/", {theme}); return dtos.map(dto => LearningPath.fromDTO(dto)); } } diff --git a/frontend/src/data-objects/learning-objects/educational-goal.ts b/frontend/src/data-objects/learning-objects/educational-goal.ts new file mode 100644 index 00000000..05c7a786 --- /dev/null +++ b/frontend/src/data-objects/learning-objects/educational-goal.ts @@ -0,0 +1,4 @@ +export interface EducationalGoal { + source: string; + id: string; +} diff --git a/frontend/src/data-objects/learning-object.ts b/frontend/src/data-objects/learning-objects/learning-object.ts similarity index 76% rename from frontend/src/data-objects/learning-object.ts rename to frontend/src/data-objects/learning-objects/learning-object.ts index 9599d44f..803e83ae 100644 --- a/frontend/src/data-objects/learning-object.ts +++ b/frontend/src/data-objects/learning-objects/learning-object.ts @@ -1,14 +1,6 @@ import type {Language} from "@/data-objects/language.ts"; - -export interface EducationalGoal { - source: string; - id: string; -} - -export interface ReturnValue { - callback_url: string; - callback_schema: Record; -} +import type {ReturnValue} from "@/data-objects/learning-objects/return-value.ts"; +import type {EducationalGoal} from "@/data-objects/learning-objects/educational-goal.ts"; export interface LearningObject { key: string; diff --git a/frontend/src/data-objects/learning-objects/return-value.ts b/frontend/src/data-objects/learning-objects/return-value.ts new file mode 100644 index 00000000..56b89380 --- /dev/null +++ b/frontend/src/data-objects/learning-objects/return-value.ts @@ -0,0 +1,4 @@ +export interface ReturnValue { + callback_url: string; + callback_schema: Record; +} diff --git a/frontend/src/data-objects/learning-path.ts b/frontend/src/data-objects/learning-path.ts deleted file mode 100644 index ddafb41f..00000000 --- a/frontend/src/data-objects/learning-path.ts +++ /dev/null @@ -1,128 +0,0 @@ -import type {Language} from "@/data-objects/language.ts"; - -export interface LearningPathDTO { - language: string; - hruid: string; - title: string; - description: string; - image?: string; // Image might be missing, so it's optional - num_nodes: number; - num_nodes_left: number; - nodes: LearningPathNodeDTO[]; - keywords: string; - target_ages: number[]; - min_age: number; - max_age: number; - __order: number; -} - -interface LearningPathNodeDTO { - _id: string; - learningobject_hruid: string; - version: number; - language: Language; - start_node?: boolean; - transitions: LearningPathTransitionDTO[]; - created_at: string; - updatedAt: string; - done?: boolean; // True if a submission exists for this node by the user for whom the learning path is customized. -} - -interface LearningPathTransitionDTO { - default: boolean; - _id: string; - next: { - _id: string; - hruid: string; - version: number; - language: string; - }; -} - -export class LearningPathNode { - - constructor( - public readonly learningobjectHruid: string, - public readonly version: number, - public readonly language: Language, - public readonly transitions: {next: LearningPathNode, default: boolean}[], - public readonly createdAt: Date, - public readonly updatedAt: Date, - public readonly done: boolean = false - ) { - } - - static fromDTOAndOtherNodes(dto: LearningPathNodeDTO, otherNodes: LearningPathNodeDTO[]): LearningPathNode { - return new LearningPathNode( - dto.learningobject_hruid, - dto.version, - dto.language, - dto.transitions.map(transDto => { - let nextNodeDto = otherNodes.filter(it => - it.learningobject_hruid === transDto.next.hruid - && it.language === transDto.next.language - && it.version === transDto.next.version - ); - if (nextNodeDto.length !== 1) { - throw new Error(`Invalid learning path! There is a transition to node` - + `${transDto.next.hruid}/${transDto.next.language}/${transDto.next.version}, but there are` - + `${nextNodeDto.length} such nodes.`); - } - return { - next: LearningPathNode.fromDTOAndOtherNodes(nextNodeDto[0], otherNodes), - default: transDto.default - } - }), - new Date(dto.created_at), - new Date(dto.updatedAt), - dto.done - ) - } -} - -export class LearningPath { - constructor( - public readonly language: string, - public readonly hruid: string, - public readonly title: string, - public readonly description: string, - public readonly amountOfNodes: number, - public readonly amountOfNodesLeft: number, - public readonly keywords: string[], - public readonly targetAges: {min: number; max: number}, - public readonly startNode: LearningPathNode, - public readonly image?: string // Image might be missing, so it's optional - ) { - } - - public get nodesAsList(): LearningPathNode[] { - let list: LearningPathNode[] = []; - let currentNode = this.startNode; - while (currentNode) { - list.push(currentNode); - currentNode = currentNode.transitions.filter(it => it.default)[0]?.next - || currentNode.transitions[0]?.next; - } - return list; - } - - static fromDTO(dto: LearningPathDTO): LearningPath { - let startNodeDto = dto.nodes.filter(it => it.start_node === true); - if (startNodeDto.length !== 1) { - throw new Error(`Invalid learning path: ${dto.hruid}/${dto.language}! - Expected precisely one start node, but there were ${startNodeDto.length}.`); - } - return new LearningPath( - dto.language, - dto.hruid, - dto.title, - dto.description, - dto.num_nodes, - dto.num_nodes_left, - dto.keywords.split(' '), - {min: dto.min_age, max: dto.max_age}, - LearningPathNode.fromDTOAndOtherNodes(startNodeDto[0], dto.nodes), - dto.image - ) - } -} diff --git a/frontend/src/data-objects/learning-paths/learning-path-dto.ts b/frontend/src/data-objects/learning-paths/learning-path-dto.ts new file mode 100644 index 00000000..5e0f8746 --- /dev/null +++ b/frontend/src/data-objects/learning-paths/learning-path-dto.ts @@ -0,0 +1,17 @@ +import type {LearningPathNodeDTO} from "@/data-objects/learning-paths/learning-path.ts"; + +export interface LearningPathDTO { + language: string; + hruid: string; + title: string; + description: string; + image?: string; // Image might be missing, so it's optional + num_nodes: number; + num_nodes_left: number; + nodes: LearningPathNodeDTO[]; + keywords: string; + target_ages: number[]; + min_age: number; + max_age: number; + __order: number; +} diff --git a/frontend/src/data-objects/learning-paths/learning-path-node.ts b/frontend/src/data-objects/learning-paths/learning-path-node.ts new file mode 100644 index 00000000..d423f6bc --- /dev/null +++ b/frontend/src/data-objects/learning-paths/learning-path-node.ts @@ -0,0 +1,57 @@ +import type {Language} from "@/data-objects/language.ts"; +import type {LearningPathNodeDTO} from "@/data-objects/learning-paths/learning-path.ts"; + +export class LearningPathNode { + public readonly learningobjectHruid: string; + public readonly version: number; + public readonly language: Language; + public readonly transitions: { next: LearningPathNode, default: boolean }[]; + public readonly createdAt: Date; + public readonly updatedAt: Date; + public readonly done: boolean; + + constructor(options: { + learningobjectHruid: string, + version: number, + language: Language, + transitions: { next: LearningPathNode, default: boolean }[], + createdAt: Date, + updatedAt: Date, + done?: boolean + }) { + this.learningobjectHruid = options.learningobjectHruid; + this.version = options.version; + this.language = options.language; + this.transitions = options.transitions; + this.createdAt = options.createdAt; + this.updatedAt = options.updatedAt; + this.done = options.done || false; + } + + static fromDTOAndOtherNodes(dto: LearningPathNodeDTO, otherNodes: LearningPathNodeDTO[]): LearningPathNode { + return new LearningPathNode({ + learningobjectHruid: dto.learningobject_hruid, + version: dto.version, + language: dto.language, + transitions: dto.transitions.map(transDto => { + const nextNodeDto = otherNodes.filter(it => + it.learningobject_hruid === transDto.next.hruid + && it.language === transDto.next.language + && it.version === transDto.next.version + ); + if (nextNodeDto.length !== 1) { + throw new Error(`Invalid learning path! There is a transition to node` + + `${transDto.next.hruid}/${transDto.next.language}/${transDto.next.version}, but there are` + + `${nextNodeDto.length} such nodes.`); + } + return { + next: LearningPathNode.fromDTOAndOtherNodes(nextNodeDto[0], otherNodes), + default: transDto.default + } + }), + createdAt: new Date(dto.created_at), + updatedAt: new Date(dto.updatedAt), + done: dto.done + }) + } +} diff --git a/frontend/src/data-objects/learning-paths/learning-path.ts b/frontend/src/data-objects/learning-paths/learning-path.ts new file mode 100644 index 00000000..00a33522 --- /dev/null +++ b/frontend/src/data-objects/learning-paths/learning-path.ts @@ -0,0 +1,94 @@ +import type {Language} from "@/data-objects/language.ts"; +import {LearningPathNode} from "@/data-objects/learning-paths/learning-path-node.ts"; +import type {LearningPathDTO} from "@/data-objects/learning-paths/learning-path-dto.ts"; + +export interface LearningPathNodeDTO { + _id: string; + learningobject_hruid: string; + version: number; + language: Language; + start_node?: boolean; + transitions: LearningPathTransitionDTO[]; + created_at: string; + updatedAt: string; + done?: boolean; // True if a submission exists for this node by the user for whom the learning path is customized. +} + +export interface LearningPathTransitionDTO { + default: boolean; + _id: string; + next: { + _id: string; + hruid: string; + version: number; + language: string; + }; +} + +export class LearningPath { + public readonly language: string; + public readonly hruid: string; + public readonly title: string; + public readonly description: string; + public readonly amountOfNodes: number; + public readonly amountOfNodesLeft: number; + public readonly keywords: string[]; + public readonly targetAges: {min: number; max: number}; + public readonly startNode: LearningPathNode; + public readonly image?: string; // Image might be missing, so it's optional + + constructor(options: { + language: string, + hruid: string, + title: string, + description: string, + amountOfNodes: number, + amountOfNodesLeft: number, + keywords: string[], + targetAges: {min: number; max: number}, + startNode: LearningPathNode, + image?: string // Image might be missing, so it's optional + }) { + this.language = options.language; + this.hruid = options.hruid; + this.title = options.title; + this.description = options.description; + this.amountOfNodes = options.amountOfNodes; + this.amountOfNodesLeft = options.amountOfNodesLeft; + this.keywords = options.keywords; + this.targetAges = options.targetAges; + this.startNode = options.startNode; + this.image = options.image; + } + + public get nodesAsList(): LearningPathNode[] { + const list: LearningPathNode[] = []; + let currentNode = this.startNode; + while (currentNode) { + list.push(currentNode); + currentNode = currentNode.transitions.find(it => it.default)?.next + || currentNode.transitions[0]?.next; + } + return list; + } + + static fromDTO(dto: LearningPathDTO): LearningPath { + const startNodeDto = dto.nodes.filter(it => it.start_node === true); + if (startNodeDto.length !== 1) { + throw new Error(`Invalid learning path: ${dto.hruid}/${dto.language}! + Expected precisely one start node, but there were ${startNodeDto.length}.`); + } + return new LearningPath({ + language: dto.language, + hruid: dto.hruid, + title: dto.title, + description: dto.description, + amountOfNodes: dto.num_nodes, + amountOfNodesLeft: dto.num_nodes_left, + keywords: dto.keywords.split(' '), + targetAges: {min: dto.min_age, max: dto.max_age}, + startNode: LearningPathNode.fromDTOAndOtherNodes(startNodeDto[0], dto.nodes), + image: dto.image + }); + } +} diff --git a/frontend/src/exception/invalid-response-exception.ts b/frontend/src/exception/invalid-response-exception.ts new file mode 100644 index 00000000..5cbd35b3 --- /dev/null +++ b/frontend/src/exception/invalid-response-exception.ts @@ -0,0 +1,5 @@ +export class InvalidResponseException extends Error { + constructor(message: string) { + super(message); + } +} diff --git a/frontend/src/exception/not-found-exception.ts b/frontend/src/exception/not-found-exception.ts new file mode 100644 index 00000000..fd5b29a6 --- /dev/null +++ b/frontend/src/exception/not-found-exception.ts @@ -0,0 +1,5 @@ +export class NotFoundException extends Error { + constructor(message: string) { + super(message); + } +} diff --git a/frontend/src/queries/learning-objects.ts b/frontend/src/queries/learning-objects.ts index 93821873..df858a36 100644 --- a/frontend/src/queries/learning-objects.ts +++ b/frontend/src/queries/learning-objects.ts @@ -2,8 +2,8 @@ import {type MaybeRefOrGetter, toValue} from "vue"; import type {Language} from "@/data-objects/language.ts"; import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query"; import {getLearningObjectController} from "@/controllers/controllers.ts"; -import type {LearningObject} from "@/data-objects/learning-object.ts"; -import type {LearningPath} from "@/data-objects/learning-path.ts"; +import type {LearningObject} from "@/data-objects/learning-objects/learning-object.ts"; +import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts"; const LEARNING_OBJECT_KEY = "learningObject"; const learningObjectController = getLearningObjectController(); @@ -15,7 +15,7 @@ export function useLearningObjectMetadataQuery( ): UseQueryReturnType { return useQuery({ queryKey: [LEARNING_OBJECT_KEY, "metadata", hruid, language, version], - queryFn: () => { + queryFn: async () => { const [hruidVal, languageVal, versionVal] = [toValue(hruid), toValue(language), toValue(version)]; return learningObjectController.getMetadata(hruidVal, languageVal, versionVal) }, @@ -30,7 +30,7 @@ export function useLearningObjectHTMLQuery( ): UseQueryReturnType { return useQuery({ queryKey: [LEARNING_OBJECT_KEY, "html", hruid, language, version], - queryFn: () => { + queryFn: async () => { const [hruidVal, languageVal, versionVal] = [toValue(hruid), toValue(language), toValue(version)]; return learningObjectController.getHTML(hruidVal, languageVal, versionVal) }, @@ -43,9 +43,9 @@ export function useLearningObjectListForPathQuery( ): UseQueryReturnType { return useQuery({ queryKey: [LEARNING_OBJECT_KEY, "onPath", learningPath], - queryFn: () => { - let learningObjects = []; - for (let node of toValue(learningPath).nodesAsList) { + queryFn: async () => { + const learningObjects = []; + for (const node of toValue(learningPath).nodesAsList) { learningObjects.push( learningObjectController.getMetadata(node.learningobjectHruid, node.language, node.version) ); diff --git a/frontend/src/queries/learning-paths.ts b/frontend/src/queries/learning-paths.ts index ca0dac10..032aa493 100644 --- a/frontend/src/queries/learning-paths.ts +++ b/frontend/src/queries/learning-paths.ts @@ -2,7 +2,7 @@ import {type MaybeRefOrGetter, toValue} from "vue"; import type {Language} from "@/data-objects/language.ts"; import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query"; import { getLearningPathController } from "@/controllers/controllers"; -import type {LearningPath} from "@/data-objects/learning-path.ts"; +import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts"; const LEARNING_PATH_KEY = "learningPath"; const learningPathController = getLearningPathController(); @@ -14,7 +14,7 @@ export function useGetLearningPathQuery( ): UseQueryReturnType { return useQuery({ queryKey: [LEARNING_PATH_KEY, "get", hruid, language, options], - queryFn: () => { + queryFn: async () => { const [hruidVal, languageVal, optionsVal] = [toValue(hruid), toValue(language), toValue(options)]; return learningPathController.getBy(hruidVal, languageVal, optionsVal) }, @@ -27,9 +27,7 @@ export function useGetAllLearningPathsByThemeQuery( ): UseQueryReturnType { return useQuery({ queryKey: [LEARNING_PATH_KEY, "getAllByTheme", theme], - queryFn: () => { - return learningPathController.getAllByTheme(toValue(theme)) - }, + queryFn: async () => learningPathController.getAllByTheme(toValue(theme)), enabled: () => Boolean(toValue(theme)), }) } @@ -39,7 +37,7 @@ export function useSearchLearningPathQuery( ): UseQueryReturnType { return useQuery({ queryKey: [LEARNING_PATH_KEY, "search", query], - queryFn: () => { + queryFn: async () => { const queryVal = toValue(query); return learningPathController.search(queryVal); }, diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index cc32bb35..64c49d25 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -15,6 +15,7 @@ import LearningPathPage from "@/views/learning-paths/LearningPathPage.vue"; import LearningPathSearchPage from "@/views/learning-paths/LearningPathSearchPage.vue"; import UserHomePage from "@/views/homepage/UserHomePage.vue"; import SingleTheme from "@/views/SingleTheme.vue"; +import LearningObjectView from "@/views/learning-paths/LearningObjectView.vue"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -117,22 +118,21 @@ const router = createRouter({ meta: { requiresAuth: true } }, { - path: ":hruid/:language", + path: ":hruid/:language/:learningObjectHruid", name: "LearningPath", component: LearningPathPage, props: true, meta: { requiresAuth: true }, - children: [ - { - path: ":learningObjectHruid", - component: LearningPathPage, - props: true, - meta: { requiresAuth: true } - } - ] }, ] }, + { + path: "/learningObject/:hruid/:language/:version/raw", + name: "LearningObjectView", + component: LearningObjectView, + props: true, + meta: { requiresAuth: true } + }, { path: "/:catchAll(.*)", name: "NotFound", diff --git a/frontend/src/services/api-client/api-exceptions.ts b/frontend/src/services/api-client/api-exceptions.ts deleted file mode 100644 index d2fa2ac2..00000000 --- a/frontend/src/services/api-client/api-exceptions.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type {AxiosResponse} from "axios"; - -export class HttpErrorStatusException extends Error { - public readonly statusCode: number; - - constructor(response: AxiosResponse) { - super(`${response.statusText} (${response.status})`); - this.statusCode = response.status; - } -} - -export class NotFoundException extends Error { - constructor(message: string) { - super(message); - } -} - -export class InvalidResponseException extends Error { - constructor(message: string) { - super(message); - } -} diff --git a/frontend/src/utils/response-assertions.ts b/frontend/src/utils/response-assertions.ts index 5be421ff..ebc6f9c0 100644 --- a/frontend/src/utils/response-assertions.ts +++ b/frontend/src/utils/response-assertions.ts @@ -1,4 +1,5 @@ -import {InvalidResponseException, NotFoundException} from "@/services/api-client/api-exceptions.ts"; +import {NotFoundException} from "@/exception/not-found-exception.ts"; +import {InvalidResponseException} from "@/exception/invalid-response-exception.ts"; export function single(list: T[]): T { if (list.length === 1) { diff --git a/frontend/src/views/CallbackPage.vue b/frontend/src/views/CallbackPage.vue index 45a0134f..7d792d96 100644 --- a/frontend/src/views/CallbackPage.vue +++ b/frontend/src/views/CallbackPage.vue @@ -1,22 +1,25 @@ diff --git a/frontend/src/views/HomePage.vue b/frontend/src/views/HomePage.vue index 1c4d716a..08ce44c1 100644 --- a/frontend/src/views/HomePage.vue +++ b/frontend/src/views/HomePage.vue @@ -1,6 +1,4 @@ @@ -151,6 +134,7 @@ :to="{path: node.key, query: route.query}" :title="node.title" :active="node.key === props.learningObjectHruid" + :key="node.key" v-if="!node.teacherExclusive || authService.authState.activeRole === 'teacher'" >