New Case Contacts Table: row actions menu#6834
Open
cliftonmcintosh wants to merge 13 commits intorubyforgood:mainfrom
Open
New Case Contacts Table: row actions menu#6834cliftonmcintosh wants to merge 13 commits intorubyforgood:mainfrom
cliftonmcintosh wants to merge 13 commits intorubyforgood:mainfrom
Conversation
36e1e71 to
7a11bdd
Compare
Co-Authored-By: claude-sonnet-4-6 <noreply@anthropic.com>
Each row in the new case contacts datatable now has a Bootstrap dropdown menu with Edit, Delete, and Set/Resolve Reminder actions. Items are shown or hidden based on per-row Pundit permissions already returned by the datatable JSON. Delete and Resolve Reminder use AJAX so the table reloads in place. Set Reminder opens a SweetAlert2 dialog for an optional note. Backend controllers now respond to JSON for destroy and followup resolve so jQuery does not follow the HTML redirect. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The delete action in the new case contacts table now shows a confirmation dialog before sending the DELETE request. Cancelling the dialog aborts the request. Tests updated to reflect async flow. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Edit and Delete are now rendered as disabled dropdown items when the current user lacks permission, rather than being omitted from the menu. Disabled items retain aria-disabled="true" for screen reader accessibility. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
b50076e to
e59e9ee
Compare
1600b95 to
92abe1e
Compare
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
92abe1e to
c4370f3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What github issue is this PR for, if any?
Resolves #6500
What changed, and why?
Implements the ellipsis (⋮) action menu for each row in the new case contacts table at
/case_contacts/new_design. The menu contains three items: Edit, Delete, and Set Reminder (or Resolve Reminder if a pending followup already exists).app/datatables/case_contact_datatable.rbcurrent_userparameter to the initializer so the datatable can compute per-row permissionscan_edit,can_destroy,edit_path, andfollowup_idcan_editandcan_destroyare derived fromCaseContactPolicyso the UI reflects actual Pundit permissionsfollowup_idis the id of any open (requested) followup, used to toggle between Set Reminder and Resolve Reminderincludesto add:followupsand:creatorto avoid N+1 queriesapp/controllers/case_contacts/case_contacts_new_design_controller.rbcurrent_usertoCaseContactDatatable.newapp/controllers/case_contacts_controller.rbrespond_totodestroyso jQuery AJAX receives204 No Contentinstead of an HTML redirect that would be silently followedapp/controllers/case_contacts/followups_controller.rbrespond_totoresolvefor the same reasonapp/javascript/src/dashboard.jsedit_pathwithdata-turbo="false"; rendered as a disabled<span>whencan_editis falseDELETErequest via AJAX; rendered as a disabled<button>whencan_destroyis falsePATCHto the followup resolve endpoint; shown when an open followup exists<meta>tagaria-label,aria-haspopup, andaria-expandedattributes; the icon is markedaria-hidden="true"How is this tested? (please write rspec and jest tests!) 💖💪
Note: if you see a flake in your test build in github actions, please post in slack #casa "Flaky test: " :) 💪
Note: We love capybara tests! If you are writing both haml/js and ruby, please try to test your work with tests at every level including system tests like https://github.com/rubyforgood/casa/tree/main/spec/system
Datatable spec — updated
spec/datatables/case_contact_datatable_spec.rb:can_editis"true"for admin,"false"for a different volunteer's contactcan_destroyreflects policy (admin can destroy active contacts; volunteers cannot)edit_pathis the correct Rails edit path for the contactfollowup_idis empty when no requested followup existsfollowup_idcontains the followup id when a requested followup existsRequest specs — updated
spec/requests/case_contacts/case_contacts_new_design_spec.rb:can_edit,can_destroy,edit_path, andfollowup_idfor each rowcan_edit: "true"andcan_destroy: "true"can_edit: "true"for their own contact andcan_destroy: "false"for active contactscan_destroy: "true"for their own draft contactsJest — updated
app/javascript/__tests__/dashboard.test.js:Ellipsis column rendering:
aria-labelcontaining the contact datearia-hidden="true"can_editis"true"; rendered as a disabled<span>when"false"can_destroyis"true"; rendered as a disabled<button>witharia-disabled="true"when"false"followup_idis emptydata-followup-id) whenfollowup_idis presentClick handlers:
DELETEwith CSRF header when confirmed; does not send request when cancelled; reloads DataTable on success{ note }when confirmed with a note; does not POST when cancelled; reloads DataTable on successPATCHto/followups/:id/resolvewith CSRF header; reloads DataTable on successSystem specs — updated
spec/system/case_contacts/case_contacts_new_design_spec.rb:Action menu visibility:
Edit action:
Delete action:
Set Reminder action:
Resolve Reminder action:
Permission states:
Screen recordings
Edit case contact
edit.contact.mov
Delete case contact
delete.case.contact.mov
Delete disabled for volunteer
A volunteer can only delete a draft case contact. This screen recording shows the Delete disabled for non-drafts and the Delete working for drafts.
volunteer.can.only.delete.drafts.mov
Set reminder
set.reminder.mov
Resolve reminder
resolve.reminder.mov
AI Disclosure
This PR was implemented with the assistance of Claude Code (Anthropic, claude-sonnet-4-6). The AI was used to:
All generated code was reviewed and committed by the author.
Action menu clipped near bottom of table
When a row is near the bottom of the table, the dropdown action menu may be partially obscured by the table footer or page content below it.
The root cause seems to be
overflow-x: hiddenon the<body>element, which clipsposition: absoluteelements (including Bootstrap dropdowns) that extend beyond the body's paint area. I'm worried that fixing this globally risks unintended layout side effects elsewhere, so it is left as is.Menu is hidden by table footer
menu.hidden.by.footer.mov