fix(frontend): Linting errors/warnings opgelost
This commit is contained in:
parent
b2e6b33716
commit
4d98be78c1
26 changed files with 272 additions and 258 deletions
|
@ -10,12 +10,12 @@
|
||||||
|
|
||||||
const query = computed({
|
const query = computed({
|
||||||
get: () => route.query.query as string | null,
|
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);
|
const queryInput = ref(query.value);
|
||||||
|
|
||||||
function search() {
|
function search(): void {
|
||||||
query.value = queryInput.value;
|
query.value = queryInput.value;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import {convertBase64ToImageSrc} from "@/utils/base64ToImage.ts";
|
import {convertBase64ToImageSrc} from "@/utils/base64ToImage.ts";
|
||||||
import type {LearningPath} from "@/data-objects/learning-path.ts";
|
import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -15,6 +15,7 @@ const props = defineProps<{learningPaths: LearningPath[]}>();
|
||||||
class="learning-path-card"
|
class="learning-path-card"
|
||||||
link
|
link
|
||||||
:to="`/learningPath/${learningPath.hruid}/${learningPath.language}/${learningPath.startNode.learningobjectHruid}`"
|
:to="`/learningPath/${learningPath.hruid}/${learningPath.language}/${learningPath.startNode.learningobjectHruid}`"
|
||||||
|
:key="[learningPath.hruid, learningPath.language]"
|
||||||
v-for="learningPath in props.learningPaths"
|
v-for="learningPath in props.learningPaths"
|
||||||
>
|
>
|
||||||
<v-img
|
<v-img
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const errorMessage = computed(() => {
|
const errorMessage = computed(() => {
|
||||||
let errorWithMessage = (error.value as {message: string}) || null;
|
const errorWithMessage = (error.value as {message: string}) || null;
|
||||||
return errorWithMessage?.message || JSON.stringify(errorWithMessage)
|
return errorWithMessage?.message || JSON.stringify(errorWithMessage)
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,40 +9,42 @@ export abstract class BaseController {
|
||||||
this.basePath = basePath;
|
this.basePath = basePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private assertSuccessResponse(response: AxiosResponse<unknown, unknown>) {
|
private static assertSuccessResponse(response: AxiosResponse<unknown, unknown>): void {
|
||||||
if (response.status / 100 !== 2) {
|
if (response.status / 100 !== 2) {
|
||||||
throw new HttpErrorResponseException(response);
|
throw new HttpErrorResponseException(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private absolutePathFor(path: string) {
|
protected async get<T>(path: string, queryParams?: QueryParams, responseType?: ResponseType): Promise<T> {
|
||||||
return "/" + this.basePath + path;
|
const response = await apiClient.get<T>(
|
||||||
}
|
|
||||||
|
|
||||||
protected async get<T>(path: string, queryParams?: Record<string, any>, responseType?: ResponseType): Promise<T> {
|
|
||||||
let response = await apiClient.get<T>(
|
|
||||||
this.absolutePathFor(path),
|
this.absolutePathFor(path),
|
||||||
{params: queryParams, responseType}
|
{params: queryParams, responseType}
|
||||||
);
|
);
|
||||||
this.assertSuccessResponse(response);
|
BaseController.assertSuccessResponse(response);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async post<T>(path: string, body: unknown): Promise<T> {
|
protected async post<T>(path: string, body: unknown): Promise<T> {
|
||||||
let response = await apiClient.post<T>(this.absolutePathFor(path), body);
|
const response = await apiClient.post<T>(this.absolutePathFor(path), body);
|
||||||
this.assertSuccessResponse(response);
|
BaseController.assertSuccessResponse(response);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async delete<T>(path: string): Promise<T> {
|
protected async delete<T>(path: string): Promise<T> {
|
||||||
let response = await apiClient.delete<T>(this.absolutePathFor(path))
|
const response = await apiClient.delete<T>(this.absolutePathFor(path))
|
||||||
this.assertSuccessResponse(response);
|
BaseController.assertSuccessResponse(response);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async put<T>(path: string, body: unknown): Promise<T> {
|
protected async put<T>(path: string, body: unknown): Promise<T> {
|
||||||
let response = await apiClient.put<T>(this.absolutePathFor(path), body);
|
const response = await apiClient.put<T>(this.absolutePathFor(path), body);
|
||||||
this.assertSuccessResponse(response);
|
BaseController.assertSuccessResponse(response);
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private absolutePathFor(path: string): string {
|
||||||
|
return "/" + this.basePath + path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryParams = Record<string, string | number | boolean | undefined>;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {BaseController} from "@/controllers/base-controller.ts";
|
import {BaseController} from "@/controllers/base-controller.ts";
|
||||||
import type {Language} from "@/data-objects/language.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 {
|
export class LearningObjectController extends BaseController {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
import {BaseController} from "@/controllers/base-controller.ts";
|
import {BaseController} from "@/controllers/base-controller.ts";
|
||||||
import {LearningPath} from "@/data-objects/learning-path.ts";
|
import {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
|
||||||
import type {LearningPathDTO} from "@/data-objects/learning-path.ts";
|
|
||||||
import type {Language} from "@/data-objects/language.ts";
|
import type {Language} from "@/data-objects/language.ts";
|
||||||
import {single} from "@/utils/response-assertions.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 {
|
export class LearningPathController extends BaseController {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("learningPath");
|
super("learningPath");
|
||||||
}
|
}
|
||||||
async search(query: string) {
|
async search(query: string): Promise<LearningPath[]> {
|
||||||
let dtos = await this.get<LearningPathDTO[]>("/", {search: query});
|
const dtos = await this.get<LearningPathDTO[]>("/", {search: query});
|
||||||
return dtos.map(dto => LearningPath.fromDTO(dto));
|
return dtos.map(dto => LearningPath.fromDTO(dto));
|
||||||
}
|
}
|
||||||
async getBy(hruid: string, language: Language, options?: {forGroup?: string, forStudent?: string}) {
|
async getBy(hruid: string, language: Language, options?: {forGroup?: string, forStudent?: string}): Promise<LearningPath> {
|
||||||
let dtos = await this.get<LearningPathDTO[]>("/", {
|
const dtos = await this.get<LearningPathDTO[]>("/", {
|
||||||
hruid,
|
hruid,
|
||||||
language,
|
language,
|
||||||
forGroup: options?.forGroup,
|
forGroup: options?.forGroup,
|
||||||
|
@ -21,8 +21,8 @@ export class LearningPathController extends BaseController {
|
||||||
});
|
});
|
||||||
return LearningPath.fromDTO(single(dtos));
|
return LearningPath.fromDTO(single(dtos));
|
||||||
}
|
}
|
||||||
async getAllByTheme(theme: string) {
|
async getAllByTheme(theme: string): Promise<LearningPath[]> {
|
||||||
let dtos = await this.get<LearningPathDTO[]>("/", {theme});
|
const dtos = await this.get<LearningPathDTO[]>("/", {theme});
|
||||||
return dtos.map(dto => LearningPath.fromDTO(dto));
|
return dtos.map(dto => LearningPath.fromDTO(dto));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
export interface EducationalGoal {
|
||||||
|
source: string;
|
||||||
|
id: string;
|
||||||
|
}
|
|
@ -1,14 +1,6 @@
|
||||||
import type {Language} from "@/data-objects/language.ts";
|
import type {Language} from "@/data-objects/language.ts";
|
||||||
|
import type {ReturnValue} from "@/data-objects/learning-objects/return-value.ts";
|
||||||
export interface EducationalGoal {
|
import type {EducationalGoal} from "@/data-objects/learning-objects/educational-goal.ts";
|
||||||
source: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReturnValue {
|
|
||||||
callback_url: string;
|
|
||||||
callback_schema: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LearningObject {
|
export interface LearningObject {
|
||||||
key: string;
|
key: string;
|
|
@ -0,0 +1,4 @@
|
||||||
|
export interface ReturnValue {
|
||||||
|
callback_url: string;
|
||||||
|
callback_schema: Record<string, unknown>;
|
||||||
|
}
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
94
frontend/src/data-objects/learning-paths/learning-path.ts
Normal file
94
frontend/src/data-objects/learning-paths/learning-path.ts
Normal file
|
@ -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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
5
frontend/src/exception/invalid-response-exception.ts
Normal file
5
frontend/src/exception/invalid-response-exception.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export class InvalidResponseException extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
5
frontend/src/exception/not-found-exception.ts
Normal file
5
frontend/src/exception/not-found-exception.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export class NotFoundException extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,8 @@ import {type MaybeRefOrGetter, toValue} from "vue";
|
||||||
import type {Language} from "@/data-objects/language.ts";
|
import type {Language} from "@/data-objects/language.ts";
|
||||||
import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query";
|
import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query";
|
||||||
import {getLearningObjectController} from "@/controllers/controllers.ts";
|
import {getLearningObjectController} from "@/controllers/controllers.ts";
|
||||||
import type {LearningObject} from "@/data-objects/learning-object.ts";
|
import type {LearningObject} from "@/data-objects/learning-objects/learning-object.ts";
|
||||||
import type {LearningPath} from "@/data-objects/learning-path.ts";
|
import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
|
||||||
|
|
||||||
const LEARNING_OBJECT_KEY = "learningObject";
|
const LEARNING_OBJECT_KEY = "learningObject";
|
||||||
const learningObjectController = getLearningObjectController();
|
const learningObjectController = getLearningObjectController();
|
||||||
|
@ -15,7 +15,7 @@ export function useLearningObjectMetadataQuery(
|
||||||
): UseQueryReturnType<LearningObject, Error> {
|
): UseQueryReturnType<LearningObject, Error> {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [LEARNING_OBJECT_KEY, "metadata", hruid, language, version],
|
queryKey: [LEARNING_OBJECT_KEY, "metadata", hruid, language, version],
|
||||||
queryFn: () => {
|
queryFn: async () => {
|
||||||
const [hruidVal, languageVal, versionVal] = [toValue(hruid), toValue(language), toValue(version)];
|
const [hruidVal, languageVal, versionVal] = [toValue(hruid), toValue(language), toValue(version)];
|
||||||
return learningObjectController.getMetadata(hruidVal, languageVal, versionVal)
|
return learningObjectController.getMetadata(hruidVal, languageVal, versionVal)
|
||||||
},
|
},
|
||||||
|
@ -30,7 +30,7 @@ export function useLearningObjectHTMLQuery(
|
||||||
): UseQueryReturnType<Document, Error> {
|
): UseQueryReturnType<Document, Error> {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [LEARNING_OBJECT_KEY, "html", hruid, language, version],
|
queryKey: [LEARNING_OBJECT_KEY, "html", hruid, language, version],
|
||||||
queryFn: () => {
|
queryFn: async () => {
|
||||||
const [hruidVal, languageVal, versionVal] = [toValue(hruid), toValue(language), toValue(version)];
|
const [hruidVal, languageVal, versionVal] = [toValue(hruid), toValue(language), toValue(version)];
|
||||||
return learningObjectController.getHTML(hruidVal, languageVal, versionVal)
|
return learningObjectController.getHTML(hruidVal, languageVal, versionVal)
|
||||||
},
|
},
|
||||||
|
@ -43,9 +43,9 @@ export function useLearningObjectListForPathQuery(
|
||||||
): UseQueryReturnType<LearningObject, Error> {
|
): UseQueryReturnType<LearningObject, Error> {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [LEARNING_OBJECT_KEY, "onPath", learningPath],
|
queryKey: [LEARNING_OBJECT_KEY, "onPath", learningPath],
|
||||||
queryFn: () => {
|
queryFn: async () => {
|
||||||
let learningObjects = [];
|
const learningObjects = [];
|
||||||
for (let node of toValue(learningPath).nodesAsList) {
|
for (const node of toValue(learningPath).nodesAsList) {
|
||||||
learningObjects.push(
|
learningObjects.push(
|
||||||
learningObjectController.getMetadata(node.learningobjectHruid, node.language, node.version)
|
learningObjectController.getMetadata(node.learningobjectHruid, node.language, node.version)
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {type MaybeRefOrGetter, toValue} from "vue";
|
||||||
import type {Language} from "@/data-objects/language.ts";
|
import type {Language} from "@/data-objects/language.ts";
|
||||||
import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query";
|
import {useQuery, type UseQueryReturnType} from "@tanstack/vue-query";
|
||||||
import { getLearningPathController } from "@/controllers/controllers";
|
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 LEARNING_PATH_KEY = "learningPath";
|
||||||
const learningPathController = getLearningPathController();
|
const learningPathController = getLearningPathController();
|
||||||
|
@ -14,7 +14,7 @@ export function useGetLearningPathQuery(
|
||||||
): UseQueryReturnType<LearningPath, Error> {
|
): UseQueryReturnType<LearningPath, Error> {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [LEARNING_PATH_KEY, "get", hruid, language, options],
|
queryKey: [LEARNING_PATH_KEY, "get", hruid, language, options],
|
||||||
queryFn: () => {
|
queryFn: async () => {
|
||||||
const [hruidVal, languageVal, optionsVal] = [toValue(hruid), toValue(language), toValue(options)];
|
const [hruidVal, languageVal, optionsVal] = [toValue(hruid), toValue(language), toValue(options)];
|
||||||
return learningPathController.getBy(hruidVal, languageVal, optionsVal)
|
return learningPathController.getBy(hruidVal, languageVal, optionsVal)
|
||||||
},
|
},
|
||||||
|
@ -27,9 +27,7 @@ export function useGetAllLearningPathsByThemeQuery(
|
||||||
): UseQueryReturnType<LearningPath[], Error> {
|
): UseQueryReturnType<LearningPath[], Error> {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [LEARNING_PATH_KEY, "getAllByTheme", theme],
|
queryKey: [LEARNING_PATH_KEY, "getAllByTheme", theme],
|
||||||
queryFn: () => {
|
queryFn: async () => learningPathController.getAllByTheme(toValue(theme)),
|
||||||
return learningPathController.getAllByTheme(toValue(theme))
|
|
||||||
},
|
|
||||||
enabled: () => Boolean(toValue(theme)),
|
enabled: () => Boolean(toValue(theme)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -39,7 +37,7 @@ export function useSearchLearningPathQuery(
|
||||||
): UseQueryReturnType<LearningPath[], Error> {
|
): UseQueryReturnType<LearningPath[], Error> {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [LEARNING_PATH_KEY, "search", query],
|
queryKey: [LEARNING_PATH_KEY, "search", query],
|
||||||
queryFn: () => {
|
queryFn: async () => {
|
||||||
const queryVal = toValue(query);
|
const queryVal = toValue(query);
|
||||||
return learningPathController.search(queryVal);
|
return learningPathController.search(queryVal);
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@ import LearningPathPage from "@/views/learning-paths/LearningPathPage.vue";
|
||||||
import LearningPathSearchPage from "@/views/learning-paths/LearningPathSearchPage.vue";
|
import LearningPathSearchPage from "@/views/learning-paths/LearningPathSearchPage.vue";
|
||||||
import UserHomePage from "@/views/homepage/UserHomePage.vue";
|
import UserHomePage from "@/views/homepage/UserHomePage.vue";
|
||||||
import SingleTheme from "@/views/SingleTheme.vue";
|
import SingleTheme from "@/views/SingleTheme.vue";
|
||||||
|
import LearningObjectView from "@/views/learning-paths/LearningObjectView.vue";
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
@ -117,22 +118,21 @@ const router = createRouter({
|
||||||
meta: { requiresAuth: true }
|
meta: { requiresAuth: true }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ":hruid/:language",
|
path: ":hruid/:language/:learningObjectHruid",
|
||||||
name: "LearningPath",
|
name: "LearningPath",
|
||||||
component: LearningPathPage,
|
component: LearningPathPage,
|
||||||
props: true,
|
props: true,
|
||||||
meta: { requiresAuth: 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(.*)",
|
path: "/:catchAll(.*)",
|
||||||
name: "NotFound",
|
name: "NotFound",
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
import type {AxiosResponse} from "axios";
|
|
||||||
|
|
||||||
export class HttpErrorStatusException extends Error {
|
|
||||||
public readonly statusCode: number;
|
|
||||||
|
|
||||||
constructor(response: AxiosResponse<any, any>) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<T>(list: T[]): T {
|
export function single<T>(list: T[]): T {
|
||||||
if (list.length === 1) {
|
if (list.length === 1) {
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { onMounted } from "vue";
|
import {onMounted, ref, type Ref} from "vue";
|
||||||
import auth from "../services/auth/auth-service.ts";
|
import auth from "../services/auth/auth-service.ts";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const errorMessage: Ref<string | null> = ref(null);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
try {
|
||||||
await auth.handleLoginCallback();
|
await auth.handleLoginCallback();
|
||||||
await router.replace("/user"); // Redirect to theme page
|
await router.replace("/user"); // Redirect to theme page
|
||||||
} catch (_error) {
|
} catch (error) {
|
||||||
// FIXME console.error("OIDC callback error:", error);
|
errorMessage.value = `OIDC callback error: ${error}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<p>Logging you in...</p>
|
<p v-if="!errorMessage">Logging you in...</p>
|
||||||
|
<p v-else>{{ errorMessage }}</p>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import auth from "@/services/auth/auth-service.ts";
|
|
||||||
import apiClient from "@/services/api-client/api-client.ts";
|
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg";
|
import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type {LearningPath} from "@/data-objects/learning-path.ts";
|
import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
|
||||||
import LearningPathsGrid from "@/components/LearningPathsGrid.vue";
|
import LearningPathsGrid from "@/components/LearningPathsGrid.vue";
|
||||||
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
||||||
import {useGetAllLearningPathsByThemeQuery} from "@/queries/learning-paths.ts";
|
import {useGetAllLearningPathsByThemeQuery} from "@/queries/learning-paths.ts";
|
||||||
|
@ -23,7 +23,7 @@ const learningPathsForThemeQueryResult = useGetAllLearningPathsByThemeQuery(() =
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const searchFilter = ref("");
|
const searchFilter = ref("");
|
||||||
|
|
||||||
function filterLearningPaths(learningPaths: LearningPath[]) {
|
function filterLearningPaths(learningPaths: LearningPath[]): LearningPath[] {
|
||||||
return learningPaths.filter(it =>
|
return learningPaths.filter(it =>
|
||||||
it.title.toLowerCase().includes(searchFilter.value.toLowerCase())
|
it.title.toLowerCase().includes(searchFilter.value.toLowerCase())
|
||||||
|| it.description.toLowerCase().includes(searchFilter.value.toLowerCase)
|
|| it.description.toLowerCase().includes(searchFilter.value.toLowerCase)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {Language} from "@/data-objects/language.ts";
|
import {Language} from "@/data-objects/language.ts";
|
||||||
import {type UseQueryReturnType} from "@tanstack/vue-query";
|
import type {UseQueryReturnType} from "@tanstack/vue-query";
|
||||||
import {useLearningObjectHTMLQuery} from "@/queries/learning-objects.ts";
|
import {useLearningObjectHTMLQuery} from "@/queries/learning-objects.ts";
|
||||||
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {Language} from "@/data-objects/language.ts";
|
import {Language} from "@/data-objects/language.ts";
|
||||||
import {type LearningPath, LearningPathNode} from "@/data-objects/learning-path.ts";
|
import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
|
||||||
import {computed, type ComputedRef, ref, watch} from "vue";
|
import {computed, type ComputedRef, ref} from "vue";
|
||||||
import type {LearningObject} from "@/data-objects/learning-object.ts";
|
import type {LearningObject} from "@/data-objects/learning-objects/learning-object.ts";
|
||||||
import {useRoute, useRouter} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
import {type SuccessState} from "@/services/api-client/remote-resource.ts";
|
|
||||||
import LearningObjectView from "@/views/learning-paths/LearningObjectView.vue";
|
import LearningObjectView from "@/views/learning-paths/LearningObjectView.vue";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import LearningPathSearchField from "@/components/LearningPathSearchField.vue";
|
import LearningPathSearchField from "@/components/LearningPathSearchField.vue";
|
||||||
|
@ -12,8 +11,8 @@
|
||||||
import {useLearningObjectListForPathQuery} from "@/queries/learning-objects.ts";
|
import {useLearningObjectListForPathQuery} from "@/queries/learning-objects.ts";
|
||||||
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
||||||
import authService from "@/services/auth/auth-service.ts";
|
import authService from "@/services/auth/auth-service.ts";
|
||||||
|
import {LearningPathNode} from "@/data-objects/learning-paths/learning-path-node.ts";
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
@ -30,11 +29,11 @@
|
||||||
forStudent: route.query.forStudent,
|
forStudent: route.query.forStudent,
|
||||||
forGroup: route.query.forGroup
|
forGroup: route.query.forGroup
|
||||||
} as Personalization
|
} as Personalization
|
||||||
} else {
|
}
|
||||||
return {
|
return {
|
||||||
forStudent: authService.authState.user?.profile?.preferred_username
|
forStudent: authService.authState.user?.profile?.preferred_username
|
||||||
} as Personalization
|
} as Personalization
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const learningPathQueryResult = useGetLearningPathQuery(
|
const learningPathQueryResult = useGetLearningPathQuery(
|
||||||
|
@ -51,61 +50,45 @@
|
||||||
|
|
||||||
const currentNode = computed(() => {
|
const currentNode = computed(() => {
|
||||||
const currentHruid = props.learningObjectHruid;
|
const currentHruid = props.learningObjectHruid;
|
||||||
if (nodesList.value) {
|
return nodesList.value?.find(it => it.learningobjectHruid === currentHruid);
|
||||||
return nodesList.value.filter(it => it.learningobjectHruid === currentHruid)[0]
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const nextNode = computed(() => {
|
const nextNode = computed(() => {
|
||||||
if (!currentNode.value || !nodesList.value)
|
if (!currentNode.value || !nodesList.value)
|
||||||
return;
|
return undefined;
|
||||||
const currentIndex = nodesList.value?.indexOf(currentNode.value);
|
const currentIndex = nodesList.value?.indexOf(currentNode.value);
|
||||||
if (currentIndex < nodesList.value?.length) {
|
return currentIndex < nodesList.value?.length ? nodesList.value?.[currentIndex + 1] : undefined;
|
||||||
return nodesList.value?.[currentIndex + 1];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const previousNode = computed(() => {
|
const previousNode = computed(() => {
|
||||||
if (!currentNode.value || !nodesList.value)
|
if (!currentNode.value || !nodesList.value)
|
||||||
return;
|
return undefined;
|
||||||
const currentIndex = nodesList.value?.indexOf(currentNode.value);
|
const currentIndex = nodesList.value?.indexOf(currentNode.value);
|
||||||
if (currentIndex < nodesList.value?.length) {
|
return currentIndex < nodesList.value?.length ? nodesList.value?.[currentIndex - 1] : undefined;
|
||||||
return nodesList.value?.[currentIndex - 1];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(() => learningPathQueryResult, (newValue) => {
|
|
||||||
if (learningPathQueryResult.isSuccess && false) {
|
|
||||||
router.push({
|
|
||||||
path: router.currentRoute.value.path + "/" + (newValue as SuccessState<LearningPath>).data.startNode.learningobjectHruid,
|
|
||||||
query: route.query,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const navigationDrawerShown = ref(true);
|
const navigationDrawerShown = ref(true);
|
||||||
|
|
||||||
|
|
||||||
function isLearningObjectCompleted(learningObject: LearningObject): boolean {
|
function isLearningObjectCompleted(learningObject: LearningObject): boolean {
|
||||||
if (learningObjectListQueryResult.isSuccess) {
|
if (learningObjectListQueryResult.isSuccess) {
|
||||||
return learningPathQueryResult.data.value.nodesAsList.filter(it =>
|
return learningPathQueryResult.data.value.nodesAsList.find(it =>
|
||||||
it.learningobjectHruid === learningObject.key
|
it.learningobjectHruid === learningObject.key
|
||||||
&& it.version === learningObject.version
|
&& it.version === learningObject.version
|
||||||
&& it.language == learningObject.language
|
&& it.language === learningObject.language
|
||||||
)[0].done;
|
).done;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
type NavItemState = "teacherExclusive" | "completed" | "notCompleted";
|
type NavItemState = "teacherExclusive" | "completed" | "notCompleted";
|
||||||
|
|
||||||
const ICONS: {[key: NavItemState]: string} = {
|
const ICONS: Record<NavItemState, string> = {
|
||||||
teacherExclusive: "mdi-information",
|
teacherExclusive: "mdi-information",
|
||||||
completed: "mdi-checkbox-marked-circle-outline",
|
completed: "mdi-checkbox-marked-circle-outline",
|
||||||
notCompleted: "mdi-checkbox-blank-circle-outline"
|
notCompleted: "mdi-checkbox-blank-circle-outline"
|
||||||
}
|
}
|
||||||
|
|
||||||
const COLORS: {[key: NavItemState]: string | undefined} = {
|
const COLORS: Record<NavItemState, string | undefined> = {
|
||||||
teacherExclusive: "info",
|
teacherExclusive: "info",
|
||||||
completed: "success",
|
completed: "success",
|
||||||
notCompleted: undefined
|
notCompleted: undefined
|
||||||
|
@ -116,9 +99,9 @@
|
||||||
return "teacherExclusive";
|
return "teacherExclusive";
|
||||||
} else if (isLearningObjectCompleted(learningObject)) {
|
} else if (isLearningObjectCompleted(learningObject)) {
|
||||||
return "completed";
|
return "completed";
|
||||||
} else {
|
|
||||||
return "notCompleted";
|
|
||||||
}
|
}
|
||||||
|
return "notCompleted";
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -151,6 +134,7 @@
|
||||||
:to="{path: node.key, query: route.query}"
|
:to="{path: node.key, query: route.query}"
|
||||||
:title="node.title"
|
:title="node.title"
|
||||||
:active="node.key === props.learningObjectHruid"
|
:active="node.key === props.learningObjectHruid"
|
||||||
|
:key="node.key"
|
||||||
v-if="!node.teacherExclusive || authService.authState.activeRole === 'teacher'"
|
v-if="!node.teacherExclusive || authService.authState.activeRole === 'teacher'"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type {LearningPath} from "@/data-objects/learning-path.ts";
|
import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
|
||||||
import {useRoute, useRouter} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
import {computed} from "vue";
|
import {computed} from "vue";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import LearningPathSearchField from "@/components/LearningPathSearchField.vue";
|
import LearningPathSearchField from "@/components/LearningPathSearchField.vue";
|
||||||
|
@ -9,7 +9,6 @@
|
||||||
import LearningPathsGrid from "@/components/LearningPathsGrid.vue";
|
import LearningPathsGrid from "@/components/LearningPathsGrid.vue";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const query = computed(() => route.query.query as string | null);
|
const query = computed(() => route.query.query as string | null);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue