Skip to content

Conversation

@Hialus
Copy link
Member

@Hialus Hialus commented Jan 26, 2026

Summary

This PR updates the learner profile to use the new aggregated Iris memories API, eliminating per-memory requests and significantly improving performance and UX. Memory details and conflict detection are now derived locally from aggregated data, enabling instant expansion, silent updates after deletions, and removal of unnecessary loading states. The change also modernizes the client with Angular Signals, introduces a dedicated memory details component, and aligns client, server, tests, and shared models with the updated API.

Checklist

General

Server

  • Important: I implemented the changes with a very good performance and prevented too many (unnecessary) and too complex database calls.
  • I strictly followed the principle of data economy for all database calls.
  • I strictly followed the server coding and design guidelines and the REST API guidelines.
  • I added multiple integration tests (Spring) related to the features (with a high test coverage).
  • I added pre-authorization annotations according to the guidelines and checked the course groups for all new REST Calls (security).
  • I documented the Java code using JavaDoc style.

Client

  • Important: I implemented the changes with a very good performance, prevented too many (unnecessary) REST calls and made sure the UI is responsive, even with large data (e.g. using paging).
  • I strictly followed the principle of data economy for all client-server REST calls.
  • I strictly followed the client coding guidelines.
  • I strictly followed the AET UI-UX guidelines.
  • Following the theming guidelines, I specified colors only in the theming variable files and checked that the changes look consistent in both the light and the dark theme.
  • I added multiple integration tests (Jest) related to the features (with a high test coverage), while following the test guidelines.
  • I documented the TypeScript code using JSDoc style.
  • I added multiple screenshots/screencasts of my UI changes.
  • I translated all newly inserted strings into English and German.

Motivation and Context

Memiris is not yet capable of automatically resolving memory conflicts, as this will be a significant effort outside of the scope of my Master's thesis.
Therefore for the meantime, we want to ensure that users are able to resolve memories manually in their settings.
Additionally, this PR reworks the system to load memories, as the old one was too inefficient to support this new system.

Description

  • Client

    • IrisMemoriesHttpService

      • Added getUserMemoryData()GET api/iris/user/memoryData.
      • Updated getUserMemory(id) and deleteUserMemory(id)GET/DELETE api/iris/user/memory/{id}.
      • Added method-level documentation.
    • MemirisMemoriesListComponent

      • Migrated state management to Angular Signals (loading, deleting, memoryData, open).
      • Added derived signals (memories, conflictGroups, hasConflicts, details).
      • Removed per-memory detail loading; details are derived from aggregated data.
      • Optimized conflict detection using aggregated connections only.
      • Deletions update cached data silently without reloading the list or showing intermediate loading states.
      • Simplified documentation and removed attribute-level comments.
    • memiris-memory-details.component (standalone)

      • Presentational component rendering content, learnings, and connections using the new control flow syntax.
    • Templates

      • Updated to use signals and the extracted details component.
    • Tests (client)

      • Updated service tests for new endpoints.
      • Updated list component tests to use aggregated data, assert no per-memory requests, and verify silent updates after deletions.
  • Server

    • Aligned IrisMemoryResource paths:

      • GET api/iris/user/memoryData
      • GET/DELETE api/iris/user/memory/{id}
    • Tests (server)

      • Updated integration tests to new endpoints and aggregated DTO.
      • Extended IrisRequestMockProvider to mock the v2 aggregated Memiris endpoint while retaining v1 single-memory routes.
  • Shared models

    • Added MemirisMemoryDataDTO (memories, learnings, connections) to match the server response.
  • i18n

    • Reused existing keys; no new translations added.

Steps for Testing

Prerequisites

  1. Log in as Student A and navigate to Profile → Settings → Learner Profile → Iris.
  2. Ensure that the memory collection is enabled
  3. Go to the course chat and tell Iris in 2 separate messages conflicting facts about yourself (e.g. I like X & I hate X)
  4. Wait for the sleep function to trigger (Either wait 24h or run Iris locally and manually call the respective method in main.py)
  5. Got back to the learner profile
  6. See a list of memories
  7. Expanding a memory is possible
  8. There should be a conflict resolution banner
  9. Resolve the conflicts
  10. One of the memories will be deleted

Testserver States

You can manage test servers using Helios. Check environment statuses in the environment list. To deploy to a test server, go to the CI/CD page, find your PR or branch, and trigger the deployment.

Review Progress

Performance Review

  • I (as a reviewer) confirm that the client changes (in particular related to REST calls and UI responsiveness) are implemented with a very good performance even for very large courses with more than 2000 students.
  • I (as a reviewer) confirm that the server changes (in particular related to database calls) are implemented with a very good performance even for very large courses with more than 2000 students.

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Test Coverage

Client

Class/File Line Coverage Lines Expects Ratio
memiris-memories-list.component.ts 82.17% 153 12 7.8
memiris-memory-details.component.ts 80.00% 13 ? ?
resolve-memories-conflicts-modal.component.ts 97.87% 72 18 25.0
iris-memories-http.service.ts 100.00% 18 10 55.6
memiris.model.ts not found (modified) 46 ? ?

Server

Class/File Line Coverage Lines
MemirisMemoryDataDTO.java 100.00% 6
PyrisConnectorService.java 70.00% 220
IrisMemoryResource.java 100.00% 51

Last updated: 2026-01-26 21:30:43 UTC

Screenshots

image image

Summary by CodeRabbit

Release Notes

  • New Features

    • Added memory conflict resolution modal to manage and resolve duplicate memories.
  • Refactor

    • Restructured memory API endpoints and data retrieval format.
    • Refactored memory details and list display components with improved state management.

✏️ Tip: You can customize this high-level summary in your review settings.

@github-project-automation github-project-automation bot moved this to Work In Progress in Artemis Development Jan 26, 2026
@github-actions github-actions bot added tests server Pull requests that update Java code. (Added Automatically!) client Pull requests that update TypeScript code. (Added Automatically!) core Pull requests that affect the corresponding module iris Pull requests that affect the corresponding module labels Jan 26, 2026
@github-actions
Copy link

@Hialus Test coverage could not be fully measured because some tests failed. Please check the workflow logs for details.

@github-actions
Copy link

@Hialus Test coverage has been automatically updated in the PR description.

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ✅SkippedFailedTime ⏱
End-to-End (E2E) Test Report1 ran1 passed0 skipped0 failed2s 263ms
TestResultTime ⏱
No test annotations available

@github-actions
Copy link

@Hialus Test coverage has been automatically updated in the PR description.

@Hialus Hialus marked this pull request as ready for review January 26, 2026 21:23
@Hialus Hialus requested review from a team and krusche as code owners January 26, 2026 21:23
@Hialus Hialus moved this from Work In Progress to Ready For Review in Artemis Development Jan 26, 2026
@github-actions
Copy link

@Hialus Test coverage has been automatically updated in the PR description.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 26, 2026

Walkthrough

This change introduces a new aggregated MemirisMemoryDataDTO that consolidates memories, learnings, and memory connections. The backend API is upgraded to v2, with service methods renamed to return the new DTO. Frontend components are refactored to use Angular signals, and a new conflict-resolution modal is added. Related endpoints and tests are updated accordingly.

Changes

Cohort / File(s) Summary
Backend DTO
src/main/java/de/tum/cit/aet/artemis/iris/dto/MemirisMemoryDataDTO.java
New record introduced to aggregate three lists: memories, learnings, and connections with @JsonInclude(NON_EMPTY) annotation
Backend Services
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisConnectorService.java
Method renamed from listMemirisMemories() to listMemirisMemoryData() returning MemirisMemoryDataDTO; API endpoint upgraded from /api/v1/... to /api/v2/...; response handling and error handling (404) updated
REST Controller
src/main/java/de/tum/cit/aet/artemis/iris/web/IrisMemoryResource.java
Base path changed from api/iris/memories/ to api/iris/; method listMemories() renamed to listMemoryData() returning MemirisMemoryDataDTO; endpoint paths updated ("user""user/memory-data", "user/{memoryId}""user/memory/{memoryId}"); service call updated
Frontend HTTP Service
src/main/webapp/app/iris/overview/services/iris-memories-http.service.ts, src/main/webapp/app/iris/overview/services/iris-memories-http.service.spec.ts
Method renamed from listUserMemories() to getUserMemoryData() returning Observable<MemirisMemoryDataDTO>; API prefix updated; endpoint paths updated from api/iris/memories/user to api/iris/user/memory-data
Frontend Data Models
src/main/webapp/app/iris/shared/entities/memiris.model.ts
New interface MemirisMemoryDataDTO added with memories, learnings, and connections arrays
Frontend List Component
src/main/webapp/app/core/user/settings/learner-profile/insights-learner-profile/iris-learner-profile/memiris-memories-list.component.ts, .html
Refactored to use Angular signals for state (loading, deleting, memoryData, open); introduced computed values for derived data (memories, conflictGroups, hasConflicts, details); added openResolveConflictsModal() method and modal integration with NgbModal; reworked data loading and detail-building logic
Frontend Detail Component (New)
src/main/webapp/app/core/user/settings/learner-profile/insights-learner-profile/iris-learner-profile/memiris-memory-details.component.ts, .html
New standalone presentational component for rendering memory details including learnings and connections with fallback messaging
Frontend Conflict Modal (New)
src/main/webapp/app/core/user/settings/learner-profile/insights-learner-profile/iris-learner-profile/resolve-memories-conflicts-modal.component.ts, .html, .spec.ts
New standalone modal component for resolving memory conflicts; manages navigation between conflict groups, deletion of non-selected memories, and modal result handling
Frontend Component Tests
src/main/webapp/app/core/user/settings/learner-profile/insights-learner-profile/iris-learner-profile/memiris-memories-list.component.spec.ts
Updated mocks from listUserMemories to getUserMemoryData; shifted property-based assertions to function-call style (signals); updated deletion and error handling test paths
I18N Translations
src/main/webapp/i18n/de/iris.json, src/main/webapp/i18n/en/iris.json
Added conflict object under artemisApp.iris.memories with keys for warning, modal title, actions (resolve, keep, navigate), and status messages
Backend Test Support
src/test/java/de/tum/cit/aet/artemis/core/connector/IrisRequestMockProvider.java
Added memirisApiV2URL field; introduced mockListMemoryData() and mockListMemoryDataError() helper methods for v2 Memiris endpoint mocking
Backend Integration Tests
src/test/java/de/tum/cit/aet/artemis/iris/IrisMemoryResourceIntegrationTest.java
Updated test methods to use MemirisMemoryDataDTO; switched endpoint calls from listMemories to listMemoryData; updated assertion paths for memories, learnings, and connections; updated mock calls to use v2 helpers

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Frontend as Learner Profile<br/>(UI)
    participant ListComp as MemirisMemoriesListComponent<br/>(Signal-based)
    participant HttpService as IrisMemoriesHttpService
    participant Backend as IrisMemoryResource<br/>(REST)
    participant PyrisService as PyrisConnectorService
    participant Modal as ResolveMemoriesConflictsModal

    User->>Frontend: Load learner profile
    Frontend->>ListComp: loadMemories()
    ListComp->>HttpService: getUserMemoryData()
    HttpService->>Backend: GET /api/iris/user/memory-data
    Backend->>PyrisService: listMemirisMemoryData()
    PyrisService-->>Backend: MemirisMemoryDataDTO
    Backend-->>HttpService: MemirisMemoryDataDTO
    HttpService-->>ListComp: Observable<MemirisMemoryDataDTO>
    ListComp->>ListComp: Store in memoryData signal<br/>Calculate conflictGroups
    
    alt Conflicts Detected
        ListComp->>Modal: openResolveConflictsModal()
        Modal->>Modal: Initialize groups & currentIndex
        User->>Modal: Browse conflicts
        Modal->>Modal: prev()/next() navigation
        User->>Modal: keep(groupIndex, selectedId)
        Modal->>HttpService: deleteUserMemory(id) for non-selected
        HttpService->>Backend: DELETE /api/iris/user/memory/{id}
        Backend-->>HttpService: OK
        Modal->>ListComp: resolve with deletedIds[]
        ListComp->>ListComp: applyDeletions() to memoryData
    else No Conflicts
        Frontend->>Frontend: Render memories directly
    end
    
    User->>Frontend: Click memory for details
    ListComp->>ListComp: toggleOpen(memory)
    ListComp->>HttpService: getUserMemory(memoryId)
    HttpService->>Backend: GET /api/iris/user/memory/{memoryId}
    Backend-->>HttpService: MemirisMemoryWithRelationsDTO
    ListComp->>ListComp: buildDetails() & cache result
    Frontend-->>Frontend: Render via<br/>MemirisMemoryDetailsComponent
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main feature: allowing users to resolve memory conflicts in Iris, which aligns with the primary objective of the PR to add conflict resolution UI and logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/iris/memory-conflict-resolution

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/java/de/tum/cit/aet/artemis/iris/service/pyris/PyrisConnectorService.java (1)

83-99: Normalize potentially null lists in the aggregated response.

If Pyris returns any null lists, the API contract (arrays) can break client assumptions. Consider normalizing to empty lists before returning the DTO. Based on learnings, please sanitize upstream inputs.

🛠️ Suggested defensive normalization
-            return response.getBody();
+            var body = response.getBody();
+            return new MemirisMemoryDataDTO(
+                Optional.ofNullable(body.memories()).orElseGet(Collections::emptyList),
+                Optional.ofNullable(body.learnings()).orElseGet(Collections::emptyList),
+                Optional.ofNullable(body.connections()).orElseGet(Collections::emptyList)
+            );
src/main/webapp/app/core/user/settings/learner-profile/insights-learner-profile/iris-learner-profile/memiris-memories-list.component.spec.ts (1)

49-98: Add tests for conflict resolution functionality in the main component spec.

The test file covers memory loading, details expansion, and deletion, but lacks coverage for key conflict-resolution features introduced in this PR:

  • conflictGroups computed signal (conflict detection and grouping)
  • hasConflicts computed signal
  • openResolveConflictsModal() method and its integration with modal result handling
  • applyDeletions() behavior beyond the deleteMemory context

While a separate resolve-memories-conflicts-modal.component.spec.ts exists for the modal component, the main component's integration with conflict detection and modal-driven deletions is not tested.

🧹 Nitpick comments (6)
src/main/webapp/app/core/user/settings/learner-profile/insights-learner-profile/iris-learner-profile/resolve-memories-conflicts-modal.component.spec.ts (2)

40-44: Consider using mockClear() for consistent mock resets.

Reassigning jest.fn() to reset mocks works but is unconventional. Using mockClear() or mockReset() is more idiomatic and preserves mock implementation if needed.

♻️ Suggested improvement
     afterEach(() => {
         jest.restoreAllMocks();
-        activeModalMock.close = jest.fn();
-        activeModalMock.dismiss = jest.fn();
+        (activeModalMock.close as jest.Mock).mockClear();
+        (activeModalMock.dismiss as jest.Mock).mockClear();
     });

53-63: Consider adding boundary condition tests for navigation.

The test verifies forward/backward navigation but doesn't verify behavior at boundaries (e.g., calling prev() at index 0 or next() at the last index). Adding these assertions would ensure the component handles edge cases correctly.

♻️ Suggested additions
     it('navigates with next and prev within bounds', () => {
         component.conflictGroups = [['a'], ['b'], ['c']];
         component.ngOnInit();
         expect(component.currentIndex()).toBe(0);
+        // Verify prev() at start doesn't go negative
+        component.prev();
+        expect(component.currentIndex()).toBe(0);
         component.next();
         expect(component.currentIndex()).toBe(1);
         component.next();
         expect(component.currentIndex()).toBe(2);
+        // Verify next() at end doesn't exceed bounds
+        component.next();
+        expect(component.currentIndex()).toBe(2);
         component.prev();
         expect(component.currentIndex()).toBe(1);
     });
src/main/webapp/app/core/user/settings/learner-profile/insights-learner-profile/iris-learner-profile/memiris-memory-details.component.ts (1)

13-13: Remove unnecessary CommonModule import.

The template uses only modern Angular control flow syntax (@if, @for) and the TranslateDirective. No CommonModule-dependent features (pipes, legacy structural directives) are present, making the import unnecessary for this standalone component.

♻️ Suggested change
 `@Component`({
     selector: 'jhi-memiris-memory-details',
     standalone: true,
-    imports: [CommonModule, TranslateDirective],
+    imports: [TranslateDirective],
     templateUrl: './memiris-memory-details.component.html',
 })

Also remove the unused import:

-import { CommonModule } from '@angular/common';
src/main/webapp/app/core/user/settings/learner-profile/insights-learner-profile/iris-learner-profile/resolve-memories-conflicts-modal.component.ts (1)

54-57: Remove unused _groupIndex parameter.

The _groupIndex parameter is documented as unused. Consider removing it entirely to avoid confusion, or if it's required for template binding compatibility, document that explicitly.

♻️ Suggested fix
-    async keep(_groupIndex: number, keepId: string): Promise<void> {
+    async keep(keepId: string): Promise<void> {
src/main/webapp/app/core/user/settings/learner-profile/insights-learner-profile/iris-learner-profile/memiris-memories-list.component.ts (2)

176-198: Spread operator usage for objects.

Per coding guidelines, prefer avoiding the spread operator for objects. The current implementation uses spread in multiple places (lines 183-184, 189, 194). While functional, consider using explicit object construction or Object.assign for consistency with project conventions.

♻️ Example refactor for one instance
-        this.open.update((o) => {
-            const copy = { ...o };
-            for (const id of deletedIds) delete copy[id];
-            return copy;
-        });
+        this.open.update((o) => {
+            const copy = Object.assign({}, o);
+            for (const id of deletedIds) delete copy[id];
+            return copy;
+        });

116-120: Remove orphaned comment.

This comment block and the empty // conflicts are derived... line appear to be leftover artifacts. The conflict computation logic is already documented at the conflictGroups computed signal definition.

♻️ Suggested fix
-    /**
-     * Computes conflict groups from aggregated connections and precomputes details for involved memories.
-     */
-    // conflicts are derived via computed conflictGroups
-

@github-actions
Copy link

End-to-End (E2E) Test Results Summary

TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
End-to-End (E2E) Test Report223 ran221 passed1 skipped1 failed1h 25m 28s 661ms
TestResultTime ⏱
End-to-End (E2E) Test Report
e2e/course/CourseMessages.spec.ts
ts.Course messages › Channel messages › Write/edit/delete message in channel › Student should be able to write message in channel❌ failure2m 18s 595ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client Pull requests that update TypeScript code. (Added Automatically!) core Pull requests that affect the corresponding module iris Pull requests that affect the corresponding module ready for review server Pull requests that update Java code. (Added Automatically!) tests

Projects

Status: Ready For Review

Development

Successfully merging this pull request may close these issues.

2 participants