20 add bulk delete contacts view - #24
Conversation
- Improve SQL `INSERT INTO` formatting for clarity. - Reorganize and reformat HTML templates for better consistency and readability. - Adjust Thymeleaf directives in fragments and templates. - Simplify annotation formatting in `Contact.java`. - Rename `slugs` parameter to `selected_contact_slugs` in `deleteManyContacts` for clarity. - Update `.idea` settings to remove obsolete biome options.
- Add `page` parameter to `contacts` endpoint in `ContactController`. - Pass `page` as a model attribute for rendering. - Update HTML template to support dynamic content loading with HTMX.
- Wrap contact list in a form with `hx-delete` for bulk deletion functionality. - Replace contact list rows with a Thymeleaf fragment for better modularity. - Add a "Delete Selected" button for bulk actions.
- Insert multiple new contacts into `data.sql` for extended dataset. - Refactor `contact-list-rows` Thymeleaf fragment to include `th:fragment` for reusability. - Adjust "Delete Selected" button to include HTMX attributes for confirmation and deletion logic. - Remove unused `page` parameter from `ContactController` and related HTML templates.
… list template for correct Thymeleaf usage
…tor `contact-list-rows` for streamlined Thymeleaf rendering
…t "Delete Selected" button for readability
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds UI and controller support for bulk-deleting contacts via an optional Changes
Sequence DiagramsequenceDiagram
actor User
participant UI as "Browser / Contact List"
participant HTMX as "HTMX"
participant Controller as "ContactController"
participant Service as "ContactService"
participant DB as "Database"
User->>UI: select checkboxes
User->>UI: click "Delete Selected"
UI->>HTMX: DELETE /contacts?selected_contact_slugs=...
HTMX->>Controller: HTTP DELETE request
Controller->>Controller: if selected_contact_slugs null/empty -> return 204
alt non-empty
Controller->>Service: deleteMany(selected_contact_slugs)
Service->>DB: delete rows by slug list
DB-->>Service: confirm deletions
Service-->>Controller: success
Controller-->>HTMX: 204 No Content / redirect
end
HTMX->>UI: swap/remove deleted rows
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment Tip CodeRabbit can scan for known vulnerabilities in your dependencies using OSV Scanner.OSV Scanner will automatically detect and report security vulnerabilities in your project's dependencies. No additional configuration is required. |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
src/test/java/codes/yam/contacts/ContactsApplicationTests.java (1)
9-10: Add tests for bulk delete behavior.The endpoint at
ContactController.deleteManyContacts()(lines 75–77) handles the bulk delete contract with@RequestParam List<String> selected_contact_slugs, but this flow has no test coverage. Add tests to cover parameter binding and the multi-delete logic.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/test/java/codes/yam/contacts/ContactsApplicationTests.java` around lines 9 - 10, Add unit tests to cover the bulk-delete flow for ContactController.deleteManyContacts: write tests in ContactsApplicationTests that use MockMvc (or WebTestClient) to POST/DELETE to the endpoint with multiple selected_contact_slugs request parameters, assert that parameter binding works (controller receives both slugs) and that the multi-delete logic calls the repository/service delete method for each slug and returns the expected status; specifically, create tests that (1) send multiple selected_contact_slugs and verify ContactRepository.deleteBySlug or ContactService.deleteContact is invoked for each slug, and (2) test the empty/none case to ensure no deletes occur and an appropriate response is returned. Ensure you reference ContactController.deleteManyContacts, the request param name selected_contact_slugs, and the repository/service methods used to perform deletions when wiring mocks and verifications.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/codes/yam/contacts/ContactController.java`:
- Around line 75-77: Make the request param optional and guard against a
null/empty selection in deleteManyContacts: change the `@RequestParam` on
selected_contact_slugs to be optional (e.g. required=false or
Optional<List<String>>) and then check if the list is null or empty before
calling contactService.deleteMany(selected_contact_slugs); if empty, return an
early ResponseEntity (e.g. noContent()) instead of invoking the service. Ensure
you only call contactService.deleteMany(...) when the list has elements to avoid
MissingServletRequestParameterException and unnecessary service calls.
In `@src/main/resources/templates/fragments/contact-fields.html`:
- Around line 10-12: The hx-get URL in the contact-fields fragment is built from
contact.slug so in ContactController.newContact (create flow) this yields
/contacts/null/email and breaks ContactController.validateEmail; fix by only
emitting the hx-get attribute when contact.slug is non-null: update the input in
contact-fields.html to conditionally set hx-get (e.g. use a Thymeleaf
conditional expression or th:if/th:attr to add
hx-get=@{/contacts/{slug}/email(slug=${contact.slug})} only when ${contact.slug}
!= null), leaving the input without hx-get for new contacts (or use a data
attribute fallback) so email validation requests only target the validateEmail
endpoint when a valid slug exists.
In `@src/main/resources/templates/fragments/contact-list-rows.html`:
- Around line 9-13: The checkboxes rendered by the input element
(name="selected_contact_slugs", th:value="*{slug}") lack an accessible name;
update the markup so each checkbox has an explicit accessible label by either
wrapping the input in a <label> that uses the contact display field (e.g. the
contact's name) or by adding an aria-label attribute bound to the contact name
(use Thymeleaf binding like th:attr="aria-label=*{name}" or give each input an
id bound to *{slug} and a corresponding <label
th:for="*{slug}">*{name}</label>); ensure the identifier uses th:value="*{slug}"
so ids remain unique and screen readers receive the contact name for each
checkbox.
- Around line 25-27: The fragment currently uses hx-swap="outerHTML swap:1s" on
the row element with hx-target="closest tr" and th:attr="hx-delete=...", but
ContactController returns an HTTP 303 redirect which causes HTMX to follow the
redirect and insert the full page into the targeted tr; change the hx-swap
attribute on that element from "outerHTML swap:1s" to "delete swap:1s" so HTMX
removes the row instead of swapping a full-page response into it.
---
Nitpick comments:
In `@src/test/java/codes/yam/contacts/ContactsApplicationTests.java`:
- Around line 9-10: Add unit tests to cover the bulk-delete flow for
ContactController.deleteManyContacts: write tests in ContactsApplicationTests
that use MockMvc (or WebTestClient) to POST/DELETE to the endpoint with multiple
selected_contact_slugs request parameters, assert that parameter binding works
(controller receives both slugs) and that the multi-delete logic calls the
repository/service delete method for each slug and returns the expected status;
specifically, create tests that (1) send multiple selected_contact_slugs and
verify ContactRepository.deleteBySlug or ContactService.deleteContact is invoked
for each slug, and (2) test the empty/none case to ensure no deletes occur and
an appropriate response is returned. Ensure you reference
ContactController.deleteManyContacts, the request param name
selected_contact_slugs, and the repository/service methods used to perform
deletions when wiring mocks and verifications.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5f67dcc8-dfd2-4ca4-824a-3fb6b0e83932
📒 Files selected for processing (16)
.idea/biome.xmlsrc/main/java/codes/yam/contacts/Contact.javasrc/main/java/codes/yam/contacts/ContactController.javasrc/main/java/codes/yam/contacts/ContactRepository.javasrc/main/java/codes/yam/contacts/WebConfig.javasrc/main/resources/data.sqlsrc/main/resources/templates/contacts/edit.htmlsrc/main/resources/templates/contacts/list.htmlsrc/main/resources/templates/contacts/new.htmlsrc/main/resources/templates/contacts/view.htmlsrc/main/resources/templates/error.htmlsrc/main/resources/templates/error/404.htmlsrc/main/resources/templates/fragments/contact-fields.htmlsrc/main/resources/templates/fragments/contact-list-rows.htmlsrc/main/resources/templates/layout.htmlsrc/test/java/codes/yam/contacts/ContactsApplicationTests.java
💤 Files with no reviewable changes (1)
- .idea/biome.xml
…mplate - Add `aria-label` for checkboxes in `contact-list-rows` for better accessibility. - Change `hx-swap` action from `outerHTML` to `delete` in delete actions. - Update `deleteManyContacts` to handle empty or null selections gracefully. - Enhance `hx-get` logic in contact fields to handle null slugs conditionally.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/java/codes/yam/contacts/ContactController.java (1)
74-82: Optional: Consider using camelCase for Java variable with explicitnameattribute.The parameter name
selected_contact_slugsuses snake_case to match the HTML form field, but Java convention prefers camelCase. You could use@RequestParam(name = "selected_contact_slugs", required = false) List<String> selectedContactSlugsto satisfy both conventions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/codes/yam/contacts/ContactController.java` around lines 74 - 82, In deleteManyContacts in ContactController, change the snake_case parameter to camelCase and bind it to the incoming request param by using `@RequestParam`(name = "selected_contact_slugs", required = false) List<String> selectedContactSlugs; update the method signature and any uses (e.g., the contactService.deleteMany call) to use selectedContactSlugs so Java naming conventions are followed while still matching the HTML form field.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/main/java/codes/yam/contacts/ContactController.java`:
- Around line 77-79: When selected_contact_slugs is null or empty in the
ContactController delete action, it currently returns ResponseEntity.noContent()
which HTMX treats as silent/no-op; change that branch to return the same
redirect response used by the successful delete path (i.e., the same HTTP
redirect or HX-Redirect header and status) so the client refreshes/redirects
consistently. Locate the check for selected_contact_slugs in the
ContactController method handling deletions and replace the noContent() return
with the success-path redirect/headers so both branches produce identical
HX-Redirect behavior.
---
Nitpick comments:
In `@src/main/java/codes/yam/contacts/ContactController.java`:
- Around line 74-82: In deleteManyContacts in ContactController, change the
snake_case parameter to camelCase and bind it to the incoming request param by
using `@RequestParam`(name = "selected_contact_slugs", required = false)
List<String> selectedContactSlugs; update the method signature and any uses
(e.g., the contactService.deleteMany call) to use selectedContactSlugs so Java
naming conventions are followed while still matching the HTML form field.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e597c77f-c111-498e-b99b-868e14430dda
📒 Files selected for processing (3)
src/main/java/codes/yam/contacts/ContactController.javasrc/main/resources/templates/fragments/contact-fields.htmlsrc/main/resources/templates/fragments/contact-list-rows.html
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/resources/templates/fragments/contact-list-rows.html
…e null/empty selection handling
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Closes #20
Summary by CodeRabbit
New Features
Bug Fixes / Improvements
Style
Tests