feat: add profile option in local server#369
Conversation
There was a problem hiding this comment.
Pull request overview
Adds multi-profile support to Deepr’s local server UI and API so users can create and switch between link profiles when using the embedded web interface.
Changes:
- Added
/api/profilesGET/POST endpoints and extended link APIs to accept/filter byprofileId. - Updated local server HTML UI with a profile dropdown and “New Profile” modal.
- Updated link load/create requests to include the selected
profileId.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| app/src/main/java/com/yogeshpaliyal/deepr/server/LocalServerRepositoryImpl.kt | Adds profiles API endpoints and threads profileId through link listing/creation. |
| app/src/main/assets/index.html | Adds profile selector + modal and passes profileId in link API calls. |
| deeprQueries.insertProfile(request.name) | ||
| call.respond( | ||
| HttpStatusCode.Created, | ||
| SuccessResponse("Profile created successfully"), | ||
| ) |
There was a problem hiding this comment.
POST /api/profiles writes directly via deeprQueries.insertProfile(), which bypasses the usual repository/viewmodel side effects (e.g., auto-backup scheduling in LinkRepositoryImpl.insertProfile() and analytics in AccountViewModel.insertProfile()). Also, because insertProfile is INSERT OR IGNORE (name is UNIQUE), this handler will always return 201 Created even when nothing is inserted; consider returning 409 Conflict/200 OK for existing profiles and returning the created/existing profile (including id) in the response so the UI doesn't have to re-fetch and guess.
| deeprQueries.insertProfile(request.name) | |
| call.respond( | |
| HttpStatusCode.Created, | |
| SuccessResponse("Profile created successfully"), | |
| ) | |
| // Check if a profile with the same name already exists | |
| val existingProfiles = deeprQueries.getAllProfiles().executeAsList() | |
| val existingProfile = existingProfiles.find { it.name == request.name } | |
| if (existingProfile != null) { | |
| val response = | |
| ProfileResponse( | |
| id = existingProfile.id, | |
| name = existingProfile.name, | |
| createdAt = existingProfile.createdAt, | |
| ) | |
| call.respond(HttpStatusCode.OK, response) | |
| } else { | |
| // Use AccountViewModel to ensure side effects (backup, analytics, etc.) are applied | |
| accountViewModel.insertProfile(request.name) | |
| // Fetch the newly created profile | |
| val updatedProfiles = deeprQueries.getAllProfiles().executeAsList() | |
| val createdProfile = updatedProfiles.find { it.name == request.name } | |
| if (createdProfile != null) { | |
| val response = | |
| ProfileResponse( | |
| id = createdProfile.id, | |
| name = createdProfile.name, | |
| createdAt = createdProfile.createdAt, | |
| ) | |
| call.respond(HttpStatusCode.Created, response) | |
| } else { | |
| call.respond( | |
| HttpStatusCode.InternalServerError, | |
| ErrorResponse("Profile was not found after creation"), | |
| ) | |
| } | |
| } |
| get("/api/profiles") { | ||
| try { | ||
| val profiles = deeprQueries.getAllProfiles().executeAsList() | ||
| val response = | ||
| profiles.map { profile -> | ||
| ProfileResponse( | ||
| id = profile.id, | ||
| name = profile.name, | ||
| createdAt = profile.createdAt, | ||
| ) | ||
| } | ||
| call.respond(HttpStatusCode.OK, response) |
There was a problem hiding this comment.
GET /api/profiles can legitimately return an empty list (e.g., on a fresh DB before the async default-profile initialization completes). Since the UI replaces the <select> options with the returned list, an empty response leaves the profile selector blank. Consider ensuring a default profile exists synchronously before responding, or returning a non-empty list by creating/including a default profile when none exist.
| // Populate profile dropdown | ||
| function populateProfileSelect() { | ||
| const profileSelect = document.getElementById('profileSelect'); | ||
| profileSelect.innerHTML = profiles.map(profile => ` | ||
| <option value="${profile.id}" ${profile.id === selectedProfileId ? 'selected' : ''}> | ||
| ${escapeHtml(profile.name)} | ||
| </option> | ||
| `).join(''); | ||
| } |
There was a problem hiding this comment.
populateProfileSelect() fully replaces the <select> options with profiles. If the backend returns an empty list (or the default profile’s id isn’t 1), the selector becomes empty and selectedProfileId may no longer match any option. Consider keeping a fallback option when profiles.length === 0, and/or updating selectedProfileId to the first returned profile id before rendering so subsequent /api/links?profileId=... requests stay consistent.
🧪 Integrated Test ResultsThe integrated UI tests have completed. View full test results: Test Run #21785706752 Test reports are available in the artifacts section of the workflow run. |
📱 APK Build Complete!Your debug APK has been built successfully and is ready for testing. 📥 Download APKNote: Click the link above, scroll down to the "Artifacts" section, and download the Retention: This artifact will be available for 3 days. |
🧪 Integrated Test ResultsThe integrated UI tests have completed. View full test results: Test Run #21793605978 Test reports are available in the artifacts section of the workflow run. |
📱 APK Build Complete!Your debug APK has been built successfully and is ready for testing. 📥 Download APKNote: Click the link above, scroll down to the "Artifacts" section, and download the Retention: This artifact will be available for 3 days. |
🧪 Integrated Test ResultsThe integrated UI tests have completed. View full test results: Test Run #21793792273 Test reports are available in the artifacts section of the workflow run. |
This pull request introduces a new "Profile" feature to the Deepr application, allowing users to manage multiple link profiles and switch between them. The changes include frontend UI enhancements and backend API support for profile creation, selection, and association with links.
Profile Management Feature
Frontend Integration
profileIdin API requests. [1] [2]Backend API Support
/api/profilesGET and POST endpoints for retrieving all profiles and creating new profiles, respectively./api/linksendpoint and link creation logic to support filtering and associating links byprofileId. [1] [2]ProfileResponseandAddProfileRequest, and updatedAddLinkRequestto includeprofileId.