Merge branch 'dev' into feat/homepagina
This commit is contained in:
commit
eaf6c97262
25 changed files with 622 additions and 153 deletions
19
.github/workflows/deployment.yml
vendored
Normal file
19
.github/workflows/deployment.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
name: Deployment
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
name: Deploy with docker
|
||||||
|
runs-on: [self-hosted, Linux, X64]
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
-
|
||||||
|
name: Start docker
|
||||||
|
run: docker compose -f compose.yml -f compose.prod.yml up --build -d
|
||||||
|
|
5
.github/workflows/lint-action.yml
vendored
5
.github/workflows/lint-action.yml
vendored
|
@ -11,6 +11,8 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
|
types: ["synchronize", "ready_for_review", "opened", "reopened"]
|
||||||
|
|
||||||
|
|
||||||
# Down scope as necessary via https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token
|
# Down scope as necessary via https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token
|
||||||
permissions:
|
permissions:
|
||||||
|
@ -20,6 +22,7 @@ permissions:
|
||||||
jobs:
|
jobs:
|
||||||
run-linters:
|
run-linters:
|
||||||
name: Run linters
|
name: Run linters
|
||||||
|
if: '! github.event.pull_request.draft'
|
||||||
runs-on: [self-hosted, Linux, X64]
|
runs-on: [self-hosted, Linux, X64]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -42,4 +45,4 @@ jobs:
|
||||||
eslint: true
|
eslint: true
|
||||||
eslint_args: '--config eslint.config.ts'
|
eslint_args: '--config eslint.config.ts'
|
||||||
prettier: true
|
prettier: true
|
||||||
commit_message: 'style: fix linting issues met ${linter}'
|
commit_message: 'style: fix linting issues met ${linter}'
|
3
backend/.env.test
Normal file
3
backend/.env.test
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PORT=3000
|
||||||
|
DWENGO_DB_UPDATE=true
|
||||||
|
DWENGO_DB_NAME=":memory:"
|
|
@ -19,7 +19,7 @@ export class Submission {
|
||||||
learningObjectVersion: number = 1;
|
learningObjectVersion: number = 1;
|
||||||
|
|
||||||
@PrimaryKey({ type: 'integer', autoincrement: true })
|
@PrimaryKey({ type: 'integer', autoincrement: true })
|
||||||
submissionNumber!: number;
|
submissionNumber?: number;
|
||||||
|
|
||||||
@ManyToOne({
|
@ManyToOne({
|
||||||
entity: () => Student,
|
entity: () => Student,
|
||||||
|
|
|
@ -39,14 +39,18 @@ async function getLearningObjectsForNodes(nodes: LearningPathNode[]): Promise<Ma
|
||||||
* Convert the given learning path entity to an object which conforms to the learning path content.
|
* Convert the given learning path entity to an object which conforms to the learning path content.
|
||||||
*/
|
*/
|
||||||
async function convertLearningPath(learningPath: LearningPathEntity, order: number, personalizedFor?: PersonalizationTarget): Promise<LearningPath> {
|
async function convertLearningPath(learningPath: LearningPathEntity, order: number, personalizedFor?: PersonalizationTarget): Promise<LearningPath> {
|
||||||
|
// Fetch the corresponding learning object for each node since some parts of the expected response contains parts
|
||||||
|
// With information which is not available in the LearningPathNodes themselves.
|
||||||
const nodesToLearningObjects: Map<LearningPathNode, FilteredLearningObject> = await getLearningObjectsForNodes(learningPath.nodes);
|
const nodesToLearningObjects: Map<LearningPathNode, FilteredLearningObject> = await getLearningObjectsForNodes(learningPath.nodes);
|
||||||
|
|
||||||
const targetAges = Array.from(nodesToLearningObjects.values()).flatMap((it) => it.targetAges || []);
|
// The target ages of a learning path are the union of the target ages of all learning objects.
|
||||||
|
const targetAges = [...new Set(Array.from(nodesToLearningObjects.values()).flatMap((it) => it.targetAges || []))];
|
||||||
const keywords = Array.from(nodesToLearningObjects.values()).flatMap((it) => it.keywords || []);
|
// The keywords of the learning path consist of the union of the keywords of all learning objects.
|
||||||
|
const keywords = [...new Set(Array.from(nodesToLearningObjects.values()).flatMap((it) => it.keywords || []))];
|
||||||
|
|
||||||
const image = learningPath.image ? learningPath.image.toString('base64') : undefined;
|
const image = learningPath.image ? learningPath.image.toString('base64') : undefined;
|
||||||
|
|
||||||
|
// Convert the learning object notes as retrieved from the database into the expected response format-
|
||||||
const convertedNodes = await convertNodes(nodesToLearningObjects, personalizedFor);
|
const convertedNodes = await convertNodes(nodesToLearningObjects, personalizedFor);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -67,34 +71,55 @@ async function convertLearningPath(learningPath: LearningPathEntity, order: numb
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function converting a single learning path node (as represented in the database) and the corresponding
|
||||||
|
* learning object into a learning path node as it should be represented in the API.
|
||||||
|
*
|
||||||
|
* @param node Learning path node as represented in the database.
|
||||||
|
* @param learningObject Learning object the learning path node refers to.
|
||||||
|
* @param personalizedFor Personalization target if a personalized learning path is desired.
|
||||||
|
* @param nodesToLearningObjects Mapping from learning path nodes to the corresponding learning objects.
|
||||||
|
*/
|
||||||
|
async function convertNode(
|
||||||
|
node: LearningPathNode,
|
||||||
|
learningObject: FilteredLearningObject,
|
||||||
|
personalizedFor: PersonalizationTarget | undefined,
|
||||||
|
nodesToLearningObjects: Map<LearningPathNode, FilteredLearningObject>
|
||||||
|
): Promise<LearningObjectNode> {
|
||||||
|
const lastSubmission = personalizedFor ? await getLastSubmissionForCustomizationTarget(node, personalizedFor) : null;
|
||||||
|
const transitions = node.transitions
|
||||||
|
.filter(
|
||||||
|
(trans) =>
|
||||||
|
!personalizedFor || // If we do not want a personalized learning path, keep all transitions
|
||||||
|
isTransitionPossible(trans, optionalJsonStringToObject(lastSubmission?.content)) // Otherwise remove all transitions that aren't possible.
|
||||||
|
)
|
||||||
|
.map((trans, i) => convertTransition(trans, i, nodesToLearningObjects));
|
||||||
|
return {
|
||||||
|
_id: learningObject.uuid,
|
||||||
|
language: learningObject.language,
|
||||||
|
start_node: node.startNode,
|
||||||
|
created_at: node.createdAt.toISOString(),
|
||||||
|
updatedAt: node.updatedAt.toISOString(),
|
||||||
|
learningobject_hruid: node.learningObjectHruid,
|
||||||
|
version: learningObject.version,
|
||||||
|
transitions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function converting pairs of learning path nodes (as represented in the database) and the corresponding
|
* Helper function converting pairs of learning path nodes (as represented in the database) and the corresponding
|
||||||
* learning objects into a list of learning path nodes as they should be represented in the API.
|
* learning objects into a list of learning path nodes as they should be represented in the API.
|
||||||
* @param nodesToLearningObjects
|
*
|
||||||
* @param personalizedFor
|
* @param nodesToLearningObjects Mapping from learning path nodes to the corresponding learning objects.
|
||||||
|
* @param personalizedFor Personalization target if a personalized learning path is desired.
|
||||||
*/
|
*/
|
||||||
async function convertNodes(
|
async function convertNodes(
|
||||||
nodesToLearningObjects: Map<LearningPathNode, FilteredLearningObject>,
|
nodesToLearningObjects: Map<LearningPathNode, FilteredLearningObject>,
|
||||||
personalizedFor?: PersonalizationTarget
|
personalizedFor?: PersonalizationTarget
|
||||||
): Promise<LearningObjectNode[]> {
|
): Promise<LearningObjectNode[]> {
|
||||||
const nodesPromise = Array.from(nodesToLearningObjects.entries()).map(async (entry) => {
|
const nodesPromise = Array.from(nodesToLearningObjects.entries()).map((entry) =>
|
||||||
const [node, learningObject] = entry;
|
convertNode(entry[0], entry[1], personalizedFor, nodesToLearningObjects)
|
||||||
const lastSubmission = personalizedFor ? await getLastSubmissionForCustomizationTarget(node, personalizedFor) : null;
|
);
|
||||||
return {
|
|
||||||
_id: learningObject.uuid,
|
|
||||||
language: learningObject.language,
|
|
||||||
start_node: node.startNode,
|
|
||||||
created_at: node.createdAt.toISOString(),
|
|
||||||
updatedAt: node.updatedAt.toISOString(),
|
|
||||||
learningobject_hruid: node.learningObjectHruid,
|
|
||||||
version: learningObject.version,
|
|
||||||
transitions: node.transitions
|
|
||||||
.filter(
|
|
||||||
(trans) => !personalizedFor || isTransitionPossible(trans, optionalJsonStringToObject(lastSubmission?.content)) // If we want a personalized learning path, remove all transitions that aren't possible.
|
|
||||||
)
|
|
||||||
.map((trans, i) => convertTransition(trans, i, nodesToLearningObjects)), // Then convert all the transition
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return await Promise.all(nodesPromise);
|
return await Promise.all(nodesPromise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,9 +137,10 @@ function optionalJsonStringToObject(jsonString?: string): object | null {
|
||||||
* Helper function which converts a transition in the database representation to a transition in the representation
|
* Helper function which converts a transition in the database representation to a transition in the representation
|
||||||
* the Dwengo API uses.
|
* the Dwengo API uses.
|
||||||
*
|
*
|
||||||
* @param transition
|
* @param transition The transition to convert
|
||||||
* @param index
|
* @param index The sequence number of the transition to convert
|
||||||
* @param nodesToLearningObjects
|
* @param nodesToLearningObjects Map which maps each learning path node of the current learning path to the learning
|
||||||
|
* object it refers to.
|
||||||
*/
|
*/
|
||||||
function convertTransition(
|
function convertTransition(
|
||||||
transition: LearningPathTransition,
|
transition: LearningPathTransition,
|
||||||
|
|
|
@ -60,7 +60,8 @@ describe('DatabaseLearningObjectProvider', () => {
|
||||||
describe('getLearningObjectHTML', () => {
|
describe('getLearningObjectHTML', () => {
|
||||||
it('should return the correct rendering of the learning object', async () => {
|
it('should return the correct rendering of the learning object', async () => {
|
||||||
const result = await databaseLearningObjectProvider.getLearningObjectHTML(exampleLearningObject);
|
const result = await databaseLearningObjectProvider.getLearningObjectHTML(exampleLearningObject);
|
||||||
expect(result).toEqual(example.getHTMLRendering());
|
// Set newlines so your tests are platform-independent.
|
||||||
|
expect(result).toEqual(example.getHTMLRendering().replace(/\r\n/g, '\n'));
|
||||||
});
|
});
|
||||||
it('should return null for a non-existing learning object', async () => {
|
it('should return null for a non-existing learning object', async () => {
|
||||||
const result = await databaseLearningObjectProvider.getLearningObjectHTML({
|
const result = await databaseLearningObjectProvider.getLearningObjectHTML({
|
||||||
|
|
|
@ -68,7 +68,8 @@ describe('LearningObjectService', () => {
|
||||||
it('returns the expected HTML when queried with the identifier of a learning object saved in the database', async () => {
|
it('returns the expected HTML when queried with the identifier of a learning object saved in the database', async () => {
|
||||||
const result = await learningObjectService.getLearningObjectHTML(exampleLearningObject);
|
const result = await learningObjectService.getLearningObjectHTML(exampleLearningObject);
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
expect(result).toEqual(learningObjectExample.getHTMLRendering());
|
// Set newlines so your tests are platform-independent.
|
||||||
|
expect(result).toEqual(learningObjectExample.getHTMLRendering().replace(/\r\n/g, '\n'));
|
||||||
});
|
});
|
||||||
it(
|
it(
|
||||||
'returns the same HTML as the Dwengo API when queried with the identifier of a learning object that does ' +
|
'returns the same HTML as the Dwengo API when queried with the identifier of a learning object that does ' +
|
||||||
|
|
|
@ -8,18 +8,19 @@ describe('ProcessingService', () => {
|
||||||
it('renders a markdown learning object correctly', async () => {
|
it('renders a markdown learning object correctly', async () => {
|
||||||
const markdownLearningObject = mdExample.createLearningObject();
|
const markdownLearningObject = mdExample.createLearningObject();
|
||||||
const result = await processingService.render(markdownLearningObject);
|
const result = await processingService.render(markdownLearningObject);
|
||||||
expect(result).toEqual(mdExample.getHTMLRendering());
|
// Set newlines so your tests are platform-independent.
|
||||||
|
expect(result).toEqual(mdExample.getHTMLRendering().replace(/\r\n/g, '\n'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders a multiple choice question correctly', async () => {
|
it('renders a multiple choice question correctly', async () => {
|
||||||
const multipleChoiceLearningObject = multipleChoiceExample.createLearningObject();
|
const multipleChoiceLearningObject = multipleChoiceExample.createLearningObject();
|
||||||
const result = await processingService.render(multipleChoiceLearningObject);
|
const result = await processingService.render(multipleChoiceLearningObject);
|
||||||
expect(result).toEqual(multipleChoiceExample.getHTMLRendering());
|
expect(result).toEqual(multipleChoiceExample.getHTMLRendering().replace(/\r\n/g, '\n'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders an essay question correctly', async () => {
|
it('renders an essay question correctly', async () => {
|
||||||
const essayLearningObject = essayExample.createLearningObject();
|
const essayLearningObject = essayExample.createLearningObject();
|
||||||
const result = await processingService.render(essayLearningObject);
|
const result = await processingService.render(essayLearningObject);
|
||||||
expect(result).toEqual(essayExample.getHTMLRendering());
|
expect(result).toEqual(essayExample.getHTMLRendering().replace(/\r\n/g, '\n'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,6 @@ import learningObjectExample from '../../test-assets/learning-objects/pn-werking
|
||||||
import learningPathExample from '../../test-assets/learning-paths/pn-werking-example.js';
|
import learningPathExample from '../../test-assets/learning-paths/pn-werking-example.js';
|
||||||
import databaseLearningPathProvider from '../../../src/services/learning-paths/database-learning-path-provider.js';
|
import databaseLearningPathProvider from '../../../src/services/learning-paths/database-learning-path-provider.js';
|
||||||
import { expectToBeCorrectLearningPath } from '../../test-utils/expectations.js';
|
import { expectToBeCorrectLearningPath } from '../../test-utils/expectations.js';
|
||||||
import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository.js';
|
|
||||||
import learningObjectService from '../../../src/services/learning-objects/learning-object-service.js';
|
import learningObjectService from '../../../src/services/learning-objects/learning-object-service.js';
|
||||||
import { Language } from '../../../src/entities/content/language.js';
|
import { Language } from '../../../src/entities/content/language.js';
|
||||||
import {
|
import {
|
||||||
|
@ -59,7 +58,6 @@ async function initPersonalizationTestData(): Promise<{
|
||||||
learningObjectHruid: learningContent.branchingObject.hruid,
|
learningObjectHruid: learningContent.branchingObject.hruid,
|
||||||
learningObjectLanguage: learningContent.branchingObject.language,
|
learningObjectLanguage: learningContent.branchingObject.language,
|
||||||
learningObjectVersion: learningContent.branchingObject.version,
|
learningObjectVersion: learningContent.branchingObject.version,
|
||||||
submissionNumber: 0,
|
|
||||||
submitter: studentA,
|
submitter: studentA,
|
||||||
submissionTime: new Date(),
|
submissionTime: new Date(),
|
||||||
content: '[0]',
|
content: '[0]',
|
||||||
|
@ -76,7 +74,6 @@ async function initPersonalizationTestData(): Promise<{
|
||||||
learningObjectHruid: learningContent.branchingObject.hruid,
|
learningObjectHruid: learningContent.branchingObject.hruid,
|
||||||
learningObjectLanguage: learningContent.branchingObject.language,
|
learningObjectLanguage: learningContent.branchingObject.language,
|
||||||
learningObjectVersion: learningContent.branchingObject.version,
|
learningObjectVersion: learningContent.branchingObject.version,
|
||||||
submissionNumber: 1,
|
|
||||||
submitter: studentB,
|
submitter: studentB,
|
||||||
submissionTime: new Date(),
|
submissionTime: new Date(),
|
||||||
content: '[1]',
|
content: '[1]',
|
||||||
|
@ -106,7 +103,6 @@ function expectBranchingObjectNode(
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('DatabaseLearningPathProvider', () => {
|
describe('DatabaseLearningPathProvider', () => {
|
||||||
let learningObjectRepo: LearningObjectRepository;
|
|
||||||
let example: { learningObject: LearningObject; learningPath: LearningPath };
|
let example: { learningObject: LearningObject; learningPath: LearningPath };
|
||||||
let persTestData: { learningContent: ConditionTestLearningPathAndLearningObjects; studentA: Student; studentB: Student };
|
let persTestData: { learningContent: ConditionTestLearningPathAndLearningObjects; studentA: Student; studentB: Student };
|
||||||
|
|
||||||
|
@ -114,7 +110,6 @@ describe('DatabaseLearningPathProvider', () => {
|
||||||
await setupTestApp();
|
await setupTestApp();
|
||||||
example = await initExampleData();
|
example = await initExampleData();
|
||||||
persTestData = await initPersonalizationTestData();
|
persTestData = await initPersonalizationTestData();
|
||||||
learningObjectRepo = getLearningObjectRepository();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fetchLearningPaths', () => {
|
describe('fetchLearningPaths', () => {
|
||||||
|
|
|
@ -1,48 +1,167 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
|
||||||
import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
const route = useRoute();
|
import auth from "@/services/auth/auth-service.ts";
|
||||||
|
|
||||||
|
// Import assets
|
||||||
|
import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg";
|
||||||
|
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
|
|
||||||
// Instantiate variables to use in html to render right
|
const role = auth.authState.activeRole;
|
||||||
// Links and content dependent on the role (student or teacher)
|
|
||||||
const isTeacher = route.path.includes("teacher");
|
|
||||||
|
|
||||||
const userId = route.params.id as string;
|
const name: string = auth.authState.user!.profile.name!;
|
||||||
|
const initials: string = name
|
||||||
const role = isTeacher ? "teacher" : "student";
|
|
||||||
const name = "Kurt Cobain";
|
|
||||||
const initials = name
|
|
||||||
.split(" ")
|
.split(" ")
|
||||||
.map((n) => {
|
.map((n) => n[0])
|
||||||
return n[0];
|
|
||||||
})
|
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
|
// Available languages
|
||||||
const languages = ref([
|
const languages = ref([
|
||||||
{ name: "English", code: "en" },
|
{ name: "English", code: "en" },
|
||||||
{ name: "Nederlands", code: "nl" },
|
{ name: "Nederlands", code: "nl" },
|
||||||
|
{ name: "Français", code: "fr" },
|
||||||
|
{ name: "Deutsch", code: "de" },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Logic to change the language of the website to the selected language
|
// Logic to change the language of the website to the selected language
|
||||||
const changeLanguage = (langCode: string) => {
|
const changeLanguage = (langCode: string) => {
|
||||||
locale.value = langCode;
|
locale.value = langCode;
|
||||||
localStorage.setItem("user-lang", langCode);
|
localStorage.setItem("user-lang", langCode);
|
||||||
console.log(langCode);
|
};
|
||||||
|
|
||||||
|
// contains functionality to let the collapsed menu appear and disappear
|
||||||
|
// when the screen size varies
|
||||||
|
const drawer = ref(false);
|
||||||
|
|
||||||
|
// when the user wants to logout, a popup is shown to verify this
|
||||||
|
// if verified, the user should be logged out
|
||||||
|
const performLogout = () => {
|
||||||
|
auth.logout();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main>
|
<main>
|
||||||
|
<v-app class="menu_collapsed">
|
||||||
|
<v-app-bar
|
||||||
|
app
|
||||||
|
style="background-color: #f6faf2"
|
||||||
|
>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-app-bar-nav-icon @click="drawer = !drawer" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<v-app-bar-title>
|
||||||
|
<router-link
|
||||||
|
to="/user"
|
||||||
|
class="dwengo_home"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
class="dwengo_logo"
|
||||||
|
:src="dwengoLogo"
|
||||||
|
style="width: 100px"
|
||||||
|
/>
|
||||||
|
<p
|
||||||
|
class="caption"
|
||||||
|
style="font-size: smaller"
|
||||||
|
>
|
||||||
|
{{ t(`${role}`) }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</router-link>
|
||||||
|
</v-app-bar-title>
|
||||||
|
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
|
||||||
|
<v-menu open-on-hover>
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-btn
|
||||||
|
v-bind="props"
|
||||||
|
icon
|
||||||
|
variant="text"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
icon="mdi-translate"
|
||||||
|
size="small"
|
||||||
|
color="#0e6942"
|
||||||
|
></v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<v-list>
|
||||||
|
<v-list-item
|
||||||
|
v-for="(language, index) in languages"
|
||||||
|
:key="index"
|
||||||
|
@click="changeLanguage(language.code)"
|
||||||
|
>
|
||||||
|
<v-list-item-title>{{ language.name }}</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
|
||||||
|
<v-btn
|
||||||
|
@click="performLogout"
|
||||||
|
text
|
||||||
|
>
|
||||||
|
<v-tooltip
|
||||||
|
:text="t('logout')"
|
||||||
|
location="bottom"
|
||||||
|
>
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-icon
|
||||||
|
v-bind="props"
|
||||||
|
icon="mdi-logout"
|
||||||
|
size="x-large"
|
||||||
|
color="#0e6942"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</v-tooltip>
|
||||||
|
</v-btn>
|
||||||
|
</v-app-bar>
|
||||||
|
|
||||||
|
<v-navigation-drawer
|
||||||
|
v-model="drawer"
|
||||||
|
app
|
||||||
|
>
|
||||||
|
<v-list>
|
||||||
|
<v-list-item
|
||||||
|
to="/user/assignment"
|
||||||
|
link
|
||||||
|
>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title class="menu_item">{{ t("assignments") }}</v-list-item-title>
|
||||||
|
</v-list-item-content>
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item
|
||||||
|
to="/user/class"
|
||||||
|
link
|
||||||
|
>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title class="menu_item">{{ t("classes") }}</v-list-item-title>
|
||||||
|
</v-list-item-content>
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item
|
||||||
|
to="/user/discussion"
|
||||||
|
link
|
||||||
|
>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title class="menu_item">{{ t("discussions") }}</v-list-item-title>
|
||||||
|
</v-list-item-content>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-navigation-drawer>
|
||||||
|
</v-app>
|
||||||
|
|
||||||
<nav class="menu">
|
<nav class="menu">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<router-link
|
<router-link
|
||||||
:to="`/${role}/${userId}`"
|
to="/user"
|
||||||
class="dwengo_home"
|
class="dwengo_home"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
|
@ -56,7 +175,7 @@
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<router-link
|
<router-link
|
||||||
:to="`/${role}/${userId}/assignment`"
|
:to="`/user/assignment`"
|
||||||
class="menu_item"
|
class="menu_item"
|
||||||
>
|
>
|
||||||
{{ t("assignments") }}
|
{{ t("assignments") }}
|
||||||
|
@ -64,14 +183,14 @@
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<router-link
|
<router-link
|
||||||
:to="`/${role}/${userId}/class`"
|
to="/user/class"
|
||||||
class="menu_item"
|
class="menu_item"
|
||||||
>{{ t("classes") }}</router-link
|
>{{ t("classes") }}</router-link
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<router-link
|
<router-link
|
||||||
:to="`/${role}/${userId}/discussion`"
|
to="/user/discussion"
|
||||||
class="menu_item"
|
class="menu_item"
|
||||||
>{{ t("discussions") }}
|
>{{ t("discussions") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
@ -106,7 +225,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<li>
|
<li>
|
||||||
<router-link :to="`/login`">
|
<!-- <v-btn
|
||||||
|
@click="performLogout"
|
||||||
|
to="/login"
|
||||||
|
style="background-color: transparent; box-shadow: none !important"
|
||||||
|
>
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
:text="t('logout')"
|
:text="t('logout')"
|
||||||
location="bottom"
|
location="bottom"
|
||||||
|
@ -120,7 +243,48 @@
|
||||||
></v-icon>
|
></v-icon>
|
||||||
</template>
|
</template>
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
</router-link>
|
</v-btn> -->
|
||||||
|
<v-dialog max-width="500">
|
||||||
|
<template v-slot:activator="{ props: activatorProps }">
|
||||||
|
<v-btn
|
||||||
|
v-bind="activatorProps"
|
||||||
|
style="background-color: transparent; box-shadow: none !important"
|
||||||
|
>
|
||||||
|
<v-tooltip
|
||||||
|
:text="t('logout')"
|
||||||
|
location="bottom"
|
||||||
|
>
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-icon
|
||||||
|
v-bind="props"
|
||||||
|
icon="mdi-logout"
|
||||||
|
size="x-large"
|
||||||
|
color="#0e6942"
|
||||||
|
>
|
||||||
|
</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-tooltip>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:default="{ isActive }">
|
||||||
|
<v-card :title="t('logoutVerification')">
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
|
||||||
|
<v-btn
|
||||||
|
:text="t('cancel')"
|
||||||
|
@click="isActive.value = false"
|
||||||
|
></v-btn>
|
||||||
|
<v-btn
|
||||||
|
:text="t('logout')"
|
||||||
|
@click="performLogout"
|
||||||
|
to="/login"
|
||||||
|
></v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
</v-dialog>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<v-avatar
|
<v-avatar
|
||||||
|
@ -187,4 +351,16 @@
|
||||||
nav a.router-link-active {
|
nav a.router-link-active {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 700px) {
|
||||||
|
.menu {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 701px) {
|
||||||
|
.menu_collapsed {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
"welcome": "Willkommen",
|
"welcome": "Willkommen",
|
||||||
"student": "schüler",
|
"student": "schüler",
|
||||||
"teacher": "lehrer",
|
"teacher": "lehrer",
|
||||||
"assignments": "aufgaben",
|
"assignments": "Aufgaben",
|
||||||
"classes": "klasses",
|
"classes": "Klasses",
|
||||||
"discussions": "diskussionen",
|
"discussions": "Diskussionen",
|
||||||
"login": "einloggen",
|
"login": "einloggen",
|
||||||
"logout": "ausloggen",
|
"logout": "ausloggen",
|
||||||
|
"cancel": "kündigen",
|
||||||
|
"logoutVerification": "Sind Sie sicher, dass Sie sich abmelden wollen?",
|
||||||
"homeTitle": "Unsere Stärken",
|
"homeTitle": "Unsere Stärken",
|
||||||
"homeIntroduction1": "Wir entwickeln innovative Workshops und Bildungsressourcen, die wir in Zusammenarbeit mit Lehrern und Freiwilligen Schülern auf der ganzen Welt zur Verfügung stellen. Unsere Train-the-Trainer-Sitzungen ermöglichen es ihnen, unsere praktischen Workshops an die Schüler weiterzugeben.",
|
"homeIntroduction1": "Wir entwickeln innovative Workshops und Bildungsressourcen, die wir in Zusammenarbeit mit Lehrern und Freiwilligen Schülern auf der ganzen Welt zur Verfügung stellen. Unsere Train-the-Trainer-Sitzungen ermöglichen es ihnen, unsere praktischen Workshops an die Schüler weiterzugeben.",
|
||||||
"homeIntroduction2": "Wir fügen allen unseren Projekten ständig neue Projekte und Methoden hinzu. Für diese Projekte suchen wir immer nach einem gesellschaftlich relevanten Thema. Darüber hinaus stellen wir sicher, dass unser didaktisches Material auf wissenschaftlicher Forschung basiert, und achten stets auf die Inklusion.",
|
"homeIntroduction2": "Wir fügen allen unseren Projekten ständig neue Projekte und Methoden hinzu. Für diese Projekte suchen wir immer nach einem gesellschaftlich relevanten Thema. Darüber hinaus stellen wir sicher, dass unser didaktisches Material auf wissenschaftlicher Forschung basiert, und achten stets auf die Inklusion.",
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
"welcome": "Welcome",
|
"welcome": "Welcome",
|
||||||
"student": "student",
|
"student": "student",
|
||||||
"teacher": "teacher",
|
"teacher": "teacher",
|
||||||
"assignments": "assignments",
|
"assignments": "Assignments",
|
||||||
"classes": "classes",
|
"classes": "Classes",
|
||||||
"discussions": "discussions",
|
"discussions": "Discussions",
|
||||||
"logout": "log out",
|
"logout": "log out",
|
||||||
|
"cancel": "cancel",
|
||||||
|
"logoutVerification": "Are you sure you want to log out?",
|
||||||
"homeTitle": "Our strengths",
|
"homeTitle": "Our strengths",
|
||||||
"homeIntroduction1": "We develop innovative workshops and educational resources, and we provide them to students around the globe in collaboration with teachers and volunteers. Our train-the-trainer sessions enable them to bring our hands-on workshops to the students.",
|
"homeIntroduction1": "We develop innovative workshops and educational resources, and we provide them to students around the globe in collaboration with teachers and volunteers. Our train-the-trainer sessions enable them to bring our hands-on workshops to the students.",
|
||||||
"homeIntroduction2": "We continuously add new projects and methodologies to all our projects. For these projects, we always look for a socially relevant theme. Additionally, we ensure that our didactic material is based on scientific research and always keep an eye on inclusivity.",
|
"homeIntroduction2": "We continuously add new projects and methodologies to all our projects. For these projects, we always look for a socially relevant theme. Additionally, we ensure that our didactic material is based on scientific research and always keep an eye on inclusivity.",
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
"welcome": "Bienvenue",
|
"welcome": "Bienvenue",
|
||||||
"student": "élève",
|
"student": "élève",
|
||||||
"teacher": "enseignant",
|
"teacher": "enseignant",
|
||||||
"assignments": "travails",
|
"assignments": "Travails",
|
||||||
"classes": "classes",
|
"classes": "Classes",
|
||||||
"discussions": "discussions",
|
"discussions": "Discussions",
|
||||||
"login": "se connecter",
|
"login": "se connecter",
|
||||||
"logout": "se déconnecter",
|
"logout": "se déconnecter",
|
||||||
|
"cancel": "annuler",
|
||||||
|
"logoutVerification": "Êtes-vous sûr de vouloir vous déconnecter ?",
|
||||||
"homeTitle": "Nos atouts",
|
"homeTitle": "Nos atouts",
|
||||||
"homeIntroduction1": "Nous développons des ateliers innovants et des ressources éducatives que nous mettons à la disposition des élèves du monde entier en collaboration avec des enseignants et des bénévoles. Nos sessions de formation des formateurs leur permettent d'offrir nos ateliers pratiques aux élèves.",
|
"homeIntroduction1": "Nous développons des ateliers innovants et des ressources éducatives que nous mettons à la disposition des élèves du monde entier en collaboration avec des enseignants et des bénévoles. Nos sessions de formation des formateurs leur permettent d'offrir nos ateliers pratiques aux élèves.",
|
||||||
"homeIntroduction2": "Nous ajoutons continuellement de nouveaux projets et de nouvelles méthodologies à tous nos projets. Pour ces projets, nous recherchons toujours un thème socialement pertinent. En outre, nous veillons à ce que notre matériel didactique soit basé sur la recherche scientifique et nous gardons toujours un œil sur l'inclusivité.",
|
"homeIntroduction2": "Nous ajoutons continuellement de nouveaux projets et de nouvelles méthodologies à tous nos projets. Pour ces projets, nous recherchons toujours un thème socialement pertinent. En outre, nous veillons à ce que notre matériel didactique soit basé sur la recherche scientifique et nous gardons toujours un œil sur l'inclusivité.",
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
"welcome": "Welkom",
|
"welcome": "Welkom",
|
||||||
"student": "leerling",
|
"student": "leerling",
|
||||||
"teacher": "leerkracht",
|
"teacher": "leerkracht",
|
||||||
"assignments": "opdrachten",
|
"assignments": "Opdrachten",
|
||||||
"classes": "klassen",
|
"classes": "Klassen",
|
||||||
"discussions": "discussies",
|
"discussions": "Discussies",
|
||||||
"logout": "log uit",
|
"logout": "log uit",
|
||||||
|
"cancel": "annuleren",
|
||||||
|
"logoutVerification": "Bent u zeker dat u wilt uitloggen?",
|
||||||
"homeTitle": "Onze sterke punten",
|
"homeTitle": "Onze sterke punten",
|
||||||
"homeIntroduction1": "We ontwikkelen innovatieve workshops en leermiddelen en bieden deze aan studenten over de hele wereld in samenwerking met leerkrachten en vrijwilligers. Onze train-de-trainer sessies stellen hen in staat om onze hands-on workshops naar de leerlingen te brengen.",
|
"homeIntroduction1": "We ontwikkelen innovatieve workshops en leermiddelen en bieden deze aan studenten over de hele wereld in samenwerking met leerkrachten en vrijwilligers. Onze train-de-trainer sessies stellen hen in staat om onze hands-on workshops naar de leerlingen te brengen.",
|
||||||
"homeIntroduction2": "We voegen voortdurend nieuwe projecten en methodologieën toe aan al onze projecten. Voor deze projecten zoeken we altijd een maatschappelijk relevant thema. Daarnaast zorgen we ervoor dat ons didactisch materiaal gebaseerd is op wetenschappelijk onderzoek en houden we inclusiviteit altijd in het oog.",
|
"homeIntroduction2": "We voegen voortdurend nieuwe projecten en methodologieën toe aan al onze projecten. Voor deze projecten zoeken we altijd een maatschappelijk relevant thema. Daarnaast zorgen we ervoor dat ons didactisch materiaal gebaseerd is op wetenschappelijk onderzoek en houden we inclusiviteit altijd in het oog.",
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
import { createRouter, createWebHistory } from "vue-router";
|
import { createRouter, createWebHistory } from "vue-router";
|
||||||
import MenuBar from "@/components/MenuBar.vue";
|
import MenuBar from "@/components/MenuBar.vue";
|
||||||
import StudentHomepage from "@/views/StudentHomepage.vue";
|
import StudentHomepage from "@/views/homepage/StudentHomepage.vue";
|
||||||
import StudentAssignments from "@/views/assignments/StudentAssignments.vue";
|
|
||||||
import StudentClasses from "@/views/classes/StudentClasses.vue";
|
|
||||||
import StudentDiscussions from "@/views/discussions/StudentDiscussions.vue";
|
|
||||||
import TeacherHomepage from "@/views/TeacherHomepage.vue";
|
|
||||||
import TeacherAssignments from "@/views/assignments/TeacherAssignments.vue";
|
|
||||||
import TeacherClasses from "@/views/classes/TeacherClasses.vue";
|
|
||||||
import TeacherDiscussions from "@/views/discussions/TeacherDiscussions.vue";
|
|
||||||
import SingleAssignment from "@/views/assignments/SingleAssignment.vue";
|
import SingleAssignment from "@/views/assignments/SingleAssignment.vue";
|
||||||
import SingleClass from "@/views/classes/SingleClass.vue";
|
import SingleClass from "@/views/classes/SingleClass.vue";
|
||||||
import SingleDiscussion from "@/views/discussions/SingleDiscussion.vue";
|
import SingleDiscussion from "@/views/discussions/SingleDiscussion.vue";
|
||||||
|
@ -16,6 +9,10 @@ import CreateClass from "@/views/classes/CreateClass.vue";
|
||||||
import CreateAssignment from "@/views/assignments/CreateAssignment.vue";
|
import CreateAssignment from "@/views/assignments/CreateAssignment.vue";
|
||||||
import CreateDiscussion from "@/views/discussions/CreateDiscussion.vue";
|
import CreateDiscussion from "@/views/discussions/CreateDiscussion.vue";
|
||||||
import CallbackPage from "@/views/CallbackPage.vue";
|
import CallbackPage from "@/views/CallbackPage.vue";
|
||||||
|
import UserDiscussions from "@/views/discussions/UserDiscussions.vue";
|
||||||
|
import UserClasses from "@/views/classes/UserClasses.vue";
|
||||||
|
import UserAssignments from "@/views/classes/UserAssignments.vue";
|
||||||
|
import authState from "@/services/auth/auth-service.ts";
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
@ -24,105 +21,104 @@ const router = createRouter({
|
||||||
path: "/",
|
path: "/",
|
||||||
name: "home",
|
name: "home",
|
||||||
component: () => import("../views/HomePage.vue"),
|
component: () => import("../views/HomePage.vue"),
|
||||||
|
meta: { requiresAuth: false },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/login",
|
path: "/login",
|
||||||
name: "LoginPage",
|
name: "LoginPage",
|
||||||
component: () => import("../views/LoginPage.vue"),
|
component: () => import("../views/LoginPage.vue"),
|
||||||
|
meta: { requiresAuth: false },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/callback",
|
path: "/callback",
|
||||||
component: CallbackPage,
|
component: CallbackPage,
|
||||||
|
meta: { requiresAuth: false },
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: "/student/:id",
|
path: "/user",
|
||||||
component: MenuBar,
|
component: MenuBar,
|
||||||
|
meta: { requiresAuth: true },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "home",
|
path: "home",
|
||||||
name: "StudentHomePage",
|
name: "UserHomePage",
|
||||||
component: StudentHomepage,
|
component: StudentHomepage,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "assignment",
|
path: "assignment",
|
||||||
name: "StudentAssignments",
|
name: "UserAssignments",
|
||||||
component: StudentAssignments,
|
component: UserAssignments,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "class",
|
path: "class",
|
||||||
name: "StudentClasses",
|
name: "UserClasses",
|
||||||
component: StudentClasses,
|
component: UserClasses,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "discussion",
|
path: "discussion",
|
||||||
name: "StudentDiscussions",
|
name: "UserDiscussions",
|
||||||
component: StudentDiscussions,
|
component: UserDiscussions,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
path: "/teacher/:id",
|
|
||||||
component: MenuBar,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "home",
|
|
||||||
name: "TeacherHomepage",
|
|
||||||
component: TeacherHomepage,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "assignment",
|
|
||||||
name: "TeacherAssignments",
|
|
||||||
component: TeacherAssignments,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "class",
|
|
||||||
name: "TeacherClasses",
|
|
||||||
component: TeacherClasses,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "discussion",
|
|
||||||
name: "TeacherDiscussions",
|
|
||||||
component: TeacherDiscussions,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/assignment/create",
|
path: "/assignment/create",
|
||||||
name: "CreateAssigment",
|
name: "CreateAssigment",
|
||||||
component: CreateAssignment,
|
component: CreateAssignment,
|
||||||
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/assignment/:id",
|
path: "/assignment/:id",
|
||||||
name: "SingleAssigment",
|
name: "SingleAssigment",
|
||||||
component: SingleAssignment,
|
component: SingleAssignment,
|
||||||
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/class/create",
|
path: "/class/create",
|
||||||
name: "CreateClass",
|
name: "CreateClass",
|
||||||
component: CreateClass,
|
component: CreateClass,
|
||||||
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/class/:id",
|
path: "/class/:id",
|
||||||
name: "SingleClass",
|
name: "SingleClass",
|
||||||
component: SingleClass,
|
component: SingleClass,
|
||||||
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/discussion/create",
|
path: "/discussion/create",
|
||||||
name: "CreateDiscussion",
|
name: "CreateDiscussion",
|
||||||
component: CreateDiscussion,
|
component: CreateDiscussion,
|
||||||
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/discussion/:id",
|
path: "/discussion/:id",
|
||||||
name: "SingleDiscussion",
|
name: "SingleDiscussion",
|
||||||
component: SingleDiscussion,
|
component: SingleDiscussion,
|
||||||
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/:catchAll(.*)",
|
path: "/:catchAll(.*)",
|
||||||
name: "NotFound",
|
name: "NotFound",
|
||||||
component: NotFound,
|
component: NotFound,
|
||||||
|
meta: { requiresAuth: false },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
// Verify if user is logged in before accessing certain routes
|
||||||
|
if (to.meta.requiresAuth) {
|
||||||
|
if (!authState.isLoggedIn.value) {
|
||||||
|
next("/login");
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
@ -20,6 +20,15 @@ async function getUserManagers(): Promise<UserManagersForRoles> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the current authentication state.
|
||||||
|
*/
|
||||||
|
const authState = reactive<AuthState>({
|
||||||
|
user: null,
|
||||||
|
accessToken: null,
|
||||||
|
activeRole: authStorage.getActiveRole() || null,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the information about who is currently logged in from the IDP.
|
* Load the information about who is currently logged in from the IDP.
|
||||||
*/
|
*/
|
||||||
|
@ -35,15 +44,6 @@ async function loadUser(): Promise<User | null> {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Information about the current authentication state.
|
|
||||||
*/
|
|
||||||
const authState = reactive<AuthState>({
|
|
||||||
user: null,
|
|
||||||
accessToken: null,
|
|
||||||
activeRole: authStorage.getActiveRole() || null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const isLoggedIn = computed(() => authState.user !== null);
|
const isLoggedIn = computed(() => authState.user !== null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
You are currently logged in as {{ auth.authState.user!.profile.name }} ({{ auth.authState.activeRole }})
|
You are currently logged in as {{ auth.authState.user!.profile.name }} ({{ auth.authState.activeRole }})
|
||||||
</p>
|
</p>
|
||||||
<v-btn @click="performLogout">Logout</v-btn>
|
<v-btn @click="performLogout">Logout</v-btn>
|
||||||
|
<v-btn to="/user">home</v-btn>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
7
frontend/src/views/discussions/UserDiscussions.vue
Normal file
7
frontend/src/views/discussions/UserDiscussions.vue
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main></main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
7
frontend/src/views/homepage/StudentHomepage.vue
Normal file
7
frontend/src/views/homepage/StudentHomepage.vue
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main></main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
7
frontend/src/views/homepage/TeacherHomepage.vue
Normal file
7
frontend/src/views/homepage/TeacherHomepage.vue
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main></main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
7
frontend/src/views/homepage/UserHomePage.vue
Normal file
7
frontend/src/views/homepage/UserHomePage.vue
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<main></main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
272
package-lock.json
generated
272
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "dwengo-1-monorepo",
|
"name": "dwengo-1-monorepo",
|
||||||
"version": "0.0.1",
|
"version": "0.1.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "dwengo-1-monorepo",
|
"name": "dwengo-1-monorepo",
|
||||||
"version": "0.0.1",
|
"version": "0.1.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"backend",
|
"backend",
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
"@types/eslint-config-prettier": "^6.11.3",
|
"@types/eslint-config-prettier": "^6.11.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.24.1",
|
"@typescript-eslint/eslint-plugin": "^8.24.1",
|
||||||
"@typescript-eslint/parser": "^8.24.1",
|
"@typescript-eslint/parser": "^8.24.1",
|
||||||
|
"@vitest/coverage-v8": "^3.0.8",
|
||||||
"eslint": "^9.20.1",
|
"eslint": "^9.20.1",
|
||||||
"eslint-config-prettier": "^10.0.1",
|
"eslint-config-prettier": "^10.0.1",
|
||||||
"jiti": "^2.4.2",
|
"jiti": "^2.4.2",
|
||||||
|
@ -27,7 +28,7 @@
|
||||||
},
|
},
|
||||||
"backend": {
|
"backend": {
|
||||||
"name": "dwengo-1-backend",
|
"name": "dwengo-1-backend",
|
||||||
"version": "0.0.1",
|
"version": "0.1.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mikro-orm/core": "6.4.9",
|
"@mikro-orm/core": "6.4.9",
|
||||||
"@mikro-orm/knex": "6.4.9",
|
"@mikro-orm/knex": "6.4.9",
|
||||||
|
@ -89,7 +90,7 @@
|
||||||
},
|
},
|
||||||
"frontend": {
|
"frontend": {
|
||||||
"name": "dwengo-1-frontend",
|
"name": "dwengo-1-frontend",
|
||||||
"version": "0.0.1",
|
"version": "0.1.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.8.2",
|
"axios": "^1.8.2",
|
||||||
"oidc-client-ts": "^3.1.0",
|
"oidc-client-ts": "^3.1.0",
|
||||||
|
@ -597,6 +598,16 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@bcoe/v8-coverage": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@colors/colors": {
|
"node_modules/@colors/colors": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
|
||||||
|
@ -1018,6 +1029,16 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@istanbuljs/schema": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
|
||||||
|
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jercle/yargonaut": {
|
"node_modules/@jercle/yargonaut": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
@ -1612,7 +1633,8 @@
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
],
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.34.8",
|
"version": "4.34.8",
|
||||||
|
@ -1624,7 +1646,8 @@
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
],
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@scarf/scarf": {
|
"node_modules/@scarf/scarf": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
|
@ -2046,6 +2069,39 @@
|
||||||
"vue": "^3.2.25"
|
"vue": "^3.2.25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vitest/coverage-v8": {
|
||||||
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-y7SAKsQirsEJ2F8bulBck4DoluhI2EEgTimHd6EEUgJBGKy9tC25cpywh1MH4FvDGoG2Unt7+asVd1kj4qOSAw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@ampproject/remapping": "^2.3.0",
|
||||||
|
"@bcoe/v8-coverage": "^1.0.2",
|
||||||
|
"debug": "^4.4.0",
|
||||||
|
"istanbul-lib-coverage": "^3.2.2",
|
||||||
|
"istanbul-lib-report": "^3.0.1",
|
||||||
|
"istanbul-lib-source-maps": "^5.0.6",
|
||||||
|
"istanbul-reports": "^3.1.7",
|
||||||
|
"magic-string": "^0.30.17",
|
||||||
|
"magicast": "^0.3.5",
|
||||||
|
"std-env": "^3.8.0",
|
||||||
|
"test-exclude": "^7.0.1",
|
||||||
|
"tinyrainbow": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vitest/browser": "3.0.8",
|
||||||
|
"vitest": "3.0.8"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vitest/browser": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vitest/eslint-plugin": {
|
"node_modules/@vitest/eslint-plugin": {
|
||||||
"version": "1.1.31",
|
"version": "1.1.31",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
@ -2066,12 +2122,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/expect": {
|
"node_modules/@vitest/expect": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-Xu6TTIavTvSSS6LZaA3EebWFr6tsoXPetOWNMOlc7LO88QVVBwq2oQWBoDiLCN6YTvNYsGSjqOO8CAdjom5DCQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/spy": "3.0.6",
|
"@vitest/spy": "3.0.8",
|
||||||
"@vitest/utils": "3.0.6",
|
"@vitest/utils": "3.0.8",
|
||||||
"chai": "^5.2.0",
|
"chai": "^5.2.0",
|
||||||
"tinyrainbow": "^2.0.0"
|
"tinyrainbow": "^2.0.0"
|
||||||
},
|
},
|
||||||
|
@ -2080,11 +2138,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/mocker": {
|
"node_modules/@vitest/mocker": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-n3LjS7fcW1BCoF+zWZxG7/5XvuYH+lsFg+BDwwAz0arIwHQJFUEsKBQ0BLU49fCxuM/2HSeBPHQD8WjgrxMfow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/spy": "3.0.6",
|
"@vitest/spy": "3.0.8",
|
||||||
"estree-walker": "^3.0.3",
|
"estree-walker": "^3.0.3",
|
||||||
"magic-string": "^0.30.17"
|
"magic-string": "^0.30.17"
|
||||||
},
|
},
|
||||||
|
@ -2106,6 +2166,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/mocker/node_modules/estree-walker": {
|
"node_modules/@vitest/mocker/node_modules/estree-walker": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -2113,7 +2175,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/pretty-format": {
|
"node_modules/@vitest/pretty-format": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-BNqwbEyitFhzYMYHUVbIvepOyeQOSFA/NeJMIP9enMntkkxLgOcgABH6fjyXG85ipTgvero6noreavGIqfJcIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -2124,11 +2188,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/runner": {
|
"node_modules/@vitest/runner": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-c7UUw6gEcOzI8fih+uaAXS5DwjlBaCJUo7KJ4VvJcjL95+DSR1kova2hFuRt3w41KZEFcOEiq098KkyrjXeM5w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/utils": "3.0.6",
|
"@vitest/utils": "3.0.8",
|
||||||
"pathe": "^2.0.3"
|
"pathe": "^2.0.3"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
|
@ -2136,11 +2202,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/snapshot": {
|
"node_modules/@vitest/snapshot": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-x8IlMGSEMugakInj44nUrLSILh/zy1f2/BgH0UeHpNyOocG18M9CWVIFBaXPt8TrqVZWmcPjwfG/ht5tnpba8A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/pretty-format": "3.0.6",
|
"@vitest/pretty-format": "3.0.8",
|
||||||
"magic-string": "^0.30.17",
|
"magic-string": "^0.30.17",
|
||||||
"pathe": "^2.0.3"
|
"pathe": "^2.0.3"
|
||||||
},
|
},
|
||||||
|
@ -2149,7 +2217,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/spy": {
|
"node_modules/@vitest/spy": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-MR+PzJa+22vFKYb934CejhR4BeRpMSoxkvNoDit68GQxRLSf11aT6CTj3XaqUU9rxgWJFnqicN/wxw6yBRkI1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -2160,11 +2230,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitest/utils": {
|
"node_modules/@vitest/utils": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-nkBC3aEhfX2PdtQI/QwAWp8qZWwzASsU4Npbcd5RdMPBSSLCpkZp52P3xku3s3uA0HIEhGvEcF8rNkBsz9dQ4Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/pretty-format": "3.0.6",
|
"@vitest/pretty-format": "3.0.8",
|
||||||
"loupe": "^3.1.3",
|
"loupe": "^3.1.3",
|
||||||
"tinyrainbow": "^2.0.0"
|
"tinyrainbow": "^2.0.0"
|
||||||
},
|
},
|
||||||
|
@ -2635,6 +2707,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/assertion-error": {
|
"node_modules/assertion-error": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2860,6 +2934,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/cac": {
|
"node_modules/cac": {
|
||||||
"version": "6.7.14",
|
"version": "6.7.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
|
||||||
|
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -3014,6 +3090,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/chai": {
|
"node_modules/chai": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -3044,6 +3122,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/check-error": {
|
"node_modules/check-error": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -3419,6 +3499,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/deep-eql": {
|
"node_modules/deep-eql": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -3722,6 +3804,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/es-module-lexer": {
|
"node_modules/es-module-lexer": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
@ -4854,6 +4938,13 @@
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html-escaper": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/html-tags": {
|
"node_modules/html-tags": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
@ -5205,6 +5296,71 @@
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/istanbul-lib-coverage": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-lib-report": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"istanbul-lib-coverage": "^3.0.0",
|
||||||
|
"make-dir": "^4.0.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-lib-source-maps": {
|
||||||
|
"version": "5.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz",
|
||||||
|
"integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.23",
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"istanbul-lib-coverage": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-lib-source-maps/node_modules/@jridgewell/trace-mapping": {
|
||||||
|
"version": "0.3.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||||
|
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-reports": {
|
||||||
|
"version": "3.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
|
||||||
|
"integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"html-escaper": "^2.0.0",
|
||||||
|
"istanbul-lib-report": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jackspeak": {
|
"node_modules/jackspeak": {
|
||||||
"version": "3.4.3",
|
"version": "3.4.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
@ -5700,6 +5856,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/loupe": {
|
"node_modules/loupe": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
@ -5739,6 +5897,34 @@
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0"
|
"@jridgewell/sourcemap-codec": "^1.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/magicast": {
|
||||||
|
"version": "0.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz",
|
||||||
|
"integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/parser": "^7.25.4",
|
||||||
|
"@babel/types": "^7.25.4",
|
||||||
|
"source-map-js": "^1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/make-dir": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^7.5.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/make-error": {
|
"node_modules/make-error": {
|
||||||
"version": "1.3.6",
|
"version": "1.3.6",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
@ -6697,6 +6883,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/pathval": {
|
"node_modules/pathval": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -8263,6 +8451,21 @@
|
||||||
"node": ">=8.0.0"
|
"node": ">=8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/test-exclude": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@istanbuljs/schema": "^0.1.2",
|
||||||
|
"glob": "^10.4.1",
|
||||||
|
"minimatch": "^9.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/text-hex": {
|
"node_modules/text-hex": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||||
|
@ -8303,6 +8506,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/tinyspy": {
|
"node_modules/tinyspy": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -8753,7 +8958,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite-node": {
|
"node_modules/vite-node": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-6PhR4H9VGlcwXZ+KWCdMqbtG649xCPZqfI9j2PsK1FcXgEzro5bGHcVKFCTqPLaNKZES8Evqv4LwvZARsq5qlg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -8853,6 +9060,7 @@
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
|
@ -8897,17 +9105,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vitest": {
|
"node_modules/vitest": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-dfqAsNqRGUc8hB9OVR2P0w8PZPEckti2+5rdZip0WIz9WW0MnImJ8XiR61QhqLa92EQzKP2uPkzenKOAHyEIbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/expect": "3.0.6",
|
"@vitest/expect": "3.0.8",
|
||||||
"@vitest/mocker": "3.0.6",
|
"@vitest/mocker": "3.0.8",
|
||||||
"@vitest/pretty-format": "^3.0.6",
|
"@vitest/pretty-format": "^3.0.8",
|
||||||
"@vitest/runner": "3.0.6",
|
"@vitest/runner": "3.0.8",
|
||||||
"@vitest/snapshot": "3.0.6",
|
"@vitest/snapshot": "3.0.8",
|
||||||
"@vitest/spy": "3.0.6",
|
"@vitest/spy": "3.0.8",
|
||||||
"@vitest/utils": "3.0.6",
|
"@vitest/utils": "3.0.8",
|
||||||
"chai": "^5.2.0",
|
"chai": "^5.2.0",
|
||||||
"debug": "^4.4.0",
|
"debug": "^4.4.0",
|
||||||
"expect-type": "^1.1.0",
|
"expect-type": "^1.1.0",
|
||||||
|
@ -8919,7 +9129,7 @@
|
||||||
"tinypool": "^1.0.2",
|
"tinypool": "^1.0.2",
|
||||||
"tinyrainbow": "^2.0.0",
|
"tinyrainbow": "^2.0.0",
|
||||||
"vite": "^5.0.0 || ^6.0.0",
|
"vite": "^5.0.0 || ^6.0.0",
|
||||||
"vite-node": "3.0.6",
|
"vite-node": "3.0.8",
|
||||||
"why-is-node-running": "^2.3.0"
|
"why-is-node-running": "^2.3.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -8935,8 +9145,8 @@
|
||||||
"@edge-runtime/vm": "*",
|
"@edge-runtime/vm": "*",
|
||||||
"@types/debug": "^4.1.12",
|
"@types/debug": "^4.1.12",
|
||||||
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
||||||
"@vitest/browser": "3.0.6",
|
"@vitest/browser": "3.0.8",
|
||||||
"@vitest/ui": "3.0.6",
|
"@vitest/ui": "3.0.8",
|
||||||
"happy-dom": "*",
|
"happy-dom": "*",
|
||||||
"jsdom": "*"
|
"jsdom": "*"
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
"@types/eslint-config-prettier": "^6.11.3",
|
"@types/eslint-config-prettier": "^6.11.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.24.1",
|
"@typescript-eslint/eslint-plugin": "^8.24.1",
|
||||||
"@typescript-eslint/parser": "^8.24.1",
|
"@typescript-eslint/parser": "^8.24.1",
|
||||||
|
"@vitest/coverage-v8": "^3.0.8",
|
||||||
"eslint": "^9.20.1",
|
"eslint": "^9.20.1",
|
||||||
"eslint-config-prettier": "^10.0.1",
|
"eslint-config-prettier": "^10.0.1",
|
||||||
"jiti": "^2.4.2",
|
"jiti": "^2.4.2",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue