diff --git a/docs/user/adaptive-learning/adaptive-learning-instructor.rst b/docs/user/adaptive-learning/adaptive-learning-instructor.rst index cef05c5e10d9..955d00e18d6b 100644 --- a/docs/user/adaptive-learning/adaptive-learning-instructor.rst +++ b/docs/user/adaptive-learning/adaptive-learning-instructor.rst @@ -36,7 +36,7 @@ Instructors can manage competencies and prerequisites of a course in the *Compet * View all competencies and prerequisites of their course * Create, edit or delete competencies and prerequisites -* Manage relations between competencies (which are necessary to build learning paths) +* :ref:`manage_relations` between competencies * :ref:`import_competencies` from other courses or the :ref:`standardized competency catalog` * :ref:`generate_competencies` using LLMs @@ -59,6 +59,26 @@ Alternatively, instructors can also link competencies to an exercise or lecture |instructor-competency-link| +.. _manage_relations: + +Manage Relations +^^^^^^^^^^^^^^^^ + +| An Instructor can create relations between competencies by selecting a source and target competency from the dropdown menus. + They can also set a relation type, which can be one of the following: + +* *Assumes*: The head competency assumes the knowledge of the tail competency but does not deepen it. E.g. Class diagrams assume knowledge about object-oriented programming. +* *Extends*: The head competency builds upon the knowledge of the tail competency and deepens it. E.g. Inheritance deepens the knowledge about object-oriented programming. +* *Matches*: The knowledge of the head and tail competency match each other. + +| The relations are displayed in a diagram below the form and can be deleted by clicking on them. + +.. note:: + + Relations are necessary for the learning path generation. Without them, Artemis cannot suggest a reasonable order of competencies for students. + +|instructor-competency-relations| + .. _import_competencies: Import Competencies @@ -149,6 +169,8 @@ Once the feature is enabled, instructors get access to each student's learning p :width: 1000 .. |instructor-competency-link| image:: instructor/competency-link.png :width: 600 +.. |instructor-competency-relations| image:: instructor/competency-relations.png + :width: 1000 .. |instructor-generate-competencies| image:: instructor/generate-competencies.png :width: 1000 .. |instructor-competency-recommendation| image:: instructor/competency-recommendation.png diff --git a/docs/user/adaptive-learning/instructor/competency-relations.png b/docs/user/adaptive-learning/instructor/competency-relations.png new file mode 100644 index 000000000000..d22a1ccb47b8 Binary files /dev/null and b/docs/user/adaptive-learning/instructor/competency-relations.png differ diff --git a/src/main/java/de/tum/in/www1/artemis/domain/competency/RelationType.java b/src/main/java/de/tum/in/www1/artemis/domain/competency/RelationType.java index eb5907a81fbf..ac4f04e7cb98 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/competency/RelationType.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/competency/RelationType.java @@ -1,10 +1,6 @@ package de.tum.in.www1.artemis.domain.competency; public enum RelationType { - /** - * A generic relation between two competencies. - */ - RELATES, /** * The tail competency assumes that the student already achieved the head competency. */ diff --git a/src/main/resources/config/liquibase/changelog/20240708144500_changelog.xml b/src/main/resources/config/liquibase/changelog/20240708144500_changelog.xml new file mode 100644 index 000000000000..cccaa5515918 --- /dev/null +++ b/src/main/resources/config/liquibase/changelog/20240708144500_changelog.xml @@ -0,0 +1,12 @@ + + + + + UPDATE competency_relation + SET type = type - 1 + WHERE type > 0; + + + diff --git a/src/main/resources/config/liquibase/master.xml b/src/main/resources/config/liquibase/master.xml index 6cd571aaaa4d..ab3037c89fad 100644 --- a/src/main/resources/config/liquibase/master.xml +++ b/src/main/resources/config/liquibase/master.xml @@ -18,6 +18,7 @@ + diff --git a/src/main/webapp/app/course/competencies/competency-management/competency-relation-graph.component.html b/src/main/webapp/app/course/competencies/competency-management/competency-relation-graph.component.html index 078d871d2414..e50d548a6cc4 100644 --- a/src/main/webapp/app/course/competencies/competency-management/competency-relation-graph.component.html +++ b/src/main/webapp/app/course/competencies/competency-management/competency-relation-graph.component.html @@ -39,7 +39,10 @@ (change)="validate()" > @for (relationType of competencyRelationType | keyvalue: keepOrder; track relationType) { - + } diff --git a/src/main/webapp/app/entities/competency.model.ts b/src/main/webapp/app/entities/competency.model.ts index c40c4c896f03..c7c4df55b1b9 100644 --- a/src/main/webapp/app/entities/competency.model.ts +++ b/src/main/webapp/app/entities/competency.model.ts @@ -20,7 +20,6 @@ export enum CompetencyTaxonomy { } export enum CompetencyRelationType { - RELATES = 'RELATES', ASSUMES = 'ASSUMES', EXTENDS = 'EXTENDS', MATCHES = 'MATCHES', diff --git a/src/main/webapp/i18n/de/competency.json b/src/main/webapp/i18n/de/competency.json index 1790a798d6e1..285d14522267 100644 --- a/src/main/webapp/i18n/de/competency.json +++ b/src/main/webapp/i18n/de/competency.json @@ -180,18 +180,22 @@ }, "relation": { "competencyRelations": "Beziehungen zwischen Kompetenzen", - "tailCompetency": "Kompetenz Schluss", + "tailCompetency": "Schlusskompetenz", "relationType": "Beziehungstyp", - "headCompetency": "Kompetenz Start", + "headCompetency": "Startkompetenz", "createRelation": "Beziehung erstellen", "createsCircularRelation": "Du kannst keine kreisförmigen Beziehungen zwischen Kompetenzen erstellen.", "selfRelation": "Du kannst keine Beziehung zwischen einer Kompetenz und sich selbst erstellen.", "relationAlreadyExists": "Diese Beziehung existiert bereits.", "type": { - "RELATES": "Bezieht sich auf", "ASSUMES": "Setzt voraus", "EXTENDS": "Erweitert", "MATCHES": "Stimmt überein mit" + }, + "typeExplanation": { + "ASSUMES": "Die Startkompetenz setzt das Wissen aus der Schlusskompetenz voraus und bringt neues Wissen bei, das auf der Schlusskompetenz aufbaut.", + "EXTENDS": "Die Startkompetenz setzt das Wissen aus der Schlusskompetenz voraus und vertieft dieses Wissen weiter.", + "MATCHES": "Die Start- und Schlusskompetenz sind gleichwertig und umfassen dasselbe Wissen." } } }, diff --git a/src/main/webapp/i18n/en/competency.json b/src/main/webapp/i18n/en/competency.json index d18b116ee619..b6f4ace4f8e7 100644 --- a/src/main/webapp/i18n/en/competency.json +++ b/src/main/webapp/i18n/en/competency.json @@ -188,10 +188,14 @@ "selfRelation": "You can not create a relation between a competency and itself.", "relationAlreadyExists": "This relation already exists.", "type": { - "RELATES": "Relates", "ASSUMES": "Assumes", "EXTENDS": "Extends", "MATCHES": "Matches" + }, + "typeExplanation": { + "ASSUMES": "The head competency assumes that the student mastered the tail competency and teaches new knowledge that builds upon the tail competency.", + "EXTENDS": "The head competency assumes that the student mastered the tail competency and deepens that knowledge further.", + "MATCHES": "The head and tail competency match and cover the same knowledge." } } }, diff --git a/src/test/java/de/tum/in/www1/artemis/competency/CompetencyIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/competency/CompetencyIntegrationTest.java index ef9cf6c1e447..316a96a233fd 100644 --- a/src/test/java/de/tum/in/www1/artemis/competency/CompetencyIntegrationTest.java +++ b/src/test/java/de/tum/in/www1/artemis/competency/CompetencyIntegrationTest.java @@ -954,7 +954,7 @@ void shouldImportCompetencies() throws Exception { Competency head = createCompetency(course3); Competency tail = createCompetency(course3); - createRelation(tail, head, RelationType.RELATES); + createRelation(tail, head, RelationType.ASSUMES); competencyDTOList = request.postListWithResponseBody("/api/courses/" + course.getId() + "/competencies/import-all/" + course3.getId() + "?importRelations=true", null, CompetencyWithTailRelationDTO.class, HttpStatus.CREATED); @@ -1046,7 +1046,7 @@ void shouldImportCompetencies() throws Exception { Competency head = createCompetency(course2); Competency tail = createCompetency(course2); - createRelation(tail, head, RelationType.RELATES); + createRelation(tail, head, RelationType.ASSUMES); List competencyList = List.of(head, tail); competencyDTOList = request.postListWithResponseBody("/api/courses/" + course.getId() + "/competencies/import/bulk?importRelations=true", competencyList, diff --git a/src/test/java/de/tum/in/www1/artemis/service/LearningPathServiceTest.java b/src/test/java/de/tum/in/www1/artemis/service/LearningPathServiceTest.java index 12589529149e..063a924dac16 100644 --- a/src/test/java/de/tum/in/www1/artemis/service/LearningPathServiceTest.java +++ b/src/test/java/de/tum/in/www1/artemis/service/LearningPathServiceTest.java @@ -252,11 +252,6 @@ void testSimpleRelation(RelationType type) { generateGraphAndAssert(expected); } - @Test - void testSingleRelates() { - testSimpleRelation(RelationType.RELATES); - } - @Test void testSingleAssumes() { testSimpleRelation(RelationType.ASSUMES); @@ -415,10 +410,10 @@ void testOrderOfCompetenciesByPriorUtility() { Competency[] priors2 = competencyUtilService.createCompetencies(course, future(111), future(113), future(115)); for (var competency : priors1) { - competencyUtilService.addRelation(competency1, RelationType.RELATES, competency); + competencyUtilService.addRelation(competency1, RelationType.ASSUMES, competency); } for (var competency : priors2) { - competencyUtilService.addRelation(competency2, RelationType.RELATES, competency); + competencyUtilService.addRelation(competency2, RelationType.ASSUMES, competency); } masterCompetencies(priors1); masterCompetencies(priors2[0]); diff --git a/src/test/javascript/spec/component/competencies/competency.service.spec.ts b/src/test/javascript/spec/component/competencies/competency.service.spec.ts index 010e7d5e8e2f..47ae7ebd8676 100644 --- a/src/test/javascript/spec/component/competencies/competency.service.spec.ts +++ b/src/test/javascript/spec/component/competencies/competency.service.spec.ts @@ -294,7 +294,7 @@ describe('CompetencyService', () => { it('should get competency relations', fakeAsync(() => { const relation: CompetencyRelation = { id: 1, - type: CompetencyRelationType.RELATES, + type: CompetencyRelationType.ASSUMES, }; const returnedFromService = [relation]; const expected = [...returnedFromService];