feat(frontend): Heel ruwe eerste versie van leerpadbeheerpagina toegevoegd

This commit is contained in:
Gerald Schmittinger 2025-05-13 01:03:55 +02:00
parent 1a768fedcc
commit 2db5d77296
15 changed files with 732 additions and 5820 deletions

View file

@ -1,18 +1,23 @@
<script setup lang="ts">
import {useLearningObjectListForAdminQuery} from "@/queries/learning-objects.ts";
import OwnLearningObjectsView from "@/views/own-learning-content/OwnLearningObjectsView.vue"
import OwnLearningPathsView from "@/views/own-learning-content/OwnLearningPathsView.vue"
import OwnLearningObjectsView from "@/views/own-learning-content/learning-objects/OwnLearningObjectsView.vue"
import OwnLearningPathsView from "@/views/own-learning-content/learning-paths/OwnLearningPathsView.vue"
import authService from "@/services/auth/auth-service.ts";
import UsingQueryResult from "@/components/UsingQueryResult.vue";
import type { LearningObject } from "@/data-objects/learning-objects/learning-object";
import { ref, type Ref } from "vue";
import { useI18n } from "vue-i18n";
import { useGetAllLearningPathsByAdminQuery } from "@/queries/learning-paths";
import type { LearningPathDTO } from "@/data-objects/learning-paths/learning-path-dto";
const { t } = useI18n();
const learningObjectsQuery =
useLearningObjectListForAdminQuery(authService.authState.user?.profile.preferred_username);
const learningPathsQuery =
useGetAllLearningPathsByAdminQuery(authService.authState.user?.profile.preferred_username);
type Tab = "learningObjects" | "learningPaths";
const tab: Ref<Tab> = ref("learningObjects");
</script>
@ -34,7 +39,12 @@ import { useI18n } from "vue-i18n";
</using-query-result>
</v-tabs-window-item>
<v-tabs-window-item value="learningPaths">
<own-learning-paths-view/>
<using-query-result
:query-result="learningPathsQuery"
v-slot="response: { data: LearningPathDTO[] }"
>
<own-learning-paths-view :learning-paths="response.data"/>
</using-query-result>
</v-tabs-window-item>
</v-tabs-window>
</div>
@ -45,8 +55,10 @@ import { useI18n } from "vue-i18n";
display: flex;
flex-direction: column;
height: 100%;
padding: 20px 30px;
}
.main-content {
flex: 1;
flex: 1 1;
height: 100%;
}
</style>

View file

@ -1,9 +0,0 @@
<script lang="ts">
</script>
<template>
<p>Own learning paths</p>
</template>
<style>
</style>

View file

@ -0,0 +1,50 @@
<script setup lang="ts">
import type { LearningObject } from '@/data-objects/learning-objects/learning-object';
import UsingQueryResult from '@/components/UsingQueryResult.vue';
import LearningObjectContentView from '../../learning-paths/learning-object/content/LearningObjectContentView.vue';
import { useDeleteLearningObjectMutation, useLearningObjectHTMLQuery } from '@/queries/learning-objects';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const props = defineProps<{
selectedLearningObject?: LearningObject
}>();
const learningObjectQueryResult = useLearningObjectHTMLQuery(
() => props.selectedLearningObject?.key,
() => props.selectedLearningObject?.language,
() => props.selectedLearningObject?.version
);
const { isPending, mutate } = useDeleteLearningObjectMutation();
function deleteLearningObject(): void {
if (props.selectedLearningObject) {
mutate({
hruid: props.selectedLearningObject.key,
language: props.selectedLearningObject.language,
version: props.selectedLearningObject.version
});
}
}
</script>
<template>
<v-card
v-if="selectedLearningObject"
:title="t('previewFor') + selectedLearningObject.title"
>
<template v-slot:text>
<using-query-result :query-result="learningObjectQueryResult" v-slot="response: { data: Document }">
<learning-object-content-view :learning-object-content="response.data"></learning-object-content-view>
</using-query-result>
</template>
<template v-slot:actions>
<v-btn text="Delete" @click="deleteLearningObject()"></v-btn>
</template>
</v-card>
</template>
<style scoped>
</style>

View file

@ -32,17 +32,14 @@
<template>
<v-dialog max-width="500" v-model="dialogOpen">
<template v-slot:activator="{ props: activatorProps }">
<v-fab icon="mdi mdi-plus" v-bind="activatorProps"></v-fab>
<v-fab icon="mdi mdi-plus" v-bind="activatorProps" color="rgb(14, 105, 66)" size="large"></v-fab>
</template>
<template v-slot:default="{ isActive }">
<v-card :title="t('learning_object_upload_title')">
<v-card :title="t('learningObjectUploadTitle')">
<v-card-text>
<v-file-upload
:browse-text="t('upload_browse')"
:divider-text="t('upload_divider')"
icon="mdi-upload"
:title="t('upload_drag_and_drop')"
v-model="fileToUpload"
:disabled="isPending"
></v-file-upload>
@ -50,7 +47,7 @@
v-if="error"
icon="mdi mdi-alert-circle"
type="error"
:title="t('upload_failed')"
:title="t('uploadFailed')"
:text="t((error.response?.data as ContainsErrorString).error ?? error.message)"
></v-alert>
</v-card-text>

View file

@ -1,11 +1,9 @@
<script setup lang="ts">
import type { LearningObject } from '@/data-objects/learning-objects/learning-object';
import LearningObjectUploadButton from '@/views/own-learning-content/LearningObjectUploadButton.vue'
import LearningObjectContentView from '../learning-paths/learning-object/content/LearningObjectContentView.vue';
import LearningObjectUploadButton from '@/views/own-learning-content/learning-objects/LearningObjectUploadButton.vue'
import LearningObjectPreviewCard from './LearningObjectPreviewCard.vue';
import { computed, ref, type Ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useLearningObjectHTMLQuery } from '@/queries/learning-objects';
import UsingQueryResult from '@/components/UsingQueryResult.vue';
const { t } = useI18n();
const props = defineProps<{
@ -19,17 +17,12 @@ import UsingQueryResult from '@/components/UsingQueryResult.vue';
{ title: t("title"), key: "title" }
];
const selectedLearningObjects: Ref<LearningObject[]> = ref([])
const selectedLearningObjects: Ref<LearningObject[]> = ref([]);
const selectedLearningObject = computed(() =>
selectedLearningObjects.value ? selectedLearningObjects.value[0] : undefined
)
const learningObjectQueryResult = useLearningObjectHTMLQuery(
() => selectedLearningObject.value?.key,
() => selectedLearningObject.value?.language,
() => selectedLearningObject.value?.version
);
</script>
<template>
@ -43,17 +36,7 @@ import UsingQueryResult from '@/components/UsingQueryResult.vue';
show-select
return-object
/>
<v-card
class="preview"
v-if="selectedLearningObjects.length > 0"
:title="t('preview_for') + selectedLearningObjects[0].title"
>
<template v-slot:text>
<using-query-result :query-result="learningObjectQueryResult" v-slot="response: { data: Document }">
<learning-object-content-view :learning-object-content="response.data"></learning-object-content-view>
</using-query-result>
</template>
</v-card>
<learning-object-preview-card class="preview" :selectedLearningObject="selectedLearningObject"/>
</div>
<div class="fab">
<learning-object-upload-button/>
@ -70,9 +53,11 @@ import UsingQueryResult from '@/components/UsingQueryResult.vue';
display: flex;
gap: 20px;
padding: 20px;
flex-wrap: wrap;
}
.preview {
flex: 1;
min-width: 400px;
}
.table {
flex: 1;

View file

@ -0,0 +1,62 @@
<script setup lang="ts">
import UsingQueryResult from '@/components/UsingQueryResult.vue';
import { useI18n } from 'vue-i18n';
import type { LearningPathDTO } from '@/data-objects/learning-paths/learning-path-dto';
import { computed, ref, watch } from 'vue';
import JsonEditorVue from 'json-editor-vue'
import { useMutation } from '@tanstack/vue-query';
import { usePostLearningPathMutation, usePutLearningPathMutation } from '@/queries/learning-paths';
const { t } = useI18n();
const props = defineProps<{
selectedLearningPath?: LearningPathDTO
}>();
const INDENT = 4;
const DEFAULT_LEARNING_PATH: LearningPathDTO = {
language: '',
hruid: '',
title: '',
description: '',
num_nodes: 0,
num_nodes_left: 0,
nodes: [],
keywords: '',
target_ages: [],
min_age: 0,
max_age: 0,
__order: 0
}
const { isPending: isPostPending, mutate: doPost } = usePostLearningPathMutation();
const { isPending: isPutPending, mutate: doPut } = usePutLearningPathMutation();
const learningPath = ref(DEFAULT_LEARNING_PATH);
watch(() => props.selectedLearningPath, () => learningPath.value = props.selectedLearningPath ?? DEFAULT_LEARNING_PATH);
function uploadLearningPath(): void {
if (props.selectedLearningPath) {
doPut({ learningPath: learningPath.value });
} else {
doPost({ learningPath: learningPath.value });
}
}
</script>
<template>
<v-card
:title="props.selectedLearningPath ? t('editLearningPath') : t('newLearningPath')"
>
<template v-slot:text>
<json-editor-vue v-model="learningPath"></json-editor-vue>
</template>
<template v-slot:actions>
<v-btn @click="uploadLearningPath" :loading="isPostPending || isPutPending">{{ props.selectedLearningPath ? t('saveChanges') : t('create') }}</v-btn>
</template>
</v-card>
</template>
<style scoped>
</style>

View file

@ -0,0 +1,60 @@
<script setup lang="ts">
import LearningPathPreviewCard from './LearningPathPreviewCard.vue';
import { computed, ref, type Ref } from 'vue';
import { useI18n } from 'vue-i18n';
import type { LearningPathDTO } from '@/data-objects/learning-paths/learning-path-dto';
const { t } = useI18n();
const props = defineProps<{
learningPaths: LearningPathDTO[]
}>();
const tableHeaders = [
{ title: t("hruid"), width: "250px", key: "key" },
{ title: t("language"), width: "50px", key: "language" },
{ title: t("title"), key: "title" }
];
const selectedLearningPaths: Ref<LearningPathDTO[]> = ref([]);
const selectedLearningPath = computed(() =>
selectedLearningPaths.value ? selectedLearningPaths.value[0] : undefined
);
</script>
<template>
<div class="root">
<v-data-table
class="table"
v-model="selectedLearningPaths"
:items="props.learningPaths"
:headers="tableHeaders"
select-strategy="single"
show-select
return-object
/>
<learning-path-preview-card class="preview" :selectedLearningPath="selectedLearningPath"/>
</div>
</template>
<style scoped>
.fab {
position: absolute;
right: 20px;
bottom: 20px;
}
.root {
display: flex;
gap: 20px;
padding: 20px;
flex-wrap: wrap;
}
.preview {
flex: 1;
min-width: 400px;
}
.table {
flex: 1;
}
</style>